Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/290.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在MVVM中使用一个视图对多个类型执行CRUD_C#_Wpf_Entity Framework_Mvvm_Prism - Fatal编程技术网

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应用程序没有太多经验,但我建议使用单个视图。实际上,我想这取决于你的真实情况。