单击按钮时更改视图

本文关键字:视图 按钮 单击 | 更新日期: 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等是用户控件)。

注: 如果您需要视图模型知道它是处于触摸模式还是鼠标模式,则这不适用。