Reputation: 57
I wanted to create a project based on the MVVM pattern. Unfortunately, I didn't quite get it right and now I have numerous subsequent errors.
MainWindow.xaml
<Window x:Class="MyProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MyProject"
xmlns:viewmodels="clr-namespace:MyProject.ViewModels"
xmlns:views="clr-namespace:MyProject.View"
mc:Ignorable="d"
Height="571.4" Width="730">
<Window.Resources>
<DataTemplate x:Name="Window1ViewTemplate" DataType="{x:Type viewmodels:Window1ViewModel}">
<views:Window1View DataContext="{Binding}"/>
</DataTemplate>
</Window.Resources>
<Grid>
// Grid Definition not included - not relevant
<DockPanel Background="Blue" Grid.Row="1" Grid.Column="0" Grid.RowSpan="3">
<StackPanel>
<Button Content="Window1"
Height="45"
Click="Window1_click"/>
</StackPanel>
</DockPanel>
<ContentControl Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="3" Grid.RowSpan="4" Content="{Binding}"/>
</Grid>
</Window>
MainWindow.xaml.cs
namespace MyProject
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window1_click(object sender, RoutedEventArgs e)
{
DataContext = new Window1ViewModel();
}
}
}
I have a window which I named Window1. This one is not quite relevant I guess.
Now the Click Event button opens the window correctly. But this does not fit the MVVM pattern. This will start a new thread, which then leads to countless subsequent errors.
How can I adjust the button event so that the binding is correct again.
Upvotes: 0
Views: 329
Reputation: 4556
Some suggestions for you.
MainViewModel
class, and set the DataContext
of MainWindow
to an instance of this.ICommand
, and bind the button's Command
property to it.Depending on what (library) you're using to implement the MVVM pattern, you may already have an ICommand
implementation, such as MVVMLight's
RelayCommand
. If not, you can use a basic ICommand implementation such as
public class BasicCommand: ICommand
{
private readonly Action _execute;
public Command(Action execute)
{
_execute = execute;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
_execute?.Invoke();
}
public event EventHandler CanExecuteChanged;
}
In MainViewModel, create a property of type object ContentViewModel, and bind the ContenControl's Content property to it. This property should implement INotifyPropertyChanged
as you're going to update it from within the ViewModel.
In the corresponding method for the command, set the ContentViewModel property to an appropriate value - e.g. a Window1ViewModel instance.
In the ContentControl resources, define a DataTemplate for each type you might want to display. This needs to be based on a something other than a Window - eg Grid or CustomControl or UserControl.
.
<ContentControl
Margin="8"
Content="{Binding SelectedItem}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type vm:Window1ViewModel}">
<ctrl:Window1Display DataContext="{Binding}" />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:Window2ViewModel}">
<ctrl:Window2Display DataContext="{Binding}" />
</DataTemplate>
...
</ContentControl.Resources>
</ContentControl>
More details, and a working example on my blog post.
Upvotes: 1