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.
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>