使用WPF中的MVVM模式在运行时加载XAML

这是一个从最初发布的问题扩展到的问题: 链接到loading-xaml到运行时

我正在开发一个WPF MVVM应用程序,它从外部源动态加载XAML内容,与上面的post中的答案非常相似。
这是我到目前为止所得到的:

  1. My View将ViewModel的实例声明为资源,并创建该ViewModel的实例
  2. 在我的ViewModel构造函数中,我正在加载来自外部源(文件或数据库…)的XamlString属性。
  3. 在我看来,我有一个用户在ViewModel完成加载后点击的按钮,在点击事件代码隐藏中,我将动态加载的XAML反序列化并将其添加到我的网格中。

我的问题是,如何消除代码隐藏并自动化逻辑,以便View可以在ViewModel完成获取XAML内容并初始化字符串属性后立即动态呈现新的xaml部分?

我应该使用某种消息传递总线,以便ViewModel在设置属性后通知,以便View可以添加新内容吗?

让我感到困扰的是,ViewModel确实有对Views的引用,不应该负责生成UI元素。

提前致谢!

编辑 :只是为了澄清:在我的特定情况下,我不是试图将业务对象或集合(模型)绑定到UI元素(例如网格),这显然可以通过模板和绑定来完成。 我的ViewModel正在从外部源检索整个XAML表单,并将其设置为View可用的字符串属性。

我的问题是:一旦我设置了VM中的Xaml字符串属性,谁应该负责将此XAML字符串属性反序列化为UI元素并以编程方式将其添加到我的网格中?
这听起来更像是一个View责任,而不是ViewModel。 但我理解的模式强制要用V-VM绑定替换任何代码隐藏逻辑。

我现在有一个工作解决方案,我想分享它。 不幸的是,我没有彻底摆脱代码隐藏,但它的工作方式与我期望的一样。 以下是它的工作原理(简化):

我有我简化的ViewModel:

public class MyViewModel : ViewModelBase { //This property implements INPC and triggers notification on Set public string XamlViewData {get;set;} public ViewModel() { GetXamlFormData(); } //Gets the XAML Form from an external source (eg Database, File System) public void GetXamlFormData() { //Set the Xaml String property XamlViewData = //Logic to get XAML string from external source } } 

现在我的观点:

                

基本上我创建了一个隐藏的TextBlock绑定到ViewModel中的我的XAML String属性,我将其Loaded事件挂钩到View后面代码中的事件处理程序:

  private void tb_XamlString_Loaded(object sender, RoutedEventArgs routedEventArgs) { //First get the ViewModel from DataContext MyViewModel vm = content.DataContext as MyViewModel; FrameworkElement rootObject = XamlReader.Parse(vm.XamlViewData) as FrameworkElement; //Add the XAML portion to the Grid content to render the XAML form dynamically! content.Children.Add(rootObject); } 

这可能不是最优雅的,但可以完成工作。 就像有些人说的那样,在MVVM中有一些像这样的情况需要很少的代码隐藏代码。 在使用VM检索和填充XamlString属性并将其暴露给View时,此解决方案的一部分仍然使用V-VM绑定原则。 如果我们想unit testingXAML解析和加载function,我们可以将它委托给一个单独的类。

我希望有人觉得这很有用!

我无法理解你在说什么,所以我的答案将基于我的解释。 您应该考虑发布您尝试做的样本(简化)。

1)我认为你误解了MVVM的作用。 MVVM主要是基于绑定的模式。 您的视图模型应该公开包含业务对象的属性,并且您的视图应该只绑定到这些属性。 如果我误解了你,那就是你正在做的事情,那么你的问题是你的视图需要知道属性何时更新(在反序列化你的xaml之后)。 有两种方法可以执行此操作:viewmodel上的INotifyPropertyChanged接口,或使视图模型inheritance自DependencyObject ,并创建属性依赖项属性。 我不会在这里详细介绍,因为这是一个很大的主题,您应该在做出决定之前在Google上进行研究。

2)一般来说,如果您使用的是MVVM,则不应在视图中使用click事件。 相反,在ICommand类型的视图模型上创建属性(并创建要匹配的ICommand实现,或使用DelegateCommand (谷歌)的实现,这将允许您使用委托来实现接口。想法是,您的视图绑定到属性并直接在viewmodel中执行处理程序。

3)如果要将信息从视图模型推送到视图,那么您应该在视图模型上创建一个事件并在视图中订阅它,但这是最后的手段,仅用于显示新窗口的情况等等。一般来说,你应该使用绑定。

4)为了更具体地说明你正在做什么,你应该将Grid的ItemsSource属性绑定到视图模型上的某个属性。 注意,如果您希望能够添加项目并获得即时更新,则视图模型上的属性应为ObservableCollection类型。

希望这可以帮助。