wpf Prism 6 with Unity - 解决没有命名约定的视图的视图模型

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/37036930/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 13:47:22  来源:igfitidea点击:

Prism 6 with Unity - resolving view models for views without naming convention

c#wpfmvvmunity-containerprism-6

提问by ?ukasz

I am trying to have view models resolved using DI with Prism 6 and Unity in my WPF app and this works. However I don't know how to tell the framework which view should be merged with which view model.

我正在尝试在我的 WPF 应用程序中使用带有 Prism 6 和 Unity 的 DI 解析视图模型,这有效。但是我不知道如何告诉框架哪个视图应该与哪个视图模型合并。

If I use the convention, i.e. have ViewModels, and Views namespaces, and classes ViewA and ViewAViewModel everything works, however I would like to have more flexibility to name and organize my classes and this is why I want to somehow tell the framework explicitly which view goes with which view model. I tried many things, but nothing really works. Current "solution" makes app run but view model is not set.

如果我使用约定,即有 ViewModels 和 Views 命名空间,以及类 ViewA 和 ViewAViewModel 一切正常,但是我希望有更多的灵活性来命名和组织我的类,这就是为什么我想以某种方式明确地告诉框架哪个视图搭配哪个视图模型。我尝试了很多东西,但没有一个真正有效。当前的“解决方案”使应用程序运行但未设置视图模型。

Here is the code:

这是代码:

ViewA.xaml

视图A.xaml

<UserControl x:Class="WPFDITest.Views.ViewA"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:prism="http://prismlibrary.com/"
             prism:ViewModelLocator.AutoWireViewModel="True"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <StackPanel>
        <TextBlock Text="{Binding ViewAMessage}"/>
        <TextBox Text="{Binding ViewAMessage, UpdateSourceTrigger=PropertyChanged}"/>
    </StackPanel>
</UserControl>

MainWindow.xaml

主窗口.xaml

<UserControl x:Class="WPFDITest.Views.ViewA"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:prism="http://prismlibrary.com/"
             prism:ViewModelLocator.AutoWireViewModel="True"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <StackPanel>
        <TextBlock Text="{Binding ViewAMessage}"/>
        <TextBox Text="{Binding ViewAMessage, UpdateSourceTrigger=PropertyChanged}"/>
    </StackPanel>
</UserControl>

ViewAVM.cs

ViewAVM.cs

public class ViewAVM : BindableBase
{
    private string viewAMessage;

    public ViewAVM(IModelA model)
    {
        viewAMessage = model.HelloMsgA();
    }

    public string ViewAMessage
    {
        get { return viewAMessage; }
        set { SetProperty(ref viewAMessage, value); }
    }
}

Model.cs

模型.cs

public interface IModelA
{
    string HelloMsgA();
}

public class ModelA : IModelA
{
    public string HelloMsgA()
    {
        return "Hello from A!";
    }
}

App.xaml.cs

应用程序.xaml.cs

public partial class App
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        var bootstraper = new Bootstrapper();
        bootstraper.Run();
    }
}

Bootstrapper.cs

引导程序

public class Bootstrapper : UnityBootstrapper
{
    protected override DependencyObject CreateShell()
    {
        return Container.Resolve<MainWindow>();
    }

    protected override void InitializeShell()
    {
        Application.Current.MainWindow.Show();
    }

    protected override void ConfigureContainer()
    {
        base.ConfigureContainer();
        Container.RegisterType<IModelA, ModelA>(new ContainerControlledLifetimeManager());
        Container.RegisterType<object, ViewAVM>("ViewA");
    }

    protected override void ConfigureViewModelLocator()
    {
        ViewModelLocationProvider.SetDefaultViewModelFactory(type => Container.Resolve(type));
    }
}

回答by ?ukasz

After some digging through Prism sources I found out how to do what I want. I can register each view with ViewModelLocationProvider.Registerpassing in a factory method for the view model. I created method that does just that with convenient syntax and uses container to resolve view model for given type:

在对 Prism 资源进行了一些挖掘之后,我发现了如何做我想做的事。我可以ViewModelLocationProvider.Register通过传入视图模型的工厂方法来注册每个视图。我创建了一种方法,它使用方便的语法来实现这一点,并使用容器来解析给定类型的视图模型:

public void BindViewModelToView<TViewModel, TView>()
{
    ViewModelLocationProvider.Register(typeof(TView).ToString(), () => Container.Resolve<TViewModel>());
}

And there is how I use it to bind ViewAVMto ViewAand ViewBboth using same singleton instance.

还有就是我如何使用它来绑定ViewAVMViewAViewB两个使用相同的单一实例。

public class Bootstrapper : UnityBootstrapper
{
    protected override DependencyObject CreateShell()
    {
        return Container.Resolve<MainWindow>();
    }

    protected override void InitializeShell()
    {
        Application.Current.MainWindow.Show();
    }

    protected override void ConfigureContainer()
    {
        base.ConfigureContainer();
        Container.RegisterType<IModelA, ModelA>(new ContainerControlledLifetimeManager());
        Container.RegisterType<ViewAVM>(new ContainerControlledLifetimeManager());
    }

    protected override void ConfigureViewModelLocator()
    {
        BindViewModelToView<ViewAVM, ViewA>();
        BindViewModelToView<ViewAVM, ViewB>();
    }
}

By the way, as far as I can tell by the sources, it is only possible to associate view to view model through with ViewModelLocator by registering factories or by using their or custom convention, don't look for some DI magic.

顺便说一下,据我所知,只有通过注册工厂或使用它们的或自定义约定才能将视图与视图模型与 ViewModelLocator 相关联,不要寻找一些 DI 魔法。

回答by R. Richards

Here is a link to Brian's blog on the ViewModelLocator, and it includes a section (Change those Nasty Conventions) on how to override the conventions if you would like.

这里有一个链接,指向 Brian 在 ViewModelLocator 上的博客,它包含一个部分(更改那些讨厌的约定),关于如何根据需要覆盖约定。

Getting Started with Prism's new ViewModelLocator

Prism 的新 ViewModelLocator 入门

Personally, I set my DataContext in the code behind of the UserControl, in the constructor, after the View gets registered with the container in the Module. Conventions be damned!! :)

就我个人而言,在 View 注册到模块中的容器之后,我在构造函数中 UserControl 后面的代码中设置了我的 DataContext。该死的约定!!:)

public ProductView(ProductViewModel view_model)
{
    InitializeComponent();
    DataContext = view_model;
}