Generics 如何按照Xamarin.Forms中的MVVM架构进行导航,而不使用任何框架,如PRISM或任何导航服务?

Generics 如何按照Xamarin.Forms中的MVVM架构进行导航,而不使用任何框架,如PRISM或任何导航服务?,generics,mvvm,xamarin.forms,navigation,func,Generics,Mvvm,Xamarin.forms,Navigation,Func,我有一个继承了PageBase.xaml的LoginPage.xamlLoginViewModel是LoginPage的ViewModel,它继承了BASEWMODELBaseViewModel具有定义的Func委托-OnModalNavigationRequest,该委托由PageBase在其OnAppearing方法中订阅,实现在HandleModalNavigationRequest方法中提供。单击Login按钮LoginPage.xaml时,调用LoginViewModel的OnSubm

我有一个继承了PageBase.xaml的LoginPage.xamlLoginViewModelLoginPageViewModel,它继承了BASEWMODELBaseViewModel具有定义的Func委托-OnModalNavigationRequest,该委托由PageBase在其OnAppearing方法中订阅,实现在HandleModalNavigationRequest方法中提供。单击Login按钮LoginPage.xaml时,调用LoginViewModelOnSubmit方法,绑定通过命令,该命令在成功身份验证后调用navigateTomodel方法BaseViewModelNavigateToModel方法BaseViewModel在检查是否为null后,调用HandleModelNavigationRequest方法PageBase上的delegateOnModelNavigationRequest

我的问题是,OnModalNavigationRequest总是null的形式出现,这表明它没有订户。这意味着未调用PageBaseOnAppearing方法,这意味着未实例化PageBase。如何解决这个问题

我正在发布正在发生的事件顺序代码:

免责声明:代码帮助已从

App.xaml.cs

    protected override void OnStart()
    {
        // Handle when your app starts
        var properties = Current.Properties;

        if (properties.ContainsKey("Username"))
        {
            if (properties["Username"] != null)
            {
                var loggedInUser = (string)properties["Username"];
                MainPage = new MainPage();
            }
            else
            {
                MainPage = new LoginPage();
            }
        }
        else
        {
            MainPage = new LoginPage();
        }
    }
    public partial class PageBase<TViewModel> : ContentPage, IView<TViewModel> where TViewModel : BaseViewModel, new()
   {
    public TViewModel ViewModel
    {
        get
        {
            return GetValue(BindingContextProperty) as TViewModel;
        }
        set
        {
            SetValue(BindingContextProperty, value);
        }
    }

    #region <Events>

    protected override void OnAppearing()
    {
        base.OnAppearing();

        ViewModel.OnModalNavigationRequest = HandleModalNavigationRequest;
    }

    protected override void OnDisappearing()
    {
        base.OnDisappearing();

        ViewModel.OnModalNavigationRequest = null;
    }
    #endregion

    async Task HandleModalNavigationRequest(BaseViewModel targetViewModel)
    {
        var targetView = ViewResolver.GetViewFor(targetViewModel);
        targetView.BindingContext = targetViewModel;
        await Navigation.PushModalAsync(new NavigationPage(targetView));
    }
}
    public partial class LoginPage : PageBase
    {
        LoginViewModel ViewModel => BindingContext as LoginViewModel;

        public LoginPage() : base()
        {
            BindingContext = new LoginViewModel();

            InitializeComponent();
        }
    }
        public class LoginViewModel : BaseViewModel
        {
            public Command SubmitCommand { protected set; get; }

            public LoginViewModel() : base()
            {
                Title = "Login";
                SubmitCommand = new Command(async () => await OnSubmit());
            }

            public async Task OnSubmit()
            {
                await NavigateToModal<ItemsViewModel>(new ItemsViewModel());
            }
        }
IView

public interface IView
{
}

