【问题标题】:Setting UserControl ViewModel Property设置 UserControl ViewModel 属性
【发布时间】:2013-09-05 06:59:51
【问题描述】:

全部 -

我在我的 DI 的 WPF 应用程序中使用 Unity(不带棱镜)。我有我的 MainWindow.xaml 和 MainWindowViewModel.cs。我的 Mainwindow.xaml 中有一个用户控件。用户控件有自己的 uc1.xaml 和 uc1viewmodel.cs。 UC1 ViewModel 当前作为 MainWindowViewModel 上的属性公开,因此我可以在用户控件上设置数据上下文(如许多 ppl 推荐的那样)。

我的问题是如何/在哪里可以设置此属性 - 它是在 app.xaml.cs 中还是在 mainwindowviewmodel 的构造函数中。代码片段:

App.xaml.cs

protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        //Step 1 - One Time - Creating an instance of the container
        UnityContainer unity = new UnityContainer();

        //Step 2 - Registering your MainWindowViewModel
        unity.RegisterType<IViewModel, UserControl1ViewModel>();

        //Step 3 - Creating an Instance
        UserControl1ViewModel uc1_mwvm = unity.Resolve<UserControl1ViewModel>();  <-- doesnt help
        MainWindowViewModel mwvm = unity.Resolve<MainWindowViewModel>();

        MainWindow mw = unity.Resolve<MainWindow>();

        mw.Show();
    }

MainWindowViewModel.cs

public class MainWindowViewModel
{
    public IViewModel IVM { get; set; }

    public MainWindowViewModel()
    {
        //IVM = new UserControl1ViewModel(); <-- All I really want is an equivalent but letting Unity do the work. 
    }
}

MainWindow.xaml

<Window x:Class="_05_ViewFist_UC_Unity_Working.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:uc1="clr-namespace:_05_ViewFist_UC_Unity_Working"
     xmlns:uc2="clr-namespace:_05_ViewFist_UC_Unity_Working"
    Title="MainWindow" Height="350" Width="525">
<StackPanel Orientation="Vertical">
    <TextBlock Text="{Binding NNN}" />
    <uc1:UC1 DataContext="{Binding UC1VM}" />
    <uc2:UC2 DataContext="{Binding UC2VM}" />
</StackPanel>
</Window>

UC1

<UserControl x:Class="_05_ViewFist_UC_Unity_Working.UC1"
         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" 
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300" >
<StackPanel Orientation="Horizontal" Background="Red">
    <TextBlock Text="UC1 "  />
    <TextBlock Text="{Binding FirstName}"  />
</StackPanel>
</UserControl>

正如您从代码中看到的 - UC1 的实例是在 xaml (MainWindow.xaml) 中创建的,因此当 MainWindow 实例是在 app.xaml.cs 中创建时 - 它仍然不会创建 UserControl1ViewModel 的实例。

问题又是:不要认为我在 MainwindowViewModel 的构造函数中调用 Unity Resolve 语句是一个好习惯。那是对的吗??

有人可以分享我如何/在哪里可以做到这一点的代码 sn-p 吗?

谢谢

【问题讨论】:

  • 在 MainWindowViewModel 的构造函数中设置属性。不要使用 App.xaml.cs。
  • Ninja - 在这种情况下 - 我不必在此处传递 Unity 的实例(或在此处创建另一个实例)。我记得在某处读到它是单身,但不确定这是否是正确的方法。 UnityContainer unity = new UnityContainer(); IVM = unity.Resolve();尽管正如您所建议的那样,这可行
  • 首先,unity 是用于依赖注入的。如果您不知道那是什么,请远离它。只是不要使用它并在构造函数中设置你的属性。如果您仍想使用 unity,那么您将不得不在 MainWindowViewModel 中的属性上方使用 [Dependency] 之类的属性,以便 unity 知道如何进行注入。
  • Ninja - 我非常了解 DI 是什么,而 Unity 是实现它的方法之一。同意我的属性上方没有 [Dependancy],因为我试图让这里的代码更短。
  • 那么您可能知道,一旦您调用 unity.Resolve(MainWindow),UnityContainer 就会运行它的寄存器并注入您在 MainWindow 中指定的依赖项。如果您在代码中完成了我们看不到的所有正确操作,因为您希望在此处保持简短:) 那么 UnityContainer 将在调用 MainWindow 的构造函数后设置您的属性。而且你不需要自己设置任何东西。顺便说一句,在我的示例中,MainWindow 只是一个示例类。

