wpfmvvmcrossdevexpress-wpf

Is it possible to use other components instead of MvxWindow in MvvmCross?


I am using DevExpres WPF Components and am trying to create a simple WPF-only project. The docs say that Winow should inherit from MvxWindow and UserControl from MvxWpfView. Unfortunately, Devexpess components are already inherited from Window/etc and that approach can't be used.

The only notice about possible solution is a short note in docs that Windows should "be wrapped in presenter" without any details :)

MvvmCross:

public partial class MainWindow : MvxWindow
{
    public MainWindow()
    {
        InitializeComponent();
    }
}

<views:MvxWindow  
    x:Class="TipCalc.WPF.MainWindow"
    xmlns:views="clr-namespace:MvvmCross.Platforms.Wpf.Views;assembly=MvvmCross.Platforms.Wpf"
    Title="MainWindow" Height="450" Width="800">
    <Grid>
    </Grid>
</views:MvxWindow>

DevExpress:

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : ThemedWindow
{
    public MainWindow()
    {
        InitializeComponent();
    }
}

<dx:ThemedWindow
    x:Class="DevExpressMvvmCross.MainWindow"
    Title="MainWindow" Height="350" Width="525" ShowStatusPanel="False">
    <Grid>
    </Grid>
</dx:ThemedWindow>

Is it possible to use external components with MvvmCross? I would like to stay with dx components because of themes and other cookies.


Solution

  • In order to use MVVMCross with Devexpress you should create a class which wraps Devexpress's ThemedWindow and implements MVVMCross's three interfaces. IMvxWindow, IMvxWpfView, IDisposable. You can copy the implementation of MvxWindow class. And your wrapper class might look like this:

    public class DevexpressMvxWindow : ThemedWindow, IMvxWindow, IMvxWpfView, IDisposable
    {
    
        private IMvxViewModel _viewModel;
        private IMvxBindingContext _bindingContext;
        private bool _unloaded = false;
    
        public IMvxViewModel ViewModel
        {
            get => _viewModel;
            set
            {
                _viewModel = value;
                DataContext = value;
                BindingContext.DataContext = value;
            }
        }
    
        public string Identifier { get; set; }
    
        public IMvxBindingContext BindingContext
        {
            get
            {
                if (_bindingContext != null)
                    return _bindingContext;
    
                if (Mvx.IoCProvider != null)
                    this.CreateBindingContext();
    
                return _bindingContext;
            }
            set => _bindingContext = value;
        }
    
        public DevexpressMvxWindow()
        {
            Closed += MvxWindow_Closed;
            Unloaded += MvxWindow_Unloaded;
            Loaded += MvxWindow_Loaded;
            Initialized += MvxWindow_Initialized;
        }
    
        private void MvxWindow_Initialized(object sender, EventArgs e)
        {
            if (this == Application.Current.MainWindow)
            {
                (Application.Current as MvvmCross.Platforms.Wpf.Views.MvxApplication).ApplicationInitialized();
            }
        }
    
        private void MvxWindow_Closed(object sender, EventArgs e) => Unload();
    
        private void MvxWindow_Unloaded(object sender, RoutedEventArgs e) => Unload();
    
        private void MvxWindow_Loaded(object sender, RoutedEventArgs e)
        {
            ViewModel?.ViewAppearing();
            ViewModel?.ViewAppeared();
        }
    
        private void Unload()
        {
            if (!_unloaded)
            {
                ViewModel?.ViewDisappearing();
                ViewModel?.ViewDisappeared();
                ViewModel?.ViewDestroy();
                _unloaded = true;
            }
        }
    
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    
        ~DevexpressMvxWindow()
        {
            Dispose(false);
        }
    
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                Unloaded -= MvxWindow_Unloaded;
                Loaded -= MvxWindow_Loaded;
                Closed -= MvxWindow_Closed;
            }
        }
    }
    

    Then in XAML you can use it like this:

    <customView:DevexpressMvxWindow
        xmlns:views="clr-namespace:MvvmCross.Platforms.Wpf.Views;assembly=MvvmCross.Platforms.Wpf"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
        xmlns:customView="clr-namespace:MvxSample.Wpf"
        x:Class="MvxSample.Wpf.MainWindow"
        mc:Ignorable="d"
        Title="MainWindow" Height="800" Width="1000"> 
    </customView:DevexpressMvxWindow>