C# 为不同的ViewModel但相同的属性动态显示不同的视图
好的,我正在努力掌握MVVM。我有一个应用程序,它有多个图像捕获选项。根据模式,图像可以从现有文件加载,也可以从相机捕获 我正在使用MVVM模式编写一个页面,该模式表示图像捕获设备的配置 该模型由两个类组成,它们为符合C# 为不同的ViewModel但相同的属性动态显示不同的视图,c#,wpf,mvvm,C#,Wpf,Mvvm,好的,我正在努力掌握MVVM。我有一个应用程序,它有多个图像捕获选项。根据模式,图像可以从现有文件加载,也可以从相机捕获 我正在使用MVVM模式编写一个页面,该模式表示图像捕获设备的配置 该模型由两个类组成,它们为符合IImageSource公共接口的每种模式公开特定(和非公共)值 两个模型类中的每一个都有一个上下文定义的viewmodel: CameraSourceViewModel FileSourceViewModel 以及两种相应的观点 CameraSourceView FileS
IImageSource
公共接口的每种模式公开特定(和非公共)值
两个模型类中的每一个都有一个上下文定义的viewmodel:
CameraSourceViewModel
FileSourceViewModel
CameraSourceView
FileSourceView
ImageSourceView
作为页面。我正在处理从模型中获取值的加载事件,然后,根据类型将实例化正确的viewmodel和与其相关的正确视图,然后将其作为内容添加。然而,这似乎违背了MVVM的精神,因为我现在已经在代码背后编写了一些决策代码
是否有更优雅/更好的方法来确定应该实例化和使用哪个viewmodel/视图?您有两个地方需要决定在运行时使用哪种类型:
private IImageSourceViewModel ProcessEvent(IEEvent someEvent)
{
返回viewModelFactory.Create(someEvent.Type)
}
然后在视图级别上,只需使用DataTemplateSelector,它通过绑定已解析的ViewModel实例接受,然后决定使用哪个视图:
MainViewXAML:
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()]();
}
}
私有密封类ImageSourceViewDataTemplateSelector:DataTemplateSelector
{
公共ImageSourceViewDataTemplateSelector(…依赖项,如果有…)
{
}
公共覆盖数据模板SelectTemplate(对象项,DependencyObject容器)
{
DataTemplate DataTemplate=null;
IImageSourceViewModel实例=项目作为IImageSourceViewModel;
//移入构造函数
var dataTemplateFactory=新字典
{
{typeof(ICameraSourceViewModel),(x)=>this.Resources[“CameraSourceDataTemplate”]as DataTemplate},
{typeof(IFileSourceViewModel),(x)=>this.Resources[“FileSourceViewModel”]作为数据模板}
};
//TODO:自己处理不支持的类型大小写
返回dataTemplateFactory[instance.GetType()]();
}
}
以下是一些您可以做的事情:
拥有一个ImageSourceViewModel
,即ImageSourceView
视图的视图模型。此viewModel的角色是从模型中获取“您的值”,并将其作为类型为IImageSource
的公共属性公开
然后,在ImageSourceView
视图中,您可以使用模板选择器来更改视图的内容,具体取决于公开的IImageSource
属性的具体类型
请参见实际上,您不应该需要TemplateSelector,因为这两个ViewModel将具有不同的类型。您可以将XAML中的数据模板声明为模型类型为键的资源,以便WPF自动选择正确的数据模板:
- 有一个主ViewModel,它公开ImageSourceViewModel属性。此属性将根据需要返回CameraSourceViewModel或FileSourceViewModel
- 在您的页面中,DataContext将是主ViewModel,您将拥有如下XAML:
<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>
我已经尽了最大的努力来破解你想在这里告诉我的东西,但我有点失败了。我对字典里的Func有点小麻烦;IFilter的作用是什么?为什么不在最后一行中传递它的值?很抱歉,花了这么长时间才标记出您的答案,在项目的另一部分被跟踪,只需要回到这里。
<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>