将 ContentControl 绑定到 UserControl,并重用相同的实例 [英] Binding a ContentControl to UserControl, and reuse same instance

查看:21
本文介绍了将 ContentControl 绑定到 UserControl,并重用相同的实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to bind a ContentControl's Content to a UserControl I have instantiated in my ViewModel. I cannot use the method with binding to a ViewModel and then have the UserControl be the DataTemplate of the ViewModel, as I need the Content of the ContentControl to be able to change frequently, using the same instance of the UserControls/Views, and not instantiate the views each time i re-bind.

但是,当将 UserControl-property 设置为 UserControl-instance,然后当视图呈现/绑定数据时,我得到:在附加到新的父 Visual 之前,必须断开指定的子级与当前父 Visual 的连接. 即使我之前没有将这个 UserControl 添加到任何地方,我只是早先创建了这个实例并将其保存在内存中.

However, when setting the UserControl-property to a UserControl-instance, and then when the view is rendered/data-bound I get: Must disconnect specified child from current parent Visual before attaching to new parent Visual. Even though I have not previously added this UserControl to anywhere, I just created this instance earlier and kept it in memory.

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

Are there a better way to achieve what I am doing?

在视图模型中

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 中

In the View.xaml

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

推荐答案

评论太长.

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

Building up on what @Kent stated in your comment, The whole point of MVVM is to disconnect the view-model from view related stuff(controls) which blocks the testing capability of GUI applications. Thus you having a UserControl / Button / whatever graphical view-related item negates the entire principle of MVVM.

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

You should if using MVVM comply with its standards and then re-address your problem.

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

...还有很多.它在视图模型的范围内非常具体,没有与视图相关的东西,例如在视图模型中甚至没有像 Visibility 这样的属性.您通常持有一个 bool,然后在视图中使用转换器将其切换到 Visibility 对象.

... and quite a few more. It's pretty specific in the extents of view-model not having view related stuff for eg not even having properties in view-model like Visibility. You normally hold a bool and then in the view use a converter to switch it to the Visibility object.

深入了解 MVVM 肯定会对您有所帮助,

Reading up a bit more into MVVM would certainly help you,

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

Now for something to address your current issue:

遵循 MVVM 结构,

Following a MVVM structure,

您将拥有诸如

  • 主要:MyViewModel
  • 从基础派生所有实例 ViewModel 以允许将它们保存在列表中.
  • MyViewModel 中单独列出或保存 Instance1ViewModelInstance2ViewModelInstance3ViewModel(要么自己创建,要么使用 IOC 容器让它注入它)
  • MyViewModel 像您发布的示例一样公开一个属性:
  • Main: MyViewModel
  • Derive all instance ViewModels from a base to allow them being kept in a list.
  • List or hold individually Instance1ViewModel, Instance2ViewModel, Instance3ViewModel in MyViewModel (Either create it yourself or if your using an IOC container let it inject it)
  • Have MyViewModel expose a property just like your posted example:

示例:

// 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 可以这样声明:
    • Now in your MyView.xaml View file you should(does'nt have to be top level) set the top-level DataContext to your MyViewModel
    • Your View's xaml can then be declared like:
    • 示例:

      ...
      <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 属性并使其指向三个实例视图模型中的任何一个,视图就会相应地更新.
        • Thats it!. Now you just switch the CurrentFrame property in your view-model and make it point to any of three instance view-models and the view will be correspondingly updated.
        • 这为您提供了一个符合 MVVM 的应用程序,对于您不必根据 DataTemplate 动态重新创建视图的其他问题,您可以遵循建议的方法 此处 并扩展它以供您自己使用.

          This gets you an MVVM compliant application, for your other issue of working around not having to recreate views dynamically based on DataTemplate you could follow the approaches suggested here and expand it for your own usage.

          这篇关于将 ContentControl 绑定到 UserControl,并重用相同的实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