好的,我正试图搞定MVVM。我有一个应用程序,有多个图像捕获选项。根据模式,图像可以从现有文件加载,也可以从相机捕获。
我正在使用代表图像捕获设备配置的MVVM模式编写页面。
该模型由两个类组成,这两个类公开了符合IImageSource
的公共接口的每个模式的特定(和非公共)值。
两个模型类中的每一个都有一个上下文定义的视图模型:
CameraSourceViewModel
FileSourceViewModel
和两个相应的观点。
CameraSourceView
FileSourceView
模型有一个返回IImageSource的属性。
我目前正在使用第三个视图ImageSourceView
作为页面。我正在处理从模型中获取值的加载事件,然后,根据类型将实例化正确的视图模型和正确的视图,然后添加它作为内容。然而,这似乎违背了MVVM的精神,因为我现在已经在代码中编写了一些决策代码
是否有更优雅/更好的方法来确定应该实例化和使用哪个viewmodel / view?
答案 0 :(得分:3)
实际上,您不需要TemplateSelector,因为两个ViewModel将具有不同的类型。您可以将XAML中的DataTemplates声明为模型类型为key的资源,以便WPF自动选择正确的DataTemplate:
代码示例:
<Page x:Class="Page1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:my="clr-namespace:WpfApplication1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Title="Page1">
<Page.Resources>
<DataTemplate DataType="{x:Type my:CameraSourceViewModel}">
<my:CameraSourceView/>
</DataTemplate>
<DataTemplate DataType="{x:Type my:FileSourceViewModel}">
<my:FileSourceView/>
</DataTemplate>
</Page.Resources>
<Grid>
<ContentControl Content="{Binding ImageSourceViewModel}"/>
</Grid>
</Page>
答案 1 :(得分:1)
您有两个需要决定在运行时使用哪种类型的地方:
在ViewModel级别上只使用ViewModel工厂,因此只需通过EventType / ValueType实例化相应的ViewModel:
private IImageSourceViewModel ProcessEvent(IEvent someEvent)
{
return viewModelFactory.Create(someEvent.Type)
}
然后在View级别上使用DataTemplateSelector接受已绑定的ViewModel实例,然后决定使用哪个View:
MainView XAML:
<ContentControl
Content="{Binding ImageSourceViewModel}"
ContentTemplateSelector =
"{StaticResource ImageSourceViewDataTemplateSelector}">
</ContentControl>
ImageSourceViewDataTemplateSelector:
private sealed class ImageSourceViewDataTemplateSelector: DataTemplateSelector
{
public ImageSourceViewDataTemplateSelector(... dependencies if any...)
{
}
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
DataTemplate dataTemplate = null;
IImageSourceViewModel instance = item as IImageSourceViewModel;
// move out into the constructor
var dataTemplateFactory = new Dictionary<Type, Func<DataTemplate>>
{
{ typeof(ICameraSourceViewModel), (x) => this.Resources["CameraSourceDataTemplate"] as DataTemplate },
{ typeof(IFileSourceViewModel), (x) => this.Resources["FileSourceViewModel"] as DataTemplate }
};
// TODO: handle not supported type case yourself
return dataTemplateFactory[instance.GetType()]();
}
}
答案 2 :(得分:1)
以下是关于你能做什么的一些想法:
拥有ImageSourceViewModel
,即ImageSourceView
视图的ViewModel。这个viewModel的作用是从模型中获取“你的价值”,并将其作为IImageSource
类型的公共属性公开。
然后,在ImageSourceView
视图中,您可以使用模板选择器来更改视图的内容,具体取决于公开的IImageSource
属性的具体类型。
请参阅http://www.codeproject.com/Articles/418250/WPF-Based-Dynamic-DataTemplateSelector