我的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
中公开具有不同Ts
的View
集合,因此我试图将ObservableCollection
的new 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);
}
}
好处:
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/