更改按钮上的视图单击

时间:2012-06-12 08:58:35

标签: c# wpf user-interface mvvm

我正在学习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。但是,感谢你们所有人,每个答案都非常好!

5 个答案:

答案 0 :(得分:6)

如果你想做mvvm - 那么你应该在你的viewmodel中对你的view / usercontrols 没有引用。你必须实现 INotifyPropertyChanged ! ps:如果你的Viewmodel中需要System.Windows命名空间 - 那就错了。

在您的情况下您需要什么:

  • 1 mainviewmodel
  • 用于UserControlMouse的1个视图模型
  • 用于UserControlTouch的1个视图模型
  • 用于UserControlMouse的1个/ usercontrol
  • 1 User / Controlcontrol for UserControlTouch

你的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等是用户控件)。

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