2

我正在尝试将 ContentControl 的内容绑定到我在 ViewModel 中实例化的 UserControl。我不能使用绑定到 ViewModel 的方法,然后让 UserControl 成为 ViewModel 的 DataTemplate,因为我需要 ContentControl 的内容能够经常更改,使用相同的 UserControls/Views 实例,而不是实例化每次我重新绑定的意见。

但是,当将 UserControl-property 设置为 UserControl-instance 时,然后当视图被渲染/数据绑定时,我得到:在附加到新的父 Visual 之前,必须断开指定子与当前父 Visual 的连接。尽管我之前没有将此 UserControl 添加到任何地方,但我只是较早地创建了此实例并将其保存在内存中。

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

在视图模型中

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>
4

1 回答 1

3

评论太长了。

建立在@Kent 在您的评论中所说的基础上,MVVM 的全部意义在于将视图模型与视图相关的东西(控件)断开,这会阻止 GUI 应用程序的测试能力。因此,您拥有一个 UserControl / Button / 任何与图形视图相关的项目都否定了 MVVM 的整个原则。

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

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

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

更多地阅读 MVVM 肯定会对你有所帮助,

现在来解决您当前的问题:

遵循 MVVM 结构,

您将拥有 ViewModel,例如

  • 主要的: MyViewModel
  • 从基础派生所有实例 ViewModel 以允许将它们保存在列表中。
  • 单独列出或持有Instance1ViewModel, Instance2ViewModel, Instance3ViewModelin MyViewModel(要么自己创建它,要么如果你使用 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视图文件中,您应该(不必是顶级)将顶级 DataContext 设置为您的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 动态重新创建视图的其他问题,您可以遵循此处建议的方法并将其扩展以供您自己使用。

于 2013-03-28T21:31:20.363 回答