如何在 Xamarin 中使用 ViewModel First 导航显示模态登录屏幕 [英] How to present a modal Login screen using ViewModel First navigation in Xamarin

查看:31
本文介绍了如何在 Xamarin 中使用 ViewModel First 导航显示模态登录屏幕的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我正在使用

  • 尝试使用我为此应用程序设置的自定义 NavigationService,方法是从构造函数调用 await NavigationService.Instance.PushModalAsync(); 行详细信息页面的 ViewModel.这告诉我我需要使方法异步.此外,不太了解 xamarin async,因为我对 Xamarin.Forms 和 C# 还很陌生
  • Navigation.PushModalAsync(new LoginPage()); 似乎有效,但仅适用于 MasterDetailPage 的代码隐藏的承包商.这也使用了 Navigation 类,它显然是 内置于 xamarin.但是这个方法只接受一个 Page 并且并不真正符合我的 ViewModel-First 导航策略.
  • 我主要想知道的是在使用 ViewModel-first 模式时如何以编程方式调用模式(用于登录页面)?

    编辑 1:我使用的是 Visual Studio for Mac

    对于真正令人困惑的设置深表歉意.

    解决方案

    好的,首先,对于我提出这个问题的方式以及我为什么使用 PushModalAsync 的困惑表示歉意我想显示一个登录页面.这样做的原因是我试图修改问题中链接的存储库中的示例代码,以便在将其移植到我正在处理的项目中之前查看我将如何执行此操作.

    我的解决方案

    在修补这个问题一段时间后,我意识到当我从构造函数调用它时 .Execute(); 失败的原因,而 key not found 错误是因为我是从构造函数调用它.即使将导航命令分离为单独的方法而不是使用 lambda(见下文)并从构造函数调用 that 也不起作用,因为根据我的理解,页面 没有尚未显示,因此我的 NavigationService 还没有注册它什么的.

    ICommand _loginNav;公共 ICommand NavigatePopup{得到{if (_loginNav == null){_loginNav = new Command(async () => await NavigateModalLogin());}返回_loginNav;}}异步任务 NavigateModalLogin(){await _navService.PushModalAsync();}

    在使用 Navigation.PushModalAsync(new LoginPage()); 从构造函数调用它时为我做了工作,它没有使用我的自定义导航,我不喜欢那样.所以我继续寻找更好的方法.

    考虑到我之前意识到在构造函数中进行此检查是行不通的,我想到了使用 OnAppearing()OnDisappearing()Xamarin.Forms 中的 Page 类提供的方法.

    但是,由于我使用的是 ViewModel 优先导航,因此登录的处理需要在 ViewModel 中完成.所以我在页面的代码隐藏中写了这个,以有效地将执行传递给 ViewModel,以便我可以使用它:

    protected async override Task OnAppearing(){等待 viewmodel.OnAppearing();base.OnAppearing();System.Diagnostics.Debug.WriteLine("*****这里*****");}

    然后在 ViewModel 中,我使用 OnAppearing() 方法调用了之前的 NavigateModalLogin() 函数(是的,我知道这可以优化以避免额外的方法调用但无论如何).

    关于此的好处在于 OnAppearing() 方法是 Xamarin 中的 事件处理程序.这意味着它支持 async.这意味着我不必弄清楚如何从 async/await 链开始或如何工作.

    Tl;博士

    使用 Xamarin 提供的事件处理程序调用与命令相同的方法(事件处理程序可以是同步的,也可以是异步的).

    代码:

    在您页面的代码隐藏中:

    protected async override Task OnAppearing(){等待 viewmodel.OnAppearing();base.OnAppearing();System.Diagnostics.Debug.WriteLine("*****这里*****");}

    在您页面的 ViewModel 中:

    内部异步任务 OnAppearing(){等待 NavigateModalLogin();}ICommand _loginNav;公共 ICommand NavigatePopup{得到{if (_loginNav == null){_loginNav = new Command(async () => await NavigateModalLogin());}返回_loginNav;}}异步任务 NavigateModalLogin(){await _navService.PushModalAsync();}

    So I am using the FreshMVVM Xamarin.Forms library so I can do ViewModel-first navigation in xamarin. My research tells me that this is a highly recommended practice, yet there seem to be not a whole lot of tutorials for this.

    What I am trying to achieve is a login page that pops up as a modal once the user opens the app if they are not signed in.

    I have modified the demo project slightly by adding the modal display button and associated Command from the ViewModel to the first page, however, I am having trouble invoking this programmatically.

    Here is what I am trying to so along with the relevant Command code that I intend to tweak to work with a Login Page:

    public NormalOneViewModel()
    {
        if (/*user is not already logged in*/) {
            //display the login page as a modal to get the users credentials and log them in
            //see below
        }   
    }
    ...
    ICommand _navToChild;
    public ICommand NavigatePopup
    {
        get
        {
            if (_navToChild == null)
            {
                _navToChild = new Command(async () =>
                {
                    await _navService.PushModalAsync<NormalModalViewModel>();
                });
            }
            return _navToChild;
        }
    }
    

    This Command is invoked via <Button Text="Show Modal" Command="{Binding NavigatePopup}"/> in the view associated with the viewModel above.

    I have:

    • tried to call the command programmatically using NavigatePopup.Execute(null);. This fails with an error explaining that the key cannot be found.
    • tried to call the command programmatically using NavigatePopup.Execute();. This yields the following error:
    • tried using the custom NavigationService that I have set up for this app by calling the await NavigationService.Instance.PushModalAsync<NormalModalViewModel>(); line from the constructor of the detail page's ViewModel. This tells me that I need to make the method async. Additionally, don't really understand xamarin async too well since I am fairly new to Xamarin.Forms and C#
    • Navigation.PushModalAsync(new LoginPage()); seems to work, but only in the contractor of the code-behind of the MasterDetailPage. this is also using the Navigation Class which is apparently built-into xamarin. but this method only accepts a Page and doesn't really conform to my ViewModel-First navigation strategy.

    What I am primarily wondering is how do I programmatically invoke a modal (for a login page) when using ViewModel-first patterns?

    EDIT 1: I am using Visual Studio for Mac

    Apologies for the really confusing setup.

    解决方案

    Okay, so first off, apologies for the confusion regarding the way I presented this and why I was using PushModalAsync<NormalModalViewModel> in I wanted to display a Login page. The reason for this is I was trying to modify the sample code in the repositories linked in the question in order to see how I would do this before transplanting it into the project I am working on.

    My Solution

    After tinkering with this for quite a while, I realized that the reason .Execute(); was failing when I was calling it from the constructor with the key not found error was because I was calling it from the constructor. Even after separating the navigation command into a separate method instead of using a lambda (see below) and calling that from the constructor wouldn't work because, from my understanding, the page hadn't been displayed yet and my NavigationService therefore hadn't registered it or something.

    ICommand _loginNav;
    public ICommand NavigatePopup
    {
        get
        {
            if (_loginNav == null)
            {
                _loginNav = new Command(async () => await NavigateModalLogin());
            }
            return _loginNav;
        }
    }
    
    async Task NavigateModalLogin()
    {
        await _navService.PushModalAsync<NormalModalViewModel>();
    }
    

    while using Navigation.PushModalAsync(new LoginPage()); did work for me when calling it from the constructor, it wasn't using my custom navigation and I didn't really like that. So I continued looking for a better way.

    Considering my realization from earlier that doing this check in the constructor wasn't going to work, I had the idea to use the OnAppearing() and OnDisappearing() methods provided by the Page class in Xamarin.Forms.

    However, since I am using ViewModel-first navigation, the processing of the login would need to be done in the ViewModel. So I wrote this in the code-behind of the page to effectively pass the execution to the ViewModel so I could use it:

    protected async override Task OnAppearing()
    {
        await viewmodel.OnAppearing();
        base.OnAppearing();
        System.Diagnostics.Debug.WriteLine("*****Here*****");
    }
    

    Then in the ViewModel I had the OnAppearing() method call the NavigateModalLogin() function from earlier (yes I know this can be optimized to avoid the extra method call but whatever).

    The good part about this is that the OnAppearing() method is an Event Handler in Xamarin. Which means it supports async. Which means I didn't have to figure out how to start off an async/await chain or however that works.

    Tl;dr

    Use the event handlers that Xamarin provides to call the same method that the command does (the event Handlers can be either synchronous or asynchronous).

    Code:

    In the code-behind for your page:

    protected async override Task OnAppearing()
    {
        await viewmodel.OnAppearing();
        base.OnAppearing();
        System.Diagnostics.Debug.WriteLine("*****Here*****");
    }
    

    in the ViewModel for your page:

    internal async Task OnAppearing()
    {
        await NavigateModalLogin();
    }
    
    ICommand _loginNav;
    public ICommand NavigatePopup
    {
        get
        {
            if (_loginNav == null)
            {
                _loginNav = new Command(async () => await NavigateModalLogin());
            }
            return _loginNav;
        }
    }
    
    async Task NavigateModalLogin()
    {
        await _navService.PushModalAsync<NormalModalViewModel>();
    }
    

    这篇关于如何在 Xamarin 中使用 ViewModel First 导航显示模态登录屏幕的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