Wpf MVVM—我应该将动态生成和加载XAML的代码放在哪里?

Wpf MVVM—我应该将动态生成和加载XAML的代码放在哪里?,wpf,xaml,dynamic,mvvm,Wpf,Xaml,Dynamic,Mvvm,我想这是一个哲学问题,但我有一些代码,通过在运行时从模型数据生成XAML并使用XamlReader加载,动态地将模板列添加到GridView。我的问题是,在MVVM世界中,我应该把实现这一点的代码放在哪里?目前,我在代码隐藏中有它,但我正在考虑是否应该将它移到ViewModel。再考虑一下,我想我对自己的问题有一个答案,但我希望您的反馈,因为我对这个问题还是很陌生 通常,视图只知道ViewModel内部的属性,而ViewModel提供视图将绑定到的数据,但并不真正知道视图的任何小部件/UI元素。

我想这是一个哲学问题,但我有一些代码,通过在运行时从模型数据生成XAML并使用XamlReader加载,动态地将模板列添加到GridView。我的问题是,在MVVM世界中,我应该把实现这一点的代码放在哪里?目前,我在代码隐藏中有它,但我正在考虑是否应该将它移到ViewModel。

再考虑一下,我想我对自己的问题有一个答案,但我希望您的反馈,因为我对这个问题还是很陌生


通常,视图只知道ViewModel内部的属性,而ViewModel提供视图将绑定到的数据,但并不真正知道视图的任何小部件/UI元素。所以,我的想法是,我应该把这个代码放在代码后面。代码引用DataContext(设置为ViewModel)中的属性,钩住可视化树,并动态地向树添加更多分支和叶子。当我这么说的时候,我突然觉得它很“视图”:

在WPF/Silverlight开发者圈子里,有一个很大的运动,就是转向一个MVVM架构的解决方案,但是他们没有比简单或一般的例子更进一步。 在简单的应用程序中,这不是什么大问题。当你沉思时,它会变得严重

  • 动态构造的屏幕或页面,可能是为了响应用户操作
  • 由以下内容组成的复合页: 包含视图(可能是嵌套视图)的区域 视图,每个视图都实现为MVVP 三合会
  • 向导正在关闭一个 只需单击即可查看
这里有重要的逻辑。它去哪里了

正是这个(你的问题)让我把我的东西转移到MVVM的地方,我读了一篇很好的文章,这篇文章给了我一个很好的机会,这种架构适合一个更大的架构,其中一些类构成了MVVM三人组的生命周期

如果你想更详细地阅读全文沃德·贝尔·戈斯。 这可能只是大局中的一小部分,另一篇伟大的文章讨论了复合应用程序社区中的主要参与者,请参阅


这一切与你的问题有什么关系?我认为ViewModel代表视图,您的视图是在运行时确定的,因此,如果问题需要动态生成列,则可能是其他人负责创建渲染视图和适合最终结果的适当viewmodel并对其进行实例处理。

我认为生成XAML并使用XamlReader进行处理不是一个好主意

你为什么要做那件事

如果您希望视图依赖于数据类型或特定条件,则可以通过DataTemplate实现。DataType属性使其按类型选择模板。触发器和封闭的ContentControl可以根据数据条件交换模板


我认为你们准备在数据库中存储实际的XAML,这完全是另一回事,与MVVM无关。它有很多潜在的问题,比如性能、XamlReader语法限制、程序集/资源解析怪癖、安全性等等。

现在问题已经澄清了,下面再做一次尝试

首先,WPF工具箱中的WPF图表控件可能更好地处理图表,它们在其中添加了非常有趣的内容。我绝对建议在创建自定义的基于ListView的图表之前尝试一下

但无论如何,回到你澄清的问题上来。在这里,您应该使用DataTemplateSelector,或者使用设置模板的自定义IValueConverter触发

DataTemplateSelector的发明正是出于这个原因,但实际上它有点混乱。您需要处理从资源中加载模板的问题,这比XamlReader好一点

有了IValueConverter,情况会是这样:

    <DataTemplate>
        <ContentControl x:Name="content" Content="{Binding}">
        </ContentControl>
        <DataTemplate.Triggers>
            <DataTrigger Binding="{Binding Converter={local:TemplateChoseConverter}}" Value="SystemType">
                <Setter TargetName="content" Property="ContentTemplate">
                    <Setter.Value>
                        <DataTemplate>
                            <TextBlock Text="[system type] "/>
                        </DataTemplate>
                    </Setter.Value>
                </Setter>
            </DataTrigger>
            <DataTrigger Binding="{Binding Converter={local:TemplateChoseConverter}}" Value="Action">
                <Setter TargetName="content" Property="ContentTemplate">
                    <Setter.Value>
                        <DataTemplate>
                            <Button Text="[action] "/>
                        </DataTemplate>
                    </Setter.Value>
                </Setter>
            </DataTrigger>
        </DataTemplate.Triggers>
    </DataTemplate>

在这里,您将ContentControl放在DataTemplate中,并根据在IValueConverter中计算的内容在DataTemplate中触发交换内部嵌套模板


这样,您就永远不会处理XAML,即使您选择ValueConverter的模板也只会生成字符串,然后由触发器进行处理。

我得到了一个使用MVVM原则和少量代码的有效解决方案,希望它能帮到您:

@Ori,谢谢您的回答。沃德钟楼很吸引人,后面的内容也很吸引人()。关于MMVM,社区还有很多事情要弄清楚。至于我的特殊问题,分离生成独立列的代码肯定是有意义的。我可以看到将代码放在自己的类中,然后使用我的ScreenFactory实例化并运行它。(我实际上还没有任何屏幕工厂,但我一直在考虑如何处理快速扩展的app.cs文件——现在我有了一个计划:))同意屏幕工厂很有意义,因为屏幕和视图之间的差异还没有定论。我正试着使用GridView来显示透视表。设计时不知道列数(取决于数据库中存储的数据)。每个列的DataTemplate都不同(每个列绑定到不同的数据)。您将如何使用纯XAML进行设置?如果可能的话,我当然更愿意这样做。(请参阅代码示例)这需要单独的答案,因为注释很短。感谢您的回答,但我不知道有多少列是联合国的