Page Navigation using MVVM in Store App

后端 未结 5 1002
我在风中等你
我在风中等你 2020-11-30 02:55

I\'m having a serious headache with this problem. I really dislike store apps but am forced to use it in this case. I\'ve only worked with XAML for a few weeks.

My q

5条回答
  •  鱼传尺愫
    2020-11-30 03:16

    This simply bothers me that no one has solved this at the architectural level. So this is the code for complete decoupling the views, viewmodels and the mapping between them with using the built-in Frame based navigation. The implementation uses Autofact as DI container, but can be easily ported to other IoC solutions.

    Core VM logic (these should be in the same assembly):

    // I would not get into how the ViewModel or property change notification is implemented
    public abstract class PageViewModel : ViewModel
    {
        protected internal INavigationService Navigation { get; internal set; }
    
        internal void NavigationCompleted()
        {
            OnNavigationCompleted();
        }
    
        protected virtual void OnNavigationCompleted()
        {
    
        }
    }
    
    public interface INavigationService
    {
        void Navigate() where TModel : PageViewModel;
    }
    
    public abstract class NavigationServiceBase : INavigationService
    {
        public abstract void Navigate() where TModel : PageViewModel;
        protected void CompleteNavigation(PageViewModel model)
        {
            model.Navigation = this;
            model.NavigationCompleted();
        }
    }
    

    This code should be in a UWP class library or executable:

    public interface INavigationMap
        where TModel: PageViewModel
    {
        Type ViewType { get; }
    }
    
    internal class NavigationMap : INavigationMap
        where TModel: PageViewModel
        where TView: Page
    {
        public Type ViewType => typeof(TView);
    }
    
    public class NavigationService : NavigationServiceBase
    {
        private readonly Frame NavigationFrame;
        private readonly ILifetimeScope Resolver;
    
        public NavigationService(ILifetimeScope scope)
        {
            Resolver = scope;
            NavigationFrame = Window.Current.Content as Frame;
            NavigationFrame.Navigated += NavigationFrame_Navigated;
        }
    
        private void NavigationFrame_Navigated(object sender, Windows.UI.Xaml.Navigation.NavigationEventArgs e)
        {
            if(e.Content is FrameworkElement element)
            {
                element.DataContext = e.Parameter;
    
                if(e.Parameter is PageViewModel page)
                {
                    CompleteNavigation(page);
                }
            }
        }
    
        public override void Navigate()
        {
            var model = Resolver.Resolve();
            var map = Resolver.Resolve>();
    
            NavigationFrame.Navigate(map.ViewType, model);
        }
    }
    

    The rest is just convenience code for registering in the DI and usage examples:

    public static class NavigationMap
    {
        public static void RegisterNavigation(this ContainerBuilder builder)
            where TModel : PageViewModel
            where TView : Page
        {
            builder.RegisterInstance(new NavigationMap())
                .As>()
                .SingleInstance();
        }
    }
    
         builder.RegisterNavigation();
    
    
    public class UserAuthenticationModel : PageViewModel
    {
        protected override void OnNavigationCompleted()
        {
            // UI is visible and ready
            // navigate to somewhere else
            Navigation.Navigate();
        }
    }
    

提交回复
热议问题