2017-04-18 137 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.的正确答案,以帮助他解决问题以及解决我的额外信用问题!