标签: wpf unity-container


【解决方案1】:

我从 github 下载了您的解决方案并尝试解决您的问题。

您做得很好,只是忘记了一些细节,例如属性属性。

这就是您的 App.cs 文件的外观:

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        //Step 1 - One Time - Creating an instance of the container
        UnityContainer unity = new UnityContainer();

        //Step 2 - Registeration
        unity.RegisterType<IMainWindowViewModel, MainWindowViewModel>();
        unity.RegisterType<IUC1ViewModel, UC1ViewModel>();
        unity.RegisterType<IUC2ViewModel, UC2ViewModel>();


        //// Instance of MainWindowViewModel will be created once you call Resolve MainWindow.


        MainWindow mw = unity.Resolve<MainWindow>();

        mw.Show();
    }

这是我改变的:

public class MainWindowViewModel : IMainWindowViewModel
{
    #region Public Properties

    [Dependency]
    public IUC1ViewModel UC1VM { get; set; }

    [Dependency]
    public IUC2ViewModel UC2VM { get; set; }

    public string NNN { get; set; }

    #endregion

    public MainWindowViewModel()
    {
        NNN = "This value coming from MainWindowViewModel";
    }
}

[Dependency] 是一个属性属性,它告诉 Unity 在哪里注入值。

如果你愿意,我可以将我的代码合并到你在 github 上的 repo。

如果这对您有任何帮助,请告诉我。随意将其标记为答案。

【讨论】:

  • Ninja/Dev - 非常感谢您帮助我完成这项工作。刚刚在我的示例解决方案中尝试过,效果很好。从方法的角度来看,这正是我所寻找的。我知道您之前在 cmets 中提到过 [Dependency] 属性,但直到您向我展示了上面的 sn-p,我才明白。我非常感谢您解决了下载问题并帮助我到达这里。已经将此标记为答案并给你一个upvote :)
  • 顺便说一句 - 这是您的企业吗? - hhogdev.com 无论哪种方式,如果您可以将您的电子邮件地址发送给我 - 想通过电子邮件谈论/聊天一些关于 DI/WPF 的事情 - 不是问题 :) 我的电子邮件地址在我的个人资料中列出(它是公开的)
  • 嗨,不,那不是我的企业,呵呵。我们当中很少有人称自己为刺猬。我不知道我们是怎么想出刺猬的,但是有像忍者刺猬,我是开发刺猬,然后是武士刺猬等等。我的邮箱地址是 devhedgehog@gmail.com,无论您遇到什么 wpf 问题,都可以联系我。 :)
  • 哇——我以为你和忍者是一样的:):)。感谢您的电子邮件地址 - 很快就会给您留言
【解决方案2】:

您可以使用服务定位器模式。我将它与 Unity 一起用作 DI。

internal class ServiceLocator
{
    [...]
    public MainViewModel Main { get { return container.Resolve<MainViewModel>(); } }
}

您可以按照您想要的方式实例化您的类(DI 与否,该类初始化 DI 或将其作为参数接收,您可以将 DI 存储在私有静态属性中,如果 DI 为 null 或当应用程序启动时等...)。

在您的 App.xaml 中

<Application.Resources>
        <vm:ServiceLocator x:Key="Locator"/>
    </Application.Resources>

现在,您可以设置数据上下文了

DataContext="{Binding Main, Source={StaticResource Locator}}"

编辑:

我找到了另一种方法(除其他外): 看看this article。在命令中,您可以根据需要解析视图模型。

【讨论】:

  • Daniel - 这里的问题不是实例化我的 MainWindowViewModel 类,而是实例化我的 MWVM 中的 UserControl1ViewModel,以便我可以设置绑定。我相信您提供的解决方案是实例化 MainWindowViewModel 类的模式之一(我已经通过构造函数注入进行)
  • 你的用户控件完全一样。如果你喜欢,我可以重命名它
  • 谢谢 - 让我试着回来。无需重命名:)
  • 看了更多,看到很多文章说不要对 DI 使用定位器模式。这里有一篇著名的文章 - blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern
  • 情况并不完全相同。在这里,我们使用 Service Locator 仅从视图中解析我们的视图模型,并且只解析一次。我们不提供通用方法来在代码中解析我们的类。
猜你喜欢
  • 2015-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-16
  • 2021-02-11
  • 2011-09-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多