Search code examples
xamlmvvmuwpmvvmcrossviewmodel

Open new windows in UWP app with MvvmCross


I try to open a page in a new window in my UWP app. Is this possible with the IMvxNavigationService provided by MvvmCross? Right now it only replaces the page in the current window.

Navigation flow Navigatin flow

ViewModel

public class MyViewModel: MvxViewModel
{
    private readonly IMvxNavigationService _navigationService;

    public MyViewModel(IMvxNavigationService navigationService)
    {
        _navigationService = navigationService;
    }

    public MvxCommand MyCommand { get; set; }

    public override void Prepare()
    {
        base.Prepare();
        MyCommand = new MvxCommand<>(MyEvent);
    }

    private void MyEvent()
    {
        _navigationService.Navigate<OtherViewModel>();
    }
}

Solution

  • I now realized that I could implement a custom presenter and use the new AppWindow.

    MvxWindowPresentationAttribute.cs

    public class MvxWindowPresentationAttribute : MvxBasePresentationAttribute
    {
    }
    

    CustomMvxWindowsViewPresenter.cs

    public class CustomMvxWindowsViewPresenter : MvxWindowsViewPresenter
    {
        public CustomMvxWindowsViewPresenter(IMvxWindowsFrame rootFrame) : base(rootFrame)
        {
        }
    
        public override void RegisterAttributeTypes()
        {
            base.RegisterAttributeTypes();
            AttributeTypesToActionsDictionary.Register<MvxWindowPresentationAttribute>(ShowWindow, CloseWindow);
        }
    
        private Task<bool> CloseWindow(IMvxViewModel viewModel, MvxWindowPresentationAttribute attribute)
        {
            return base.ClosePage(viewModel, attribute);
        }
    
        private Task<bool> ShowWindow(Type viewType, MvxWindowPresentationAttribute attribute,
            MvxViewModelRequest request)
        {
            try
            {
                return Task.Run(async () =>
                {
                    var requestText = GetRequestText(request);
                    var viewsContainer = Mvx.IoCProvider.Resolve<IMvxViewsContainer>();
    
                    await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.High,
                        async () => {
                            var appWindow = await AppWindow.TryCreateAsync();
                            var appWindowContentFrame = new Frame();
                            appWindowContentFrame.Navigate(viewType, requestText);
                            ElementCompositionPreview.SetAppWindowContent(appWindow, appWindowContentFrame);
                            await appWindow.TryShowAsync();
                            HandleBackButtonVisibility();
                        });
                    return true;
                });
            }
            catch (Exception exception)
            {
                return Task.FromResult(false);
            }
        }
    }
    

    Setup.cs

    protected override IMvxWindowsViewPresenter CreateViewPresenter(IMvxWindowsFrame rootFrame)
    {
        return new CustomMvxWindowsViewPresenter(rootFrame);
    }
    

    The only thing left to do is to annotate your views with the created attribute MvxWindowPresentation.

    OtherView.xaml.cs

    [MvxWindowPresentation]
    public sealed partial class OtherView : MvxWindowsPage 
    {
       // ...
    }