单击按钮时更改视图
本文关键字:视图 按钮 单击 | 更新日期: 2023-09-27 18:36:57
我现在正在学习WPF和MVVM(或者至少我正在尝试......)。
我创建了一个小的示例应用程序,它显示一个带有 2 个按钮的窗口,每个按钮都应该在单击时显示一个新的视图。所以我创建了 3 个用户控件(带有 2 个按钮的 DecisonMaker,每个"点击目标"都有一个用户控件)。
因此,我将 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();
}
}
初始用户控件(决策者)按预期显示。还调用了方法LoadMouseView
。但视图不会改变。我错过了什么?
更新:非常感谢!我错过了INotifyPropertyChanged-interface。你所有的回答都很棒,非常准确和有帮助!我不知道该接受哪一个——
接受了盲目的答案,因为它解决了问题并帮助我更好地理解了 MVVM。但是,每个答案都非常感谢你们所有人!
做MVVM - 那么你不应该在你的视图模型中引用你的视图/用户控件。 你必须实现 INotifyPropertyChanged! ps:如果你的视图模型中需要System.Windows命名空间 - 那么有问题。
在您的情况下,您需要什么:
- 1 主视图模型
- 1 个视图模型的用户控件鼠标
- 1 个视图模型用于用户控件触摸
- 1 个视图/用户控件,用于用户控制鼠标 1 个视图/用户控件,
- 用于用户控件触摸
您的主视图模型应该至少有 2 个用于切换视图的命令和 1 个用于当前视图的属性。 在您的命令中,您只需将 CurrentView 设置为正确的视图模型实例即可。 每个视图模型至少需要两个数据模板来定义正确的视图。
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>
我会做这样的事情来选择你想要的输入样式,在 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>
视图模型需要实现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));
}
}
}
您需要在 MainWindowViewModel
上实现INotifyPropertyChanged
,以便在更改 CurrentView
属性时通知视图。
的行为几乎就是你通过[TabControl][1]
得到的行为 - 为什么不使用它内置控件,只需将两个选项卡的DataContext
绑定到同一个视图模型。
这也有一个优点,即您的视图模型不知道视图类(我假设UserControlMouse
等是用户控件)。
注: 如果您需要视图模型知道它是处于触摸模式还是鼠标模式,则这不适用。