WPF / MVVM在运行时加载UserControl

我知道有很多关于我的问题的文章,但我找不到解决方案。 我是WPF的新手 – MVVM,我尝试理解MVVM-Logic。 所以我做了一个小项目来理解这一点。 对于我以后的应用程序,我想动态地将UserControls加载到我的窗口。

在我的StartView中,我有一个绑定到StartViewModel。 (绑定在APP.xaml中)

StartView app = new StartView(); StartViewModel context = new StartViewModel(); 

StartView

           

StartViewModel

 namespace test.ViewModel { public class StartViewModel : ViewModelBase { #region Fields private UCStastistikViewModel _loadedControl; #endregion public StartViewModel() { LoadedControl = new UCStastistikViewModel(); } #region Properties / Commands public UCStastistikViewModel LoadedControl { get { return _loadedControl; } set { if (value == _loadedControl) return; _loadedControl = value; OnPropertyChanged("LoadedControl"); } } #endregion #region Methods #endregion } } 

UCStatistikView

        

UCStatistikViewModel

 namespace test.ViewModel { public class UCStastistikViewModel : ViewModelBase { #region Fields #endregion public UCStastistikViewModel() { } #region Properties / Commands #endregion #region Methods #endregion } } 

现在我想在我的StartView的ContentControl中加载我的UCStatistikView。 但是在Startview中只显示Path test.UCStatistikViewModel而不是整个UC可以任何人给我一些想法,我的问题在哪里/哪里出错了?

再见j

您的ViewModel不应该关心UserControls。 相反,让他们持有ViewModels,让WPF解决如何使用DataTemplate绘制ViewModel。

例如,

                

此外,摆脱中的DataContext应该由使用控件的任何东西传入,而不是在UserControl中定义的:)

编辑

根据您对之前关于通过切换ViewModel来切换StartPage内容的回答的评论,您可能有兴趣查看我的这篇文章 。 它的标题是Navigation with MVVM ,但是相同的概念适用于切换视图或用户控件

基本上,您将使用ViewModelBase类型的属性LoadedControl而不是硬编码它的类型,然后将其设置为您希望在ContentControl中显示的任何对象。 WPF的DataTemplates将负责为ViewModel连接正确的View。

WPF不支持自动解析给定视图模型的视图。 您问题的天真解决方案是直接将UCStatistikView添加到您的StartView并将VM绑定到它

          

更详细的方法是实现ViewLocator(视图模型第一种方法)或ViewModelLocator(视图第一种方法)。 定位器自动定位视图并将视图绑定到视图模型。 有一些MVVM框架/工具包可以实现这样的定位器。

  • Caliburn.Micro :根据命名约定提供灵活的ViewLocator和ViewModelLocator。 这是一篇关于他们的文章
  • MVVM Light :提供ViewModelLocator。 这是一个介绍

使用Caliburn.Micro,您开始查看将如下所示

          

cm:View.Model="{Binding LoadedControl}"附加属性告诉caliburn找到绑定的视图模型的视图,并将ContentControl的Content属性设置为它。

这是你应该做的:

StartView:

           

StartViewModel:

 namespace test.ViewModel { public class StartViewModel : ViewModelBase { private UCStastistikViewModel _myControlViewModel; public StartViewModel() { _myControlViewModel = new UCStastistikViewModel(); } public UCStastistikViewModel MyControlViewModel { get { return _myControlViewModel; } set { if (value == _myControlViewModel) return; _myControlViewModel = value; OnPropertyChanged("MyControlViewModel"); } } } } 

UCStatistikView:

     

您的StartView背后的代码:

 this.myUCStatistikView.DataContext = ((StartViewModel)this.DataContext).MyControlViewModel; 

在测试了不同的方法之后,我的结论是,如果你有userControls,那么datacontext绑定的最佳方法是父视图的代码隐藏。

编辑 :ViewModel定位器适用于简单的示例,但如果您的ViewModel必须动态实例化(主要是它的构造函数需要参数的情况),您就无法使用它。 我个人因此而停止使用定位器。

评论: – http://patelrocky1608.wordpress.com/2013/12/26/how-to-add-custom-control-dynamically-in-wpf/

其中包含用于动态理解UserControl的整个代码..