我的应用程序中有多个位置ContentControl
放置在xaml中,我事先并不知道Content
将会是什么。实现此方案的最佳做法是什么?
现在我正在考虑两种方法:
ContentControl.Content
以查看模型并使用DataTemplate
的字典查找合适的视图。我对这种方法的问题在于,即使我要在一个单独的冠状动画中列出所有可能的组合,在某些情况下我只是在编译时根本不知道确切的视图类型(或视图模型,如果有的话)。我想,使用这种方法来托管非WPF内容我也会遇到麻烦。创建某种界面:
interface IContentPlugin : IDisposable
{
object View { get; }
}
直接将ContentControl.Content
绑定到IContentPlugin.View
。然后我可以有多个这个接口的实现,并在需要时交换它们。但是这个解决方案并没有让我觉得与MVVM应用程序相处得很好,因为它迫使我在我的视图模型中引用IContentPlugin
。
您认为最佳选择 以及为何 ?也许有更好的方法?
答案 0 :(得分:2)
您应该通过DataTemplates使用隐式视图确定。
这是通过为DataTemplates
ViewModel
范围内ResourceDictionary
类型的ContentControl
类型提供特定于类型的ResourceDictionary
(即没有关键参考的DataTemplates)来实现的。
请注意,如果单个ViewModel
可以与多个Views
相关联,则需要非常谨慎地考虑View
范围。
<强>更新强>:
使用隐式View
确定的原因是:
View
分辨率查找比编写View解析服务要快。 WPF
解析程序来重复工作,然后需要将其插入WPF
运行时。您应该告诉外部源您支持的内容,在这种情况下,始终保持ResourceDictionary
ResourceDictionaries
,这样无论内容/资源如何,您都可以将其合并到运行时WinForms
- 这意味着,您的外部资源需要为您提供ViewModel
控件包装。
作为在使用此模式之前创建了插件框架的人,使用概念性的纯粹MVVM&#34;实现大大简化了事情 - 外部资源为VM提供ResourceDictionary
类和WPF
资源,让View
为您做出cansend
决心
答案 1 :(得分:2)
这是一个非常有趣的场景,对于这些情况,我通常会引入ViewResolverService
或ViewModelResolverService
(或两者)。因此,根据ViewModel
(类,类型或名称)为view
提供的内容可以匹配它们以在ContentControl
中托管它们。或者可以根据ViewModel(类型或字符串名称)为您提供视图的服务。使用这个强大的概念,您可以使用ContentControls和/或DataTemplates,并且您可以完全控制。
我回答了一些解释这些概念的问题:
Register all viewmodel and services in ViewModelLocator
在这里: Get the View & ViewModel from a plugin
更多信息:https://stackoverflow.com/search?q=ViewModelResolver
因此,如果您从鸟瞰图中查看它,您需要将MVVM应用于您的ContentControls与您的视图。 (并且视图也有MVVM自身应用)。
HTH
答案 2 :(得分:0)
使用DataTemplate for ContentControls:
<DataTemplate DataType="{x:Type vm:DataSourceViewModel}">
<view:DataSourceView></view:DataSourceView>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:SelectTemplateViewModel}">
<view:SelectTemplateView></view:SelectTemplateView>
</DataTemplate>
.........
........
<ContentControl Margin="5" HorizontalAlignment="Stretch" Content="{Binding CurrentPage}" Name="ImportControls"></ContentControl>
VM:作为contentcontrol内容的对象类型
查看:是您希望查看特定类型的对象是否设置为ContentControl内容的特定视图
答案 3 :(得分:0)
最终,我采用了第二种方法。我能够解决我的主要问题,即:
但是这个解决方案并没有让我觉得与MVVM应用程序相处得很好,因为它迫使我在我的视图模型中引用了IContentPlugins。
传递那些&#34;插件&#34;进入viewmodels是一个错误,你不应该这样做。您可以而且应该做的是找到一种方法将视图划分为更小的独立段,并以非MVVM方式设置其内容。所以基本上我最终得到了一个视图,它充当容器,看起来像这样:
<UserControl x:Name=this>
<Grid>
<Grid.RowDefinitions>
<RowDefiniton>
<RowDefiniton>
<RowDefiniton>
</Grid.RowDefinition>
<ContentControl Grid.Row="0" Content="{Binding PluginA.View, ElementName=this}"/>
<ContentControl Grid.Row="1" Content="{Binding PluginB.View, ElementName=this}"/>
<ContentControl Grid.Row="2" Content="{Binding PluginC.View, ElementName=this}"/>
</Grid>
</UserControl>
其中PluginA
,PluginB
和PluginC
是代码隐藏中的依赖项属性,由DI容器使用属性注入设置。我对最终结果很满意,它给了我所需的灵活性。
你也可以使用PRISM,大概说的是同样的事情,但是以更一般和灵活的方式。虽然我的应用程序有点过于复杂,所以我决定保持简单。但是如果你想解决类似的问题,你应该试一试。