我的Model是一个通用类,其中包含(例如)Value属性,该属性可以是int,float,string,bool等。因此,此类自然表示为Model<T>之类。为了进行收集,Model<T>实现了IModel接口(interface),尽管IModel本身没有任何内容。

我的ViewModel包含Model<T>的实例,并通过ViewModel的构造函数传入。我仍然想知道ViewModel中的T是什么,因此,当我将Model暴露给View时,我知道Model的嵌入式Value属性的数据类型。 ViewModel的类最终如下所示:

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

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

   public T ModelsValue {get; set; }

}

这可以正常工作,但有一定局限性。因此,现在我需要在IModels中公开具有不同TsView集合,因此我试图将ObservableCollectionnew ViewModel<T>s设置为不断变化的IModels列表。问题是,我不知道如何在运行时从T中的Model<T>中获取IModel,以构造ViewModel<T>(Model<T>)

在VS2010调试器中,我可以将鼠标悬停在任何IModel对象上,例如在运行时查看其完整Model<int>,这样我就知道数据在那里。

有任何想法吗?

最佳答案

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

前言:

您的 View 模型对象可以被弱类型化。给IModel一个属性object Value {get;},并在用于所有ModelViewModel : ViewModel<IModel>对象的IModel中公开它(请参阅下面的ViewModel<T>实现)。如果您具有ObservableCollection<IModel>ICollection<Model<T>>等的各种组合,那么此处显示的框架就是一个救命稻草。如果仍然需要通用 View 模型,则可以派生一个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;
}

用法示例:
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);
    }
}

好处:
  • 使用惰性实现允许在树中进行高效甚至递归的绑定(bind)。
  • 如果基础模型集合实现INotifyCollectionChanged,则 View 模型集合仅实现INotifyCollectionChanged

  • 类概述(链接到github的完整实现):
  • ViewModel<TModel> :我的 View 模型类的基类。公开我在 View 模型的后备代码中使用的Model属性。
  • ObservableViewModelCollection<TViewModel, TModel> :懒惰的(实际上不是当前的,但绝对应该是),可观察到的从模型到 View 模型的映射。实现INotifyCollectionChanged
  • ViewModelCollection<TViewModel, TModel> :从TModel集合到TViewModel集合的懒惰映射。
  • ViewModelCollection :静态助手-当源集合实现ICollection<TViewModel>时,使用ObservableViewModelCollection<TViewModel, TModel>返回INotifyCollectionChanged,否则使用ViewModelCollection<TViewModel, TModel>

  • 一些额外的类型可能对您的 View 模型集合有用:
    ConcatCollection:与ViewModelCollection一样,它包括一个静态助手来自动选择适当的实现。 ConcatCollection通过直接绑定(bind)到源集合来连接集合。
  • ConcatCollection
  • ConcatCollection<T>
  • ObservableConcatCollection<T>

  • 这是一个示例,说明了我如何使用此类型向 View 公开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);
        }
    }
    

    关于c# - 带有MVVM的C#泛型,将T从<T>中拉出,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/2698910/

    10-10 13:31