将ContentControl绑定到UserControl,并重用相同的实例

本文关键字:实例 绑定 ContentControl UserControl | 更新日期: 2023-09-27 18:06:30

我试图绑定一个ContentControl的内容到一个UserControl我已经在我的ViewModel实例化。我不能使用绑定到ViewModel的方法,然后有UserControl是ViewModel的DataTemplate,因为我需要ContentControl的内容能够经常改变,使用UserControls/Views的相同的实例,而不是实例化视图每次我重新绑定。

然而,当设置usercontrol -属性为UserControl-instance时,然后当视图被渲染/数据绑定时,我得到:必须在附加到新的父可视化之前从当前父可视化断开指定的子。尽管我之前没有将这个UserControl添加到任何地方,但我只是在之前创建了这个实例并将其保存在内存中。

有没有更好的方法来实现我正在做的事情?

在ViewModel

public class MyViewModel : INotifyPropertyChanged
{
    //...
    private void LoadApps()
    {
        var instances = new List<UserControl>
                          {
                              new Instance1View(),
                              new Instance2View(),
                              new Instance3View(),
                          };
        SwitchInstances(instances);
    }
    private void SwitchInstances(List<UserControl> instances)
    {
        CenterApp = instances[0];
    }
    //...
    private UserControl _centerApp;
    public UserControl CenterApp
    {
        get { return _centerApp; }
        set
        {
            if (_centerApp == value)
            {
                return;
            }
            _centerApp = value;
            OnPropertyChanged("CenterApp");
        }
    }
    //...
}

View.xaml

<ContentControl Content="{Binding CenterApp}"></ContentControl>

将ContentControl绑定到UserControl,并重用相同的实例

注释太长

根据@Kent在你的评论中所说的,MVVM的全部要点是将视图模型与视图相关的东西(控件)断开连接,这阻碍了GUI应用程序的测试能力。因此,拥有UserControl/Button/任何与图形视图相关的项否定了MVVM的整个原则。

如果使用MVVM,你应该遵守它的标准,然后重新解决你的问题。

  1. 使用MVVM通常有1个视图<-> 1个视图模型
  2. 视图知道它的视图模型(通常通过DataContext)。反向不应该被编码到。
  3. 您尝试在视图模型中放置控制视图的逻辑,以允许测试逻辑(命令和INPC属性)

…还有更多。它在视图模型没有视图相关的东西的范围内是非常具体的,例如视图模型中甚至没有属性,比如Visibility。您通常持有bool,然后在视图中使用转换器将其切换到Visibility对象。

多读一点关于MVVM的知识肯定会对你有帮助,

现在有一些东西可以解决你当前的问题:

在MVVM结构之后,

你会有ViewModels,比如

  • Main: MyViewModel
  • 从一个基中派生所有的实例viewmodel,以允许它们保存在一个列表中。
  • 列出或单独持有Instance1ViewModel, Instance2ViewModel, Instance3ViewModelMyViewModel(要么创建它自己,或者如果你使用IOC容器让它注入)
  • MyViewModel暴露一个属性,就像你发布的例子:

的例子:

// ViewModelBase is the base class for all instance View Models
private ViewModelBase _currentFrame;
public ViewModelBase CurrentFrame {
  get {
    return _currentFrame;
  }
  private set {
    if (value == _currentFrame)
      return;
    _currentFrame = value;
    OnPropertyChanged(() => CurrentFrame);
  }
}

  • 现在在你的MyView.xaml视图文件中,你应该(不必是顶级的)将顶级数据文本设置为你的MyViewModel
  • 你的视图的xaml可以这样声明:

的例子:

...
<Window.Resources>
  <DataTemplate DataType="{x:Type local:Instance1ViewModel}">
    <local:Instance1View />
  </DataTemplate>
  <DataTemplate DataType="{x:Type local:Instance2ViewModel}">
    <local:Instance2View />
  </DataTemplate>
  <DataTemplate DataType="{x:Type local:Instance3ViewModel}">
    <local:Instance3View />
  </DataTemplate>
</Window.Resources>
<Grid>
  <ContentControl Content="{Binding Path=CurrentFrame}" />
</Grid>
...

  • !。现在,您只需切换视图模型中的CurrentFrame属性,并使其指向三个实例视图模型中的任何一个,视图将相应地更新。

这让你得到一个MVVM兼容的应用程序,对于你的工作周围的其他问题,不必基于DataTemplate动态地重新创建视图,你可以遵循这里建议的方法,并扩展它为您自己的使用。