创建ViewModel时如何将参考引用到类实例



我正在开发一个包含主视图和5个用户控件的程序。我创建了XAML并创建了一个视图模型,以坐在每个视图也被绑定的视图后面。

我有一个主要的Program类,我想还有其他一些类,例如producttestTool等。

当应用程序启动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

相关内容

  • 没有找到相关文章

最新更新