我正在学习WPF和MVVM(或者至少我正在努力......)。
我创建了一个小样本应用程序,它显示了一个带有2个按钮的窗口,每个按钮都应显示一个新的Click on View。所以我创建了3个UserControls(带有2个按钮的DecisonMaker,以及每个“clicktarget”的一个Usercontrol)。
所以我将MainWindow的CotentControl绑定到我的MainWindowViewModel中名为“CurrentView”的属性
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代码:
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();
}
}
初始UserControl(DecisionMaker)显示为假设。方法LoadMouseView
也被调用。但是View并没有改变。我错过了什么?
更新:非常感谢!我错过了INotifyPropertyChanged接口。你的所有答案都很棒,非常准确,乐于助人!我不知道接受哪一个 - 我认为接受“第一”答案是最公平的方式吗?
我接受了blindmeis的回答,因为它解决了问题并帮助我更好地理解MVVM。但是,感谢你们所有人,每个答案都非常好!
答案 0 :(得分:6)
如果你想做mvvm - 那么你应该在你的viewmodel中对你的view / usercontrols 没有引用。你必须实现 INotifyPropertyChanged ! ps:如果你的Viewmodel中需要System.Windows命名空间 - 那就错了。
在您的情况下您需要什么:
你的mainviewmodel应至少有2个命令来切换你的视图和1个属性的CurrentView。在您的命令中,您只需将CurrentView设置为正确的viewmodel实例。至少每个viewmodel需要两个datatemplate来定义正确的视图。
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>
答案 1 :(得分:3)
我会做这样的事情来选择你想要的输入风格,到MainWindow我添加了一个属性,让我选择输入模式。
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));
然后对于xaml视图部分,您可以使用触发器选择正确的模板。
<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>
答案 2 :(得分:2)
viewmodel需要实现INotifyPropertyChanged
。否则,当视图模型中的属性发生更改时,将不会通知视图。
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));
}
}
}
答案 3 :(得分:1)
您需要在INotifyPropertyChanged
上实施MainWindowViewModel
,以便在CurrentView
属性发生更改时通知视图。
答案 4 :(得分:1)
听起来你想要的行为几乎就是你使用[TabControl][1]
获得的行为 - 为什么不使用这个内置控件,只需将两个标签的DataContext
绑定到同一个视图模型。 / p>
这也有一个优点,就是你的视图模型不会知道视图类(我假设UserControlMouse
等是用户控件)。
注意:如果您需要视图模型知道它是处于触摸模式还是鼠标模式,这将不适用。