我有三种类型的项目如下:
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; }
}
当我开发一个使用MVVM,WPF,PRISM,EF5全部的应用程序时,我有点坚持:
首先:我将如何使用一个根据类型更改(显示/隐藏控件)的视图对这些类型执行CRUD,因为我知道稍后我可能会继续使用新类型类型?
第二:我如何将视图绑定到视图模型:
答案 0 :(得分:1)
<强>首先强>
您可以为每种类型创建适当的DataTempate
。运行时根据对象的类型自动选择它们:
<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属性定义为基本类型。
答案 1 :(得分:1)
另一种不破坏开放/封闭原则的方法是为每种类型的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);
}
}
这是未经测试的,但它向您展示了一般方法。您可以使用泛型来使这更整洁。
如果你想使用Unity而不是MEF,那么概念将是相同的,但你需要注册IStockItemEditViewModelResolver的每个实现(或使用Unity扩展并使用约定),然后你的工厂需要对容器的引用,以便它可以执行ResolveAll(请参阅Unity Resolve Multiple Classes)。