我正在开发一个包含主视图和5个用户控件的程序。我创建了XAML并创建了一个视图模型,以坐在每个视图也被绑定的视图后面。
我有一个主要的Program
类,我想还有其他一些类,例如product
,testTool
等。
当应用程序启动i加载mainWindow
时,将创建mainWindowViewModel
,然后创建Program
类。
当用户按下按钮时,我希望mainWindowViewModel
显示userControl1
,但我希望userControl1ViewModel
能够看到Program
类并访问其属性和方法。
我一直在阅读诸如"通过参考将类的实例传递"之类的内容,这很好,但是如果userControl1View
创建userControl1ViewModel
我如何传递对程序开始时创建的'program'类别的参考?
这是依赖注入旨在解决的方法。
首先,如果您正在执行MVVM,则应该能够运行整个应用程序而无需创建任何视图,即仅查看模型。如果您的MainWindow带有Childview(Say),则一般而言,您将与相应的视图模型匹配:
public MainViewModel : ViewModeBase
{
public ChildViewModel MyChild {get; } // gets assigned later
然后在您的XAML中:
<Window ...
<local:ChildView DataContext="{Binding MyChild}" />
有时您需要MyChild显示不同的视图,每种视图都将具有其相应的视图模型,并且您可能需要在运行时更改它。在这种情况下
public class MainViewModel : ViewModelBase
{
private object _MyChild;
public object MyChild
{
get { return this._MyChild; }
set
{
if (this._MyChild != value)
{
this._MyChild = value;
RaisePropertyChanged(() => this.MyChild);
}
}
}
}
然后在您的XAML中您创建一个contentControl:
<Window ...
<ContentControl ="{Binding MyChild}" />
使用此处,您然后在窗口或应用程序资源部分中使用DataTemplate来指定与视图模型匹配的视图:
<DataTemplate DataType="{x:Type vm:FooViewModel}">
<view:FooView />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:BarViewModel}">
<view:BarView />
</DataTemplate>
现在,如果您在MainViewModel中进行类似的事情...
this.MyChild = new FooViewModel();
... contentControl会自动使用类型的Fooview控制。此外,它的DataContext将自动设置为您创建的FooviewModel的实例。然后您像这样重新分配它:
this.MyChild = new BarViewModel();
...然后,泡沫将被barview替换。
因此,随着datatemplating的到位,您必须担心的只是将视图模型的参考传递给彼此,这就是依赖注入的地方。这是一个很大的话题,我建议您去阅读它,但是这个想法您是通过DI框架(而不是new
操作员)创建所有视图模型,然后将其粘合在一起。例如,您的产品可能是管理所有产品的存储库类的一部分,因此您首先声明界面:
public interface IProductRepository
{
Products[] AllProducts();
Product GetProductByName(string name);
... etc ...
您然后创建一个实现此接口的实际类,在设置过程中,您为依赖关系框架提供规则,以便每当任何东西请求IproDuctRepository(使用单个实例,创建一个新的实例等)。然后,每当您的整个应用程序中的任何内容都需要访问产品存储库时,它要做的就是声明具有[Inject]
标签的属性(这是如果您使用Ninject,每个库都有自己的方法):
public class MyClass
{
[Inject]
public IProductRepository ProductRepo {get; set;} // <-- gets injected
现在,当您创建一个类型myClass的实例时,依赖项注入框架将为您创建它,并使用提供的规则自动初始化productrepo。
这是一个非常简单的概述,概述了MVVM中的数据组合和依赖注入的工作,一旦您开始使用它们,您就会想知道如何在没有的情况下进行管理。据我所知,您的问题的主要问题是,您正在尝试让您的视图模型相互交谈。通常,这不是MVVM实施的方式。查看模型通过服务将其注入为一般经验的服务进行通信,他们的工作是作为这些服务与前端GUI元素之间的渠道,而不是彼此之间。
您所说的实际上不是简单的过程,您所说的是架构,以获取您期望的参考文献。这可以解决多种方法,因此我将在下面抛出一个相当不合理但非常快的示例。架构问题正在与// HACK:
S
通常,您希望这些模型来自中心位置,例如数据库备份,该模型控制着交接适当的实例。
public abstract class Model
{
// HACK: Don't bother wiring up OnPropertyChanged here, since we don't expect ID to get updated that often, but need a public setter for the Provider
Guid ID { get; set; }
}
// HACK: While using a generic here makes for readable code, it may become problematic if you want to inherit your models
public class ModelProvider<TModelType> where TModelType : Model, new()
{
// HACK: Use better dependency injection than this
private static ModelProvider<TModelType> _instance = new ModelProvider<TModelType>();
public static ModelProvider<TModelType> Instance => _instance;
private ModelProvider() { }
// TODO: Make this into a dictionary of WeakReferences so that you're not holding stale data in memory
ConcurrentDictionary<Guid, TModelType> LoadedModels = new Dictionary<Guid, TModelType>();
private TModelType GenerateModel(Guid id) => new TModelType { ID = id };
private TModelType LoadKnownModel(Guid id)
{
throw new NotImplementedException("Implement a data store to get known models");
}
public TModelType GetNew() => LoadedModels.AddOrUpdate(Guid.NewGuid(). GenerateModel);
public TModelType GetById(Guid id) => LoadedModels.GetOrAdd(id, LoadKnownModel);
}
然后您的ViewModels可以访问
ModelProvider<Product>.Instance.GetById(WellKnownGuid);
用于测试,WellKnownGuid
也可能是程序中的静态ID