3

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

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

这是代码:

ViewA.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>

主窗口.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

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); }
    }
}

模型.cs

public interface IModelA
{
    string HelloMsgA();
}

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

应用程序.xaml.cs

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

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

引导程序.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));
    }
}
4

2 回答 2

4

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

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

还有我如何使用它来绑定ViewAVMViewA使用ViewB相同的单例实例。

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>();
    }
}

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

于 2016-05-05T08:06:11.853 回答
3

这是 Brian 在 ViewModelLocator 上的博客的链接,其中包含一个部分(更改那些讨厌的约定),如果您愿意,如何覆盖约定。

开始使用 Prism 的新 ViewModelLocator

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

public ProductView(ProductViewModel view_model)
{
    InitializeComponent();
    DataContext = view_model;
}
于 2016-05-04T20:28:31.033 回答