C# 在MVVM中使用一个视图对多个类型执行CRUD
我有以下三种类型的项目:C# 在MVVM中使用一个视图对多个类型执行CRUD,c#,wpf,entity-framework,mvvm,prism,C#,Wpf,Entity Framework,Mvvm,Prism,我有以下三种类型的项目: public class StockItem { public int Id { get; set; } public string Name { get; set; } public decimal UnitPrice { get; set; } } public class LotItem : StockItem { public virtual ICollection<Lot> Lots { get; set; } }
public class StockItem
{
public int Id { get; set; }
public string Name { get; set; }
public decimal UnitPrice { get; set; }
}
public class LotItem : StockItem
{
public virtual ICollection<Lot> Lots { get; set; }
}
public class DetailedItem : StockItem
{
public virtual ICollection<SerialNumber> SerialNumbers { get; set; }
}
公共类库存项目
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共十进制单价{get;set;}
}
公共类项目:库存项目
{
公共虚拟ICollection地段{get;set;}
}
公共类DetailedItem:StockItem
{
公共虚拟ICollection序列号{get;set;}
}
当我在开发一个使用所有MVVM、WPF、PRISM和EF5的应用程序时,我有点迷糊了:首先:我将如何使用一个视图对这些类型执行CRUD,该视图根据类型进行更改(显示/隐藏控件),知道以后可能会有新类型继承自同一类型?
Second:如何将视图绑定到视图模型:
- 为了处理这三种类型,是否需要公开动态属性李>
- MVVM中是否有我缺少的克服这一问题的技巧
首先: 您可以为每种类型创建适当的
DataTempate
s。运行时会根据对象的类型自动选择它们:
<Window.Resources>
<DataTemplate DataType="{x:Type local:LotItem}">
<ItemsControl ItemsSource="{Binding Path=Lots}">
<ItemsControl.ItemTemplate>
<DataTemplate>
...
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
<DataTemplate DataType="{x:Type local:DetailedItem}">
<ItemsControl ItemsSource="{Binding Path=SerialNumbers}">
<ItemsControl.ItemTemplate>
<DataTemplate>
...
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</Window.Resources>
...
...
显然,您必须为每个新类型创建一个新的DataTemplate
秒:
只需将ViewModel属性定义为基本类型。另一种不违反打开/关闭原则的方法是为每种类型的StockItem创建视图模型和视图,然后创建一个类型来整理所有公开的子类型及其对应的视图模型,并提供一个工厂方法,该方法获取StockItem并返回匹配的视图模型 例如,使用IoC容器或MEF就很容易做到这一点 更新 作为使用MEF的快速示例:
public class StockItemEditViewModelFactory : IPartImportsSatisfiedNotification
{
private Dictionary<Type, IStockItemEditViewModelResolver> resolvers;
[ImportMany(IStockItemEditViewModelResolver)]
private IEnumerable<IStockItemEditViewModelResolver> importedResolvers;
public void OnImportsSatisfied()
{
// Build dictionary of StockItem -> StockItemEditViewModel
// Do error handling if no imported resolvers or duplicate types
resolvers = new Dictionary<Type, IStockItemEditViewModelResolver>
foreach(var importedResolver in importedResolvers)
{
resolvers.Add(importedResolver.StockItemType, importedResolver);
}
}
public IStockItemEditViewModel Create(StockItem stockItem)
{
// Find the appropriate resolver based on stockItem.GetType(), handle errors
var type = stockItem.GetType();
var entry = this.resolvers.FirstOrDefault(kv => kv.Key == type);
var resolver = entry.Value;
return resolver.CreateEditViewModel(stockItem);
}
}
[InheritedExport]
public interface IStockItemEditViewModelResolver
{
Type StockItemType { get; }
IStockItemEditViewModel CreateEditViewModel(StockItem stockItem);
}
public class LotItemEditViewModelResolver : IStockItemEditViewModelResolver
{
Type StockItemType { get { return typeof(LotItem); } }
IStockItemEditViewModel CreateEditViewModel(StockItem stockItem)
{
return new LotItemEditViewModel(stockItem);
}
}
public class MainViewModel
{
public IStockItemEditViewModel ActiveItem { get; private set; }
public MainViewModel(StockItemEditViewModelFactory editViewModelfactory)
{
StockItem stockItem = new LotItem();
this.ActiveItem = editViewModelFactory.Create(myStockItem);
}
}
公共类StockItemEditViewModelFactory:iPartimportsAssetFiedNotification
{
专用字典解析器;
[导入名称(IStockItemEditViewModelResolver)]
私有IEnumerable导入解析器;
公共无效OnImportsAssetized()
{
//构建StockItem的字典->StockItemEditViewModel
//如果没有导入解析程序或重复类型,请执行错误处理
解析程序=新字典
foreach(导入解析程序中的var导入解析程序)
{
添加(importedResolver.StockItemType,importedResolver);
}
}
公共IStockItemEditViewModel创建(StockItem StockItem)
{
//根据stockItem.GetType()查找相应的解析程序,并处理错误
var type=stockItem.GetType();
var条目=this.resolvers.FirstOrDefault(kv=>kv.Key==type);
var解析器=entry.Value;
返回resolver.CreateEditViewModel(stockItem);
}
}
[继承导出]
公共接口IStockItemEditViewModelResolver
{
类型StockItemType{get;}
IStockItemEditViewModel CreateEditViewModel(StockItem StockItem);
}
公共类LotItemEditViewModelResolver:IStockItemEditViewModelResolver
{
类型StockItemType{get{return typeof(LotItem);}
IStockItemEditViewModel CreateEditViewModel(StockItem StockItem)
{
返回新的LotItemEditViewModel(库存项);
}
}
公共类主视图模型
{
public IStockItemEditViewModel ActiveItem{get;private set;}
公共主视图模型(StockItemEditViewModelFactory editViewModelfactory)
{
StockItem StockItem=新的LotItem();
this.ActiveItem=editViewModelFactory.Create(myStockItem);
}
}
这是未经测试的,但它向您展示了一般方法。您可以使用泛型使其更整洁
如果您想使用Unity而不是MEF,那么概念将是相同的,但是您需要注册IStockItemEditViewModelResolver的每个实现(或者使用Unity扩展并使用约定),然后您的工厂将需要对容器的引用,以便它可以执行ResolveAll(请参阅).您能否提供一个用于管理StockItem类型->viewModel的类型的小示例?我使用Unity作为IoC容器。这是一个很好的方法,我希望我能重构视图!看来我什么都得不到。谢谢,我会认为这是最适合我的情况。虽然我还没有实现它。我是否需要为超级类构建一个根用户界面,然后将这些数据模板添加为子视图,或者只使用一个主视图,复制数据模板并根据类型进行自定义?@HichemC老实说,我对大型WPF应用程序没有太多经验,但我建议使用单个视图。实际上,我想这取决于你的真实情况。