【问题标题】:MVVM : how to pass parameter to ViewModel's constructorMVVM:如何将参数传递给 ViewModel 的构造函数
【发布时间】:2011-05-06 13:03:05
【问题描述】:

我正在使用 L. Bugnion 的 MVVM Light Framework。
将客户 ID 等参数传递给 ViewModel 的构造函数有哪些推荐的方法?

编辑: 每个 ViewModel 我需要的参数不是跨模型共享的。它是每个视图模型实例所独有的。

【问题讨论】:

    标签: silverlight mvvm viewmodel mvvm-light service-locator


    【解决方案1】:
    //Create a container class to pass via messenger service
        public class CarSelectedArgs
        {
          #region Declarations
    
          public Car Car { get; set; }
    
          #endregion
    
          #region Constructor
    
          public CarSelectedArgs(Car car)
          {
            Car = car;
          }
    
          #endregion
        }
    
    
        //example of view model sending message.
        public class SendingViewModel : ViewModelBase
        {
          private Car _car;
          public Car SelectedCar
          {
            get { return _car; }
            set
            {
              _car = value;
              if (value != null)
              {
                //messenger will notify all classes that have registered for a message of this type
                Messenger.Default.Send(new CarSelectedArgs(value));
              }
            }
          }
        }
    
    
        //Example of ViewModel registering to recieve a message
        public class SampleViewModel : ViewModelBase
        {
          #region Constructor
    
          public SampleViewModel()
          {
            Messenger.Default.Register<CarSelectedArgs>(this, OnCarSelected);
          }
          #endregion
    
          #region LocalMethods
    
          void OnCarSelected(CarSelectedArgs e)
          {
    
            var NewCar = e.Car;
          }
    
          #endregion
        }
    

    【讨论】:

      【解决方案2】:

      对我来说,使用 MVVM Light 的全部意义在于避免将任何东西注入到视图模型的构造函数中。 MVVM Light 提供了一个消息传递工具,允许您将参数发送到在视图模型内部注册的侦听器。

      例如,这是我使用 VSTO 和 WPF 的 WordWalkingStick 项目中的视图模型:

      using System;
      using System.Xml.Linq;
      using GalaSoft.MvvmLight.Messaging;
      
      namespace Songhay.Wpf.WordWalkingStick.ViewModels
      {
          using Songhay.Office2010.Word;
          using Songhay.OpenXml;
          using Songhay.OpenXml.Models;
          using Songhay.Wpf.Mvvm;
          using Songhay.Wpf.Mvvm.ViewModels;
      
          /// <summary>
          /// View Model for the default Client
          /// </summary>
          public class ClientViewModel : ViewModelBase
          {
              /// <summary>
              /// Initializes a new instance of the <see cref="ClientViewModel"/> class.
              /// </summary>
              public ClientViewModel()
              {
                  if(base.IsInDesignMode)
                  {
                      #region
      
                      this._flatOpcSourceString = ApplicationUtility
                          .LoadResource(
       new Uri("/Songhay.Wpf.WordWalkingStick;component/PackedFiles/FlatOpcToHtml.xml",
                               UriKind.Relative));
                      this._xhtmlSourceString = ApplicationUtility
                          .LoadResource(
       new Uri("/Songhay.Wpf.WordWalkingStick;component/PackedFiles/FlatOpcToHtml.html", 
                               UriKind.Relative));
      
                      #endregion
                  }
                  else
                  {
                      this._flatOpcSourceString = "Loading…";
                      this._xhtmlSourceString = "Loading…";
      
                      //Receive MvvmLight message:
                      Messenger.Default.Register(this, 
                           new Action<GenericMessage<TransformationMessage>>(
                      message =>
                      {
                          var tempDocFolder = 
       Environment.ExpandEnvironmentVariables("%UserProfile%/Desktop/");
                          var inputPath = tempDocFolder + "temp.docx";
                          var outputPath = tempDocFolder + "temp.html";
      
                          var flatOpcDoc = 
                                  XDocument.Parse(message.Content.TransformationResult);
                          OpenXmlUtility.TransformFlatToOpc(flatOpcDoc, inputPath);
      
                          this.FlatOpcSourceString = flatOpcDoc.Root.ToString();
      
                          var settings = new SonghayHtmlConverterSettings()
                          {
                              PageTitle = "My Page Title " + DateTime.Now.ToString("U"),
                              UseEntityMap = false
                          };
      
                          OpenXmlUtility.WriteHtmlFile(inputPath, outputPath, settings);
      
                          var xhtmlDoc = XDocument.Load(outputPath);
                          this.XhtmlSourceString = xhtmlDoc.Root.ToString();
      
                      }));
                  }
              }
      
              /// <summary>
              /// Gets or sets the flat opc source string.
              /// </summary>
              /// <value>The flat opc source string.</value>
              public string FlatOpcSourceString
              {
                  get
                  {
                      return _flatOpcSourceString;
                  }
                  set
                  {
                      _flatOpcSourceString = value;
                      base.RaisePropertyChanged("FlatOpcSourceString");
                  }
              }
      
              /// <summary>
              /// Gets or sets the XHTML source string.
              /// </summary>
              /// <value>The XHTML source string.</value>
              public string XhtmlSourceString
              {
                  get
                  {
                      return _xhtmlSourceString;
                  }
                  set
                  {
                      _xhtmlSourceString = value;
                      base.RaisePropertyChanged("XhtmlSourceString");
                  }
              }
      
              string _flatOpcSourceString;
              string _xhtmlSourceString;
          }
      }
      

      您可以看到 MVVM Light 正在通过其Messenger 向构造函数 (Messenger.Default.Register) 消息传递(不注入)值。

      【讨论】:

      • 我需要将参数发送到 ViewModel 的某个实例,例如客户详细信息 ViewModel 的客户 ID。如何使用 messenger 向特定的 ViewModel 实例发送消息?
      • 我不确定您的确切情况是否可以解决。看起来消息传递可以驱动可以由客户 ID 驱动的视图模型中的内部功能。在我看来,消息传递不必知道特定实例,而是消息调用可以执行的代码。
      • 您应该能够使用令牌进行特定于实例的消息传递,但我个人建议改为注入参数。
      【解决方案3】:

      通过注入,使用接口请求你想要的任何东西。

      如果您有跨模型共享的设置,请实例化一个包含值的单例,并通过 ISomethingProviderISomethingEditor 接口公开它们。

      【讨论】:

      • 感谢您的回复。但是,我需要的每个 ViewModel 的参数并不是模型之间共享的。它是每个视图模型实例所独有的,例如客户详细信息视图模型的客户 ID。
      【解决方案4】:

      这是我的工作:

      ViewModel 需要显示一个车窗,其中汽车 id 作为参数传递:

      ViewModel -> 消息到代码隐藏以查看打开窗口。消息发送 id。

      基本上在代码后面:

      var vm = new viewmodel(id); 变量视图 = 新视图(); view.datacontext = vm; view.show();

      我的视图模型有一个接受 id 的构造函数。

      【讨论】:

      • 我认为如果你要走“轻”路线,这是最好的选择。我建议,除此之外,您仅在设计模式下在 ServiceLocator 中注册该类,以便提供设计时数据。
      【解决方案5】:

      在针对视图模型编写测试的情况下,我有时会创建以 ISomething 作为参数的视图模型构造函数的重载。我让默认构造函数调用第二个构造函数,并使用 ISomething 的默认实现。在测试的情况下,我使用测试实现调用构造函数。我知道这不是最好的方法,因为它会在两个类之间创建依赖关系......但有时你必须采取简单的方式......

      public class SomeViewModel
      {
        private ISomething internalSomething;
      
        public void SomeViewModel():this(new Something()){}
      
        public void SomeViewModel(ISomething something)
        {
          this.internalSomething = something;
        }    
      }
      

      更新

      在 xaml 中创建视图可以是这样的:

      <UserControl xmlns="...."
                   xmlns:Example="SomeNamespace">
      
        <UserControl.DataContext>
           <Example:SomeViewModel />
        </UserControl.DataContext>
      
        <Grid>
           ...
        </Grid>
      </UserControl>
      

      【讨论】:

      • 如何在运行时实例化 ViewModel,并将其与视图配对?
      • 在 MvvmLight 中使用 ModelViewLocator 的情况下,这不需要任何更改。对于非常简单的项目,我有时会在 xaml 中创建视图模型。我会把它添加到帖子中......
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-09-28
      • 2014-10-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多