MVVM: как передать параметр в конструктор ViewModel

Я использую LW.BWNNW MVVM Light Framework.
Каковы некоторые из рекомендуемых подходов к передаче параметров, таких как идентификатор клиента, в конструктор ViewModel?

Изменить: Параметр, который мне нужен для каждого ViewModel, не является общим для всех моделей. это нечто уникальное для каждого экземпляра viewmodel.

Ответы

Ответ 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

Запросите все, что хотите, посредством инъекций, используя интерфейсы.

Если у вас есть общие настройки для разных моделей, создайте один синглтон, содержащий значения, и покажите их через интерфейсы ISomethingProvider и ISomethingEditor.

Ответ 3

Для меня весь смысл использования MVVM Light заключается в том, чтобы не вводить ничего в конструктор View Model. MVVM Light предоставляет средство обмена сообщениями, которое позволяет отправлять ваши параметры слушателю, зарегистрированному внутри модели просмотра.

Например, это моя модель просмотра из моего проекта WordWalkingStick с использованием VSTO и WPF:

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.Default.Register) с его Messenger.

Ответ 4

Вот что я делаю:

ViewModel должен показать окно автомобиля с идентификатором автомобиля, переданным как параметр:

ViewModel → message to codebehind для просмотра, чтобы открыть окно. Сообщение отправляет идентификатор.

По существу в коде позади:

var vm = new viewmodel (id); var view = new view(); view.datacontext = vm; view.show();

my viewmodel имеет конструктор, который принимает идентификатор.

Ответ 5

В случае написания тестов против viewmodel я иногда создаю перегрузку конструктора viewmodel, который принимает параметр 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>