将ViewModel绑定到ContentControl作为其DataContext

7

我希望在按钮点击时更改用户控件(为了不让事情变得复杂,我只提到重要部分)。 所以想法是将这些用户控件的ViewModel绑定到ContentControl上,然后使用DataTemplates将它们与Views相关联。 以下是代码:

<Window x:Class="Project.MainWindow">
<Window.Resources>
    <DataTemplate DataType="{x:Type UserControl:ViewUserControlViewModel}" >
        <UserControl:ViewUserControl/>
    </DataTemplate>
    <DataTemplate DataType="{x:Type UserControl:EditUserControlViewModel}" >
        <UserControl:EditUserControl/>
    </DataTemplate>
</Window.Resources>
<Grid>
    <ContentControl DataContext="{Binding UserControlViewModel}" />
    <Button Content="View" Click="ChangeToView()"/>
    <Button Content="Edit" Click="ChangeToEdit()"/>
</Grid>
</Window>

ViewModel:

public class MainWindowViewModel : DependencyObject
{
    public DependencyObject UserControlViewModel
    {
        get { return (DependencyObject)GetValue(UserControlViewModelProperty); }
        set { SetValue(UserControlViewModelProperty, value); }
    }
    public static readonly DependencyProperty UserControlViewModelProperty = 
           DependencyProperty.Register("UserControlViewModel", typeof(DependencyObject), typeof(MainWindowViewModel), new PropertyMetadata());

    public MainWindowViewModel()
    {
        UserControlViewModel = new EditUserControlViewModel();
    }
}

但是出现了问题。当我开始项目时,我只看到按钮,而没有任何用户控件。我做错了什么?


这是一个笔误吗?您注册了 userControlViewModel 但绑定到的是 UserControlViewModel。 - LPL
是的,这是一个打字错误。我已经纠正了 :) - Miro
3个回答

19
如果您的Window.DataContext已正确设置为MainWindowViewModel,那么这应该可以完成工作。
<ContentControl Content="{Binding UserControlViewModel}" />

1
是的,这里的主要问题是将ContentControl的DataContext绑定而不是Content。 DataContext不能控制内容控件将显示什么。 - Steve Py
2
你是一个救命恩人。 - rajibdotnet
1
你救了我的一天。 - r2d2
1
这个应该怎么工作?ContentControl 应该持有 View,而不是 ViewModel,对吗? - csstudent1418
1
@csstudent1418 没错。你不会直接显示 ViewModel。但是 DataTemplates 将数据(例如 ViewModels)链接到特定的视图,就像 OP 的示例代码一样。然后你只需要更改 ViewModel,视图就会相应地更改。 - LPL
显示剩余2条评论

4
在进行mvvm时,您的viewmodel应该实现INotifyPropertyChanged接口,而不是继承DependencyObject。
public class MainWindowViewModel : INotifyPropertyChanged
{
   private object _currentWorkspace; //instead of object type you can use a base class or interface
   public object CurrentWorkspace
   {
      get { return this._currentWorkspace; }
      set { this._currentWorkspace = value; OnPropertyChanged("CurrentWorkspace"); }
   }


   public MainWindowViewModel()
   {
      CurrentWorkspace= new EditUserControlViewModel();
   }

   //todo: to switch the workspace, create DelegeCommand/RelayCommand and set the CurrentWorkspace
   //if you don't know about these commands let me know and i post it

   public ICommand SwitchToViewCommand {get{...}}
   public ICommand SwitchToEditCommand {get{...}}
}

XAML:您应该将Content属性设置为当前工作区。

<ContentPresenter Content="{Binding UserControlViewModel}" />
<Button Content="View" Comamnd="{Binding SwitchToViewCommand}"/>
<Button Content="Edit" Comamnd="{Binding SwitchToEditCommand}"/>

不要忘记将你的窗口的DataContext设置为MainWindowViewModel实例。


1
首先,您应该发布UserControl的代码,因为(在上面的代码片段中)它负责显示一些数据。
其次,您的代码中没有绑定任何内容。
第三,您的ViewModel实现是错误的。您不需要子类化DependencyObject,而是要实现INotifyPropertyChanged接口,以建立一个能够通知您的View的ViewModel。
第四,我不知道您正在做什么。
<ContentControl DataContext="{Binding UserControlViewModel}" />

也许您可以进一步解释一下?
在实现MVVM模式时(目前您还没有这样做),第五点应该避免使用像点击事件这样的事件,而是使用命令。
(我知道这还不是一个真正的答案,但我不想写在注释语法中)

  1. UserControl的代码不相关。有两个UserControl,都只有一个元素——Label(一个的内容是“View”,另一个的内容是“Edit”)。
  2. 见4)
  3. 你在哪里看到DependencyObject的子类?它是一个DependencyProperty。
  4. 这是一个ContentControl,具有绑定到Project.MainWindow ViewModel中的UserControlViewModel DependencyProperty的DateContext。
- Miro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接