public interface IView<TViewModel> : IView where TViewModel : BaseViewModel
{
    TViewModel ViewModel { get; set; }
}
LoginViewModel.cs

    protected override void OnStart()
    {
        // Handle when your app starts
        var properties = Current.Properties;

        if (properties.ContainsKey("Username"))
        {
            if (properties["Username"] != null)
            {
                var loggedInUser = (string)properties["Username"];
                MainPage = new MainPage();
            }
            else
            {
                MainPage = new LoginPage();
            }
        }
        else
        {
            MainPage = new LoginPage();
        }
    }
    public partial class PageBase<TViewModel> : ContentPage, IView<TViewModel> where TViewModel : BaseViewModel, new()
   {
    public TViewModel ViewModel
    {
        get
        {
            return GetValue(BindingContextProperty) as TViewModel;
        }
        set
        {
            SetValue(BindingContextProperty, value);
        }
    }

    #region <Events>

    protected override void OnAppearing()
    {
        base.OnAppearing();

        ViewModel.OnModalNavigationRequest = HandleModalNavigationRequest;
    }

    protected override void OnDisappearing()
    {
        base.OnDisappearing();

        ViewModel.OnModalNavigationRequest = null;
    }
    #endregion

    async Task HandleModalNavigationRequest(BaseViewModel targetViewModel)
    {
        var targetView = ViewResolver.GetViewFor(targetViewModel);
        targetView.BindingContext = targetViewModel;
        await Navigation.PushModalAsync(new NavigationPage(targetView));
    }
}
    public partial class LoginPage : PageBase
    {
        LoginViewModel ViewModel => BindingContext as LoginViewModel;

        public LoginPage() : base()
        {
            BindingContext = new LoginViewModel();

            InitializeComponent();
        }
    }
        public class LoginViewModel : BaseViewModel
        {
            public Command SubmitCommand { protected set; get; }

            public LoginViewModel() : base()
            {
                Title = "Login";
                SubmitCommand = new Command(async () => await OnSubmit());
            }

            public async Task OnSubmit()
            {
                await NavigateToModal<ItemsViewModel>(new ItemsViewModel());
            }
        }
public类LoginViewModel:BaseViewModel
{
公共命令SubmitCommand{protected set;get;}
public LoginViewModel():base()
{
Title=“登录”;
SubmitCommand=new命令(async()=>await OnSubmit());
}
公共异步任务OnSubmit()
{
等待NavigateTomodel(新的ItemsViewModel());
}
}
通过

  • 在LoginPage.xaml中添加x:TypeArguments,如下所示:

    <views:PageBase xmlns="http://xamarin.com/schemas/2014/forms"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         xmlns:views="clr-namespace:IPMS.Views.Shared;assembly=IPMS"
         xmlns:ViewModel="clr-namespace:IPMS.ViewModels.Shared;assembly=IPMS"
         x:Class="IPMS.Views.Shared.LoginPage"
         x:TypeArguments="ViewModel:LoginViewModel"
         BackgroundImageSource="loginbg.9.jpg"
         Title="{Binding Title}">
    </views:PageBase>
    
    public partial class LoginPage : PageBase<LoginViewModel>
    {
        public LoginPage() : base()
        {
            BindingContext = new LoginViewModel();
    
            InitializeComponent();
        }
    }
    
    
    
  • 更改LoginPage.xaml.cs如下所示:

    <views:PageBase xmlns="http://xamarin.com/schemas/2014/forms"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         xmlns:views="clr-namespace:IPMS.Views.Shared;assembly=IPMS"
         xmlns:ViewModel="clr-namespace:IPMS.ViewModels.Shared;assembly=IPMS"
         x:Class="IPMS.Views.Shared.LoginPage"
         x:TypeArguments="ViewModel:LoginViewModel"
         BackgroundImageSource="loginbg.9.jpg"
         Title="{Binding Title}">
    </views:PageBase>
    
    public partial class LoginPage : PageBase<LoginViewModel>
    {
        public LoginPage() : base()
        {
            BindingContext = new LoginViewModel();
    
            InitializeComponent();
        }
    }
    
    public分部类登录页面:PageBase
    {
    public LoginPage():base()
    {
    BindingContext=新的LoginViewModel();
    初始化组件();
    }
    }
    

  • ,根据这篇文章,我发现作者提供的东西很简单,所以你会尝试作者的样本吗?是的,但样本中不包括从PageBase.xaml继承的页面,这就是我面临的挑战,因为在一些链接中,我们无法继承xaml,而我刚刚开始使用Xamarin,我不知道x:TypeArguments是做什么的。很高兴听到您自己解决了问题,所以请记住将您的回答标记为答案,谢谢。