Change view to Buttonclick

I am studying WPF and MVVM at the moment (or at least I'm trying ...).

I created a small sample application that shows a window with two buttons, each of which should show a new view on click. So I created 3 UserControls (DecisonMaker with 2 buttons and one Usercontrol for each "clicktarget").

So, I bound the CotentControl MainWindow to a property called CurrentView in my MainWindowViewModel

Code MainWindow.xaml:

<Window x:Class="WpfTestApplication.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfTestApplication" Title="MainWindow" Height="350" Width="525"> <Window.DataContext> <local:MainWindowViewModel /> </Window.DataContext> <Grid> <ContentControl Content="{Binding CurrentView, Mode=OneWay}" /> </Grid> </Window> 

MainWindowViewModel Code:

 class MainWindowViewModel { private UserControl _currentView = new DecisionMaker(); public UserControl CurrentView { get { return _currentView; } set { _currentView = value; } } public ICommand MausCommand { get { return new RelayCommand(LoadMouseView); } } public ICommand TouchCommand { get { return new RelayCommand(LoadTouchView); } } private void LoadMouseView() { CurrentView = new UserControlMouse(); } private void LoadTouchView() { CurrentView = new UserControlTouch(); } } 

The initial UserControl (DecisionMaker) is displayed as expected. The LoadMouseView method is also called. But the view does not change. What am I missing?

UPDATE: Thanks so much! I skipped the INotifyPropertyChanged interface. All your answers were just wonderful and very accurate and helpful! I don’t know which one to accept - I think this is the fairest way to accept the "first" answer?

I accepted blindmeis answer as it solved the problem and helped me better understand MVVM. But every answer was really great thanks to all of you!

+6
source share
5 answers

if you want to do mvvm - then you should have no links to your view / usercontrols in your model viewmodel. you need to implement INotifyPropertyChanged ! ps: if you need the System.Windows namespace in your Viewmodel, then something is wrong.

in your case, what you need:

  • 1 mainviewmodel
  • 1 viewmodel for UserControlMouse
  • 1 viewmodel for UserControlTouch
  • 1 view / usercontrol for UserControlMouse
  • 1 view / usercontrol for UserControlTouch

your mainviewmodel must have at least 2 commands to switch your view and 1 property for CurrentView. in your team, you simply set your CurrentView to a suitable instance of viewmodel. at least you need two datasets for each model that determine the correct look.

 public object CurrentView { get { return _currentView; } set { _currentView = value; this.RaiseNotifyPropertyChanged("CurrentView");} } 

Xaml

 <Window x:Class="WpfTestApplication.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfTestApplication" Title="MainWindow" Height="350" Width="525"> <Window.Resources> <DataTemplate DataType="{x:Type local:MyMouseViewModel}"> <local:MyMouseUserControlView/> </DataTemplate> <DataTemplate DataType="{x:Type local:MyTouchViewModel}"> <local:MyTouchUserControlView/> </DataTemplate> </Window.Resources> <Window.DataContext> <local:MainWindowViewModel /> </Window.DataContext> <Grid> <!-- here your buttons with command binding, i'm too lazy to write this. --> <!-- you content control --> <ContentControl Content="{Binding CurrentView, Mode=OneWay}" /> </Grid> </Window> 
+6
source

I would do something like this to select the input style you want and MainWindow. I added a property that allows me to choose an input method.

 public enum UserInterfaceModes { Mouse, Touch, } public UserInterfaceModes UserInterfaceMode { get { return (UserInterfaceModes)GetValue(UserInterfaceModeProperty); } set { SetValue(UserInterfaceModeProperty, value); } } public static readonly DependencyProperty UserInterfaceModeProperty = DependencyProperty.Register("UserInterfaceMode", typeof(UserInterfaceModes), typeof(MainWindow), new UIPropertyMetadata(UserInterfaceModes.Mouse)); 

then for the xaml viewing part, you can select the correct template using a trigger.

 <Style TargetType="{x:Type local:MainWindow}"> <Style.Triggers> <DataTrigger Binding="{Binding UserInterfaceMode}" Value="Mouse"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type local:MainWindow}"> <Grid Background="Red"/> </ControlTemplate> </Setter.Value> </Setter> </DataTrigger> <DataTrigger Binding="{Binding UserInterfaceMode}" Value="Touch"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type local:MainWindow}"> <Grid Background="Blue"/> </ControlTemplate> </Setter.Value> </Setter> </DataTrigger> </Style.Triggers> </Style> 
+3
source

Viewmodel models need to implement INotifyPropertyChanged . Otherwise, the view will not be notified when the property changes in the view model.

 class MainWindowViewModel : INotifyPropertyChanged { private UserControl _currentView = new DecisionMaker(); public UserControl CurrentView { get { return _currentView; } set { _currentView = value; OnPropertyChanged("CurrentView"); } } public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } } 
+2
source

You need to implement INotifyPropertyChanged in MainWindowViewModel so that the view is notified when the CurrentView property changes.

+1
source

It seems that the behavior you want is largely related to what you get with [TabControl][1] - why not use this built-in control and just bind the DataContext to both tabs to the same view model .

This also has the advantage that your view model will not know about the presentation classes (I assume UserControlMouse , etc. are user controls).

Note: this does not apply if you need a view model to know if it is in touch or mouse mode.

+1
source

Source: https://habr.com/ru/post/917864/


All Articles