Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将ContentControl绑定到UserControl,并重用同一实例_C#_Wpf_Xaml_Binding_Contentcontrol - Fatal编程技术网

C# 将ContentControl绑定到UserControl,并重用同一实例

C# 将ContentControl绑定到UserControl,并重用同一实例,c#,wpf,xaml,binding,contentcontrol,C#,Wpf,Xaml,Binding,Contentcontrol,我试图将ContentControl的内容绑定到我在ViewModel中实例化的UserControl。我不能使用绑定到ViewModel的方法,然后让UserControl成为ViewModel的DataTemplate,因为我需要ContentControl的内容能够频繁更改,使用UserControl/Views的相同实例,而不是在每次重新绑定时实例化视图 但是,当将UserControl属性设置为UserControl实例时,以及当视图呈现/数据绑定时,我得到:必须先断开指定子项与当前父

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

但是,当将UserControl属性设置为UserControl实例时,以及当视图呈现/数据绑定时,我得到:必须先断开指定子项与当前父项视觉的连接,然后再附加到新父项视觉。尽管我之前没有将这个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");
        }
    }

    //...
}
公共类MyViewModel:INotifyPropertyChanged
{
//...
私有void LoadApps()
{
var实例=新列表
{
新建Instance1View(),
新建Instance2View(),
新建Instance3View(),
};
切换实例(实例);
}
私有void开关实例(列表实例)
{
CenterApp=实例[0];
}
//...
私人用户控制(centerApp),;
公共用户控制中心应用程序
{
获取{return\u centerApp;}
设置
{
如果(_centerApp==值)
{
返回;
}
_centerApp=价值;
OnPropertyChanged(“CenterApp”);
}
}
//...
}
在View.xaml中

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

评论太长

基于@Kent在您的评论中所说的内容,MVVM的整个要点是将视图模型与视图相关的东西(控件)断开连接,这会阻碍GUI应用程序的测试能力。因此,用户控件/按钮/任何与图形视图相关的项目都否定了MVVM的整个原则

如果使用MVVM符合其标准,则应该重新解决您的问题

  • 使用MVVM,您通常有一个视图一个视图模型
  • 视图了解其视图模型(通常通过DataContext)。不应将倒档编码到
  • 您尝试将控制视图的逻辑放在视图模型中,以允许测试逻辑(命令和INPC属性)
  • 。。。还有很多。它在视图模型的范围中非常具体,没有与视图相关的东西,例如在视图模型中甚至没有属性,如
    可见性
    。您通常持有
    bool
    ,然后在视图中使用转换器将其切换到
    可见性
    对象

    多读一点MVVM肯定会对您有所帮助

    现在,让我们来谈谈您当前的问题:

    遵循MVVM结构

    您将拥有ViewModels,例如

    • Main:
      MyViewModel
    • 从基础派生所有实例视图模型,以允许它们保留在列表中
    • MyViewModel
      中分别列出或保持
      Instance1ViewModel
      Instance2ViewModel
      Instance3ViewModel
      (可以自己创建,也可以使用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);
      }
    }
    
    ...
    <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>
    ...
    
    • 现在,在您的
      MyView.xaml
      View文件中,您应该(不必是顶级的)将顶级数据上下文设置为您的
      MyViewModel
    • 然后,您的视图的xaml可以声明为:
    例如:

    // 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);
      }
    }
    
    ...
    <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动态重新创建视图的另一个问题,您可以按照建议的方法进行操作,并将其扩展以供自己使用。

    “我在ViewModel中实例化的用户控件”您做得不对。在主视图模型中实例化次视图模型,将内容控件绑定到该模型,并使用内容模板显示其可视化树。VM不应该创建视图(或依赖于视图)。@KentBoogaart,据我所知(在我的问题中说):我不能使用绑定到ViewModel的方法,然后让UserControl成为ViewModel的DataTemplate,因为我需要ContentControl的内容能够频繁更改,使用相同的UserControls/Views实例,而不是在每次重新绑定时实例化视图。还是我不明白datatemplate是如何工作的?谢谢你的详细回答!我理解所有这些,这是我第一次尝试修复它——使用视图作为ViewModel的数据模板。但是,在视图中,我将VisualStates绑定到ViewModel属性,当我将绑定到ContentControl的ViewModel切换到另一个VM,然后将其切换回时,内存中似乎有两个视图实例,它们都将ViewState绑定到我的ViewModel。每次我重新绑定ContentControl时,它都会创建一个新的视图实例。我找不到一个解决方案,可以在ContentControl中使用相同的视图实例。这时我尝试将视图实例绑定到ContentControl,而不是ViewModel,从而打破了MVVM模式。@cederlof没有问题。我理解您在从视图模型切换视图时保留视图的问题。你看过我文章最后一段的链接了吗。这个问题和你的问题一模一样,有一些有用的答案。您可以尝试Rachael的示例,并将其应用到您的容器中,以获得您的需求和否