使用MVVM的C#泛型,将T拉出<T>

buf*_*erz 1 c# generics wpf mvvm

Model是一个泛型类,它包含一个(例如)Value属性,可以是int,float,string,bool等.所以很自然这个类代表了类似的东西Model<T>.为了集合Model<T>实现接口IModel,尽管IModel它本身没有任何内容.

我的ViewModel包含和实例,Model<T>它通过ViewModel构造函数传递.我仍然想知道TViewModel中的内容,所以当我暴露ModelView我时,我知道了Model埋藏Value属性的数据类型.ViewModel的类最终看起来如下所示:

class ViewModel<T>
{
   private Model<T> _model;

   public ViewModel(Model<T> model) { ....blah.... }

   public T ModelsValue {get; set; }

}
Run Code Online (Sandbox Code Playgroud)

这很好,但是有限.所以现在我需要公开的集合IModels与不同的TsView,所以我想以一个成立ObservableCollectionnew ViewModel<T>s,以一个变化表IModels.问题是,我无法弄清楚如何获得TModel<T>IModel构建ViewModel<T>(Model<T>)在运行时.

在VS2010调试器中,我可以鼠标悬停任何IModel对象并Model<int>在运行时看到它的完整,所以我知道数据在那里.

有任何想法吗?

Sam*_*ell 7

这是我用于视图模型集合的内容:

前言:

您的视图模型对象可以是弱类型的.给出IModel一个属性object Value {get;}并将其暴露在ModelViewModel : ViewModel<IModel>用于所有IModel对象的属性中(参见ViewModel<T>下面的实现).如果你有各种各样的组合ObservableCollection<IModel>,ICollection<Model<T>>这里显示的框架是一个救星.如果您仍然需要通用视图模型,则可以派生出ModelViewModel<T> : ModelViewModel一个Model<T>在其构造函数中使用的模型.创建适当类型的逻辑将转换为传递给ViewModelCollection.Create下面的转换器.请注意,此设计会对性能造成损害.

ModelViewModel CreateModelViewModel(IModel model)
{
    Type viewModelType = typeof(ModelViewModel<>).MakeGenericType(model.Type);
    ModelViewModel viewModel = Activator.CreateInstance(viewModelType, model);
    return viewModel;
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

public class CatalogViewModel : ViewModel<ICatalog>
{
    public CatalogViewModel(ICatalog catalog)
        : base(catalog)
    {
        Func<ICatalogProduct, ProductViewModel> viewModelFactory = CreateProductViewModel;

        this.Products = ViewModelCollection.Create(catalog.Products, viewModelFactory);
    }

    public ICollection<ProductViewModel> Products
    {
        get;
        private set;
    }

    private ProductViewModel CreateProductViewModel(ICatalogProduct product)
    {
        return new ProductViewModel(product, this);
    }
}
Run Code Online (Sandbox Code Playgroud)

优点:

  • 使用延迟实现允许在树中进行有效甚至递归的绑定.
  • 视图模型集合仅INotifyCollectionChanged在底层模型集合实现时实现INotifyCollectionChanged.

类概述(链接到github的完整实现):

一些可能对您的视图模型集合有用的额外类型:

ConcatCollection:与ViewModelCollection一样,它包含一个静态助手,可以自动选择适当的实现.ConcatCollection通过直接绑定到源集合来连接集合.

下面是一个示例,说明我如何使用此类型向Children视图公开属性,同时保持我的可观察集合一直返回到原始源.

public class ProductViewModel : ViewModel<IProduct>
{
    public ProductViewModel(IProduct product)
        : base(product)
    {
        Func<IProduct, ProductViewModel> productViewModelFactory = CreateProductViewModel;
        Func<IRelease, ReleaseViewModel> releaseViewModelFactory = CreateReleaseViewModel;

        this.Products = ViewModelCollection.Create(product.Products, productViewModelFactory);
        this.Releases = ViewModelCollection.Create(product.Releases, releaseViewModelFactory);
        this.Children = ConcatCollection.Create<object>((ICollection)this.Products, (ICollection)this.Releases);
    }

    public IList<ProductViewModel> Products
    {
        get;
        private set;
    }

    public IList<ReleaseViewModel> Releases
    {
        get;
        private set;
    }

    public IEnumerable<object> Children
    {
        get;
        private set;
    }

    private ProductViewModel CreateProductViewModel(IProduct product)
    {
        return new ProductViewModel(product);
    }

    private ReleaseViewModel CreateReleaseViewModel(IRelease release)
    {
        return new ReleaseViewModel(release);
    }
}
Run Code Online (Sandbox Code Playgroud)