Xamarin.forms 视图不';在Xamarin Forms Prism导航期间不会发生变化

Xamarin.forms 视图不';在Xamarin Forms Prism导航期间不会发生变化,xamarin.forms,prism,Xamarin.forms,Prism,我的背景是WPF(使用MVVMLight工具包)和WinForms,但我对Xamarin Forms和Prism还不熟悉。我正在尝试为从Swift移植的应用程序实现两步登录。在第一步中,用户键入一个客户ID(我们的每个客户都有许多员工)。在第二步中,他们将看到该客户ID的用户列表,并选择他们的姓名和输入密码 我正在为Mac使用Xamarin Studio 6.3、Xamarin Forms 2.3.4.231和Prism/Unity 6.3.0 我的问题是,当我键入客户ID并单击提交时,第二个登

我的背景是WPF(使用MVVMLight工具包)和WinForms,但我对Xamarin Forms和Prism还不熟悉。我正在尝试为从Swift移植的应用程序实现两步登录。在第一步中,用户键入一个客户ID(我们的每个客户都有许多员工)。在第二步中,他们将看到该客户ID的用户列表,并选择他们的姓名和输入密码

我正在为Mac使用Xamarin Studio 6.3、Xamarin Forms 2.3.4.231和Prism/Unity 6.3.0

我的问题是,当我键入客户ID并单击提交时,第二个登录视图中的“OnNavigationTo”代码将运行,并且我成功地从我的web服务中检索到用户列表(该代码位于第二个ViewModel中),但第二个视图从未出现。当我逐步完成代码时,所有的业务逻辑都按预期运行,但从用户的角度来看,视图从未改变。我确信我遗漏了一些简单的东西,但在阅读了Prism navigation上的多篇博文和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>();


    }
}
UserLoginViewModel.cs(登录过程的第二步-导航目标)

public类UserLoginPageViewModel:BindableBase,INavigationAware
{
私人名单(交易商);;
公开列表处理程序
{
获取{return\u dealUsers;}
set{SetProperty(ref _dealerUsers,value);}
}
私有字符串_selectedUser;
公共字符串选择器
{
获取{return\u selectedUser;}
set{SetProperty(ref _selectedUser,value);}
}
私有字符串\u选择的删除器;
公共字符串选择器
{
获取{return\u selectedDealer;}
set{SetProperty(ref _selectedDealer,value);}
}
私人导航服务;
私人ISalesDataRepo(销售datarepo);;
公共DelegateCommand提交{get;set;}
公共用户LoginPageViewModel()
{
}
public UserLoginPageViewModel(INavigationService navigationService,ISalesDataRepo salesDataRepo)
{
_导航服务=导航服务;
_salesDataRepo=salesDataRepo;
提交=新的委派命令(单击提交);
}
作废提交()
{
//无关代码
}
public void OnNavigatedFrom(NavigationParameters)
{
}
public void OnNavigatedTo(NavigationParameters)
{
}
导航到上的公共void(导航参数)
{
//这里有一个断点被命中-此代码运行,但相关视图从未出现!
if(parameters.ContainsKey(“ChosenDealer”))
SelectedDealer=(字符串)参数[“ChosenDealer”];
if(DealUsers==null)
{
//我们有经销商,但还没有经销商的用户。异步获取他们
var getUsers=\u salesDataRepo.GetUserListAsync(SelectedDealer);
getUsers.Start();
//一旦有了用户,就设置listview。
var setUsers=getUsers.ContinueWith((先行项)=>
{
if(getUsers.Status==System.Threading.Tasks.TaskStatus.RanToCompletion)
{
DealUsers=getUsers.Result;
}
});
}
}
}
我正在导航到第二个视图(而不是ViewModel),第二个ViewModel中的预期代码正在成功运行,因此看起来一切都连接正确。有人知道我做错了什么吗?为什么观点没有改变

*额外积分*:是否有人知道在我的app.xaml.cs中创建if-else语句以注册相应存储库的方法,具体取决于我是否处于设计模式?我见过一些变通方法,您可以检查App.Current==null以确定是否处于设计模式,但显然Xamarin.Forms 6.2“破坏”了这种方法


提前谢谢

要处理设计时/模拟服务与生产服务的对比,您可以使用许多技术。但您需要一种在它们之间轻松切换的方法,为此,我建议使用编译器符号。您需要在项目中创建一个新的构建配置文件,例如,您可以创建一个名为
Mock
的配置文件,然后为该配置文件定义一个符号
Mock

  • 您可以做的第一件事是使用编译器指令注册适当的服务

#如果嘲笑
Container.Register();
#否则
Container.Register();
#恩迪夫

  • 您可以使用的另一种技术是向文件中添加条件编译。此技术将两个文件都保留在解决方案资源管理器中,并允许您实际对类进行完全相同的命名(尽管文件本身需要不同的命名)
您的csproj文件可能如下所示:

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

我想我已经解决了这个问题,它不是Prism或Xamarin.Forms所特有的;我只是对我的MVVM技能有些生疏

1) 因为我是异步加载数据的,所以视图试图在分配值之前绑定到DealUsers属性,因此该视图可能会抛出和吞咽NullReferenceException并无法加载(如果对发生的情况有更多的可见性,则更容易诊断)在ViewModel构造函数中,我必须新建列表(
DealUsers=new list();
),然后在异步方法中,我需要循环遍历结果,并将
getUsers.Result
中的每个字符串一次添加到现有(空)列表中

2) 我应该记得,这仍然不起作用,因为即使填充了列表,视图中的ListView也会显示为空。要解决此问题,我必须使用System.Collections.ObjectMo添加

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;
                }
            });
        }
    }

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