2017-04-18 138 views
0

我的背景是WPF(帶有MVVMLight Toolkit)和WinForms,但我是Xamarin Forms和Prism的新手。我正在嘗試爲我從Swift移植的應用程序實施兩步登錄。在第一步中,用戶鍵入一個客戶ID(我們每個客戶都有很多員工)。在第二步中,他們顯示了該客戶ID的用戶列表,並選擇他們的名字並輸入密碼。視圖在Xamarin形式期間不會改變棱鏡導航

我使用Xamarin Studio的6.3的Mac,Xamarin表格2.3.4.231和棱鏡/統一6.3.0

我的問題是,當我輸入用戶ID,然後點擊提交時,「OnNavigatingTo」代碼第二個登錄視圖運行,並且我成功從我的Web服務中檢索用戶列表(此代碼位於第二個ViewModel中),但第二個視圖從不出現。當我瀏覽代碼時,所有的業務邏輯都按預期運行,但從用戶的角度來看,視圖不會改變。我確信我錯過了一些簡單的事情,但在閱讀關於Prism導航的多篇博客文章並查看關於S.O.的類似問題後,我沒有找到任何幫助。

app.xaml.cs:

public partial class App : PrismApplication 
{ 
    public App(IPlatformInitializer initializer = null) : base(initializer) { } 

    protected override void OnInitialized() 
    { 
     InitializeComponent(); 

     NavigationService.NavigateAsync("DealerLoginPage"); 
    } 

    protected override void RegisterTypes() 
    { 
     Container.RegisterTypeForNavigation<DealerLoginPage>(); 
     Container.RegisterTypeForNavigation<UserLoginPage>(); 
     Container.RegisterTypeForNavigation<SalesSummaryPage>(); 

     // Uncomment this section for design data 
     //Container.RegisterType<ISalesDataRepo, DesignSalesDataRepo>(); 

     // Uncomment this section for runtime data 
     Container.RegisterType<ISalesDataRepo, AzureSalesDataRepo>(); 


    } 
} 

DealerLoginPageViewModel.cs(步驟登錄之一 - 也初始視圖/ VM)

public class DealerLoginPageViewModel : BindableBase 
{ 
    private string _chosenDealer; 
    public string ChosenDealer 
    { 
     get { return _chosenDealer; } 
     set { SetProperty(ref _chosenDealer, value); } 
    } 

    private INavigationService _navigationService; 
    public DelegateCommand Submit { get; set; } 

    public DealerLoginPageViewModel() 
    { 

    } 

    public DealerLoginPageViewModel(INavigationService navigationService) 
    { 
     _navigationService = navigationService; 
     Submit = new DelegateCommand(Submit_Clicked); 
    } 

    void Submit_Clicked() 
    { 
     NavigationParameters parameters = new NavigationParameters(); 
     parameters.Add("ChosenDealer", ChosenDealer); 

     _navigationService.NavigateAsync("UserLoginPage", parameters); 
    } 
} 

UserLoginViewModel.cs(登錄過程的步驟2 - 導航目標)

public class UserLoginPageViewModel : BindableBase, INavigationAware 
{ 
    private List<string> _dealerUsers; 
    public List<string> DealerUsers 
    { 
     get { return _dealerUsers; } 
     set { SetProperty(ref _dealerUsers, value); } 
    } 

    private string _selectedUser; 
    public string SelectedUser 
    { 
     get { return _selectedUser; } 
     set { SetProperty(ref _selectedUser, value); } 
    } 

    private string _selectedDealer; 
    public string SelectedDealer 
    { 
     get { return _selectedDealer; } 
     set { SetProperty(ref _selectedDealer, value); } 
    } 

    private INavigationService _navigationService; 
    private ISalesDataRepo _salesDataRepo; 

    public DelegateCommand Submit { get; set; } 

    public UserLoginPageViewModel() 
    { 

    } 

    public UserLoginPageViewModel(INavigationService navigationService, ISalesDataRepo salesDataRepo) 
    { 
     _navigationService = navigationService; 
     _salesDataRepo = salesDataRepo; 

     Submit = new DelegateCommand(Submit_Clicked); 
    } 

    void Submit_Clicked() 
    { 
     // unrelated code 
    } 

    public void OnNavigatedFrom(NavigationParameters parameters) 
    { 

    } 

    public void OnNavigatedTo(NavigationParameters parameters) 
    { 

    } 

