如何在不破坏 MVVM 的情况下导入 ViewModel?

发布于 2024-12-08 22:30:36 字数 1113 浏览 1 评论 0原文

[Export]
public sealed class MainViewModel : NotificationObject
{
    [Import]
    public ISomeService MyService { get; private set; }

    ...
}

为了将此类作为 DataContext 注入到我的视图中,我必须将其标记为导出,以便 MEF 在目录中创建它的实例。问题是主窗口需要创建其他窗口并传递命令,我不知道如何在不破坏 MVVM 方法的情况下实现这一点。

我认为 ICommand 将触发 MainViewModel 上的某些内容以生成新的 ViewModel,但在那之后我无法真正强制从 ViewModel 打开新窗口(视图)。另外,我什至无法真正从 MainViewModel 创建新的 ViewModel,因为那样 MEF 将无法真正工作,对吗?

[Export]
public sealed class MainViewModel : NotificationObject
{
    [Import]
    public ISomeService MyService { get; private set; }

    private ObservableCollection<IOrderViewModel> Orders { get; set; }

    public void OpenOrder(int id)
    {
        //Pseudo-code to ensure that duplicate orders are not opened)

        //Else create/open the new order
        var order = new OrderViewModel(id);

        OpenOrders.Add(order);
    }
}

这里有 2 个问题:

  1. 由于我“更新”了 OrderViewModel 服务,因此不会通过 MEF 自动加载。
  2. 我的 ViewModel 层(适当的层)上的这段代码如何创建必要的视图作为新窗口(主窗口的子窗口),然后将此新的 OrderViewModel 链接为 DataContext?
[Export]
public sealed class MainViewModel : NotificationObject
{
    [Import]
    public ISomeService MyService { get; private set; }

    ...
}

In order to INJECT this class as the DataContext to my View, I have to mark it as Export so MEF creates an instance of it in the Catalog. The problem is that the main window needs to create other windows and pass in orders, I'm not sure how to go about that without breaking the MVVM approach.

I figure that an ICommand will trigger something on my MainViewModel to generate a new ViewModel, but then after that happens I can't really force a new Window (view) to open up from the ViewModel. Plus, I can't even really create a new ViewModel from my MainViewModel because then MEF won't really work, right?

[Export]
public sealed class MainViewModel : NotificationObject
{
    [Import]
    public ISomeService MyService { get; private set; }

    private ObservableCollection<IOrderViewModel> Orders { get; set; }

    public void OpenOrder(int id)
    {
        //Pseudo-code to ensure that duplicate orders are not opened)

        //Else create/open the new order
        var order = new OrderViewModel(id);

        OpenOrders.Add(order);
    }
}

2 problems here:

  1. Since I "newed" the OrderViewModel services are not autoloaded via MEF.
  2. How does this code on my ViewModel layer (appropriate layer) create the necessary view as a NEW WINDOW (child of the main window), and then link this new OrderViewModel as the DataContext?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

一江春梦 2024-12-15 22:30:36

避免“新建”OrderViewModel 的方法是使用工厂:

[Export]
public class OrderViewModelFactory
{
    [Import]
    public ISomeDependency ImportedDependency { get; set; }

    public OrderViewModel Create(int id)
    {
        return new OrderViewModel(id, this.ImportedDependency);
    }
}

然后将工厂作为依赖项导入到 MainViewModel 中,MEF 将负责填充所有内容根据需要。

为了解决实例化窗口的问题,我们创建了一个 DialogService ,它执行以下操作:

[Export]
public class DialogService
{
    public bool? ShowDialog(string regionName, object data = null)
    {
        var window = new Window();
        var presenter = new ContentControl();
        presenter.SetProperty(RegionManager.RegionName, regionName);
        window.Content = presenter;
        if (data != null) window.DataContext = data;
        return window.ShowDialog();
    }
}

The way to avoid 'new-ing' the OrderViewModel is to use a factory:

[Export]
public class OrderViewModelFactory
{
    [Import]
    public ISomeDependency ImportedDependency { get; set; }

    public OrderViewModel Create(int id)
    {
        return new OrderViewModel(id, this.ImportedDependency);
    }
}

Then import the factory into your MainViewModel as a dependency and MEF will take care of filling everything in as required.

To get around the problem of instantiating windows, we have created a DialogService that does something like:

[Export]
public class DialogService
{
    public bool? ShowDialog(string regionName, object data = null)
    {
        var window = new Window();
        var presenter = new ContentControl();
        presenter.SetProperty(RegionManager.RegionName, regionName);
        window.Content = presenter;
        if (data != null) window.DataContext = data;
        return window.ShowDialog();
    }
}
枫林﹌晚霞¤ 2024-12-15 22:30:36

我使用的一种技术是我所说的导航服务。请注意,这与 WPF 的内置导航框架不同。您的视图模型可以直接注入一个实例,或者您可以使用 EventAggregator 模式来触发导航请求,然后由导航服务处理该请求。直接注入导航服务意味着它可以与 ViewModelFactories 等其他对象一起注入。不管你如何做,在某些时候你都必须有一个对象知道如何创建由容器正确解析的视图模型。

One technique I use is what I call the Navigation service. Note this is different from WPF's built in navigation framework. Your viewmodel could have an instance injected directly or you can use the EventAggregator pattern to fire a request to navigate that then gets handled by the navigation service. Having the navigation service injected directly means that it can be injected with other objects like ViewModelFactories. Regardless how you do it, at some point you're going to have to have an object that knows how to create the viewmodel properly resolved by your container.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文