    public void OnNavigatingTo(NavigationParameters parameters) 
    { 
     // a breakpoint here gets hit - this code runs, but related view never appears! 

     if (parameters.ContainsKey("ChosenDealer")) 
      SelectedDealer = (string)parameters["ChosenDealer"]; 

     if (DealerUsers == null) 
     { 
      // we have the dealership, but not the dealership's users yet. Get them asynchronously 
      var getUsers = _salesDataRepo.GetUserListAsync(SelectedDealer); 
      getUsers.Start(); 

      // set up the listview once we have the users. 
      var setUsers = getUsers.ContinueWith((antecedent) => 
      { 
       if (getUsers.Status == System.Threading.Tasks.TaskStatus.RanToCompletion) 
       { 
        DealerUsers = getUsers.Result; 
       } 
      }); 
     } 
    } 

} 

我導航到所述第二視圖(未視圖模型),和預期的碼我n第二個ViewModel正在成功運行,所以看起來好像所有東西都連接正確。有沒有人看到我在做什麼錯了?爲什麼這個觀點不會改變?

*額外的分數*:有誰知道在我app.xaml.cs一種方式來創建一個if-else語句註冊取決於我是否在設計模式中適當庫?我已經看到了可以檢查App.Current == null是否處於設計模式的解決方法,但顯然Xamarin.Forms 6.2「打破」了該方法...

在此先感謝!

+1

沒有完整的複製,很難說出爲什麼你遇到了問題。我會說,雖然你可以簡化你的代碼導航到UserLoginPage到'_navigationService.NavigateAsync($「UserLoginPage?ChosenDealer = {ChosenDealer}」)'。你可以查看這個[gist](https://gist.github.com/dansiegel/d6827a98788e76c4e313ccffe99d1993)關於調試這個問題的一些提示 –

+0

@DanS。 - 該要點非常有幫助 - 該方法有助於揭示在運行時被吞噬的異常。我看到'System.InvalidOperationException:當前類型Prism.Navigation.INavigationService是一個接口,無法構建。你是否缺少類型映射?'。我還沒有找到一個快速的答案,但至少這個問題似乎有更好的記錄。除非您有進一步的建議,否則我會在找到解決方案時更新該帖子。 –

+0

我不確定您提供的代碼是否是解決方案中的確切代碼,但聽起來更像是您有拼寫錯誤,並且您的UserLoginPageViewModel沒有將NavigationService完全命名爲navigationService –

回答

0

要處理設計時間/模擬服務與生產服務,您可以使用多種技術。但是你會想要一種輕鬆切換它們的方式,因爲我會建議使用編譯器符號。您需要在項目中創建一個新的構建配置文件,例如,您可以創建一個名爲Mock的構建配置文件,然後爲該配置文件MOCK定義一個符號。

  • ,您所要做的第一件事情就是用編譯器指令註冊相應的服務

#if MOCK Container.Register<IFooService,MockFooService>(); #else Container.Register<IFooService,FooService>(); #endif

  • ,您可以使用另一種方法是添加一個條件編譯到你的文件。這種技術會將這兩個文件保留在解決方案資源管理器中,並允許您實際命名相同的類(儘管文件本身需要命名不同)。

你的csproj文件可能是這樣的:

<ItemGroup> 
    <Compile Include="Services\MockFooService.cs" Condition=" '$(Configuration)' == 'Mock' " /> 
    <Compile Include="Services\FooService.cs" Condition=" '$(Configuration)' != 'Mock' " /> 
</ItemGroup> 
+0

謝謝!我從來沒有玩過這樣的事情,但它看起來很有希望。我很快就要打電話給你,但是如果我能讓它工作,我會明天讓你知道。希望Xamarin或Prism在未來版本中會有內置的內容,但是您的推薦看起來好像可以奏效。 –

0

我想我通過發行成功,這是沒有什麼特定於棱鏡或Xamarin.Forms;我只是生我的MVVM技能。

1)因爲我正在異步加載數據,視圖試圖綁定到DealerUsers屬性,因此該視圖可能是拋出併吞下NullReferenceException並且無法加載(這會是在ViewModel構造函數中,我不得不新建列表(DealerUsers = new List<string>();,然後而不是分配它(DealerUsers = getUsers.Result在異步方法中,我需要遍歷結果和將getUsers.Result中的每個字符串一次一個添加到現有(空)列表中

2)正如我應該記住的,這仍然不起作用,因爲即使列表已填充,ListV視圖中的視圖顯示爲空。要解決此問題,我必須添加using System.Collections.ObjectModel;並將List<string>更改爲ObservableCollection<string>

**注意**這解決了我的問題的大部分 - 我正在授予Dan S.的正確答案,以幫助他解決問題以及解決我的額外信用問題!