如何将视图构造函数参数传递给视图模型

7

我有一个视图和视图模型。

MyView
{
  MyView(int id)
  {
    InitializeComponent();
  }
}

 MyViewModel
    {
     private int _id;
      public int ID
       {
        get { return _id; }
        set { _id= value; OnPropertyChanged("_id"); }
       }
    }

我正在将数据上下文设置为XAML:

<Window.DataContext>
        <vm:MyViewModel/>
</Window.DataContext>

点击按钮时,我会显示我的视图为:
Application.Current.Dispatcher.Invoke(() => new MyView(id).Show());

现在,我该如何从MyView(id)将id传递到MyViewModel.ID

4
在代码中设置DataContext而不是XAML:DataContext = new MyViewModel { ID = id }; - Clemens
1
但是我想尽可能地减少代码后台的使用。 - Simsons
2
那不是 MVVM。那是船离教。Codebehind 对于 UI 关注点来说完全没问题。但它不该用于 BI。(刚注意到 - 再次问候!我没有恶意,只是在查看我的 MVVM RSS 源) - user1228
有点离题,但是使用OnPropertyChanged(nameof(MyProperty))如果你以后需要更改任何属性名称,这会让你的生活变得更轻松。 - CodeJunkie
4个回答

7

由于DataContext是在InitializeComponent()调用之后创建的,因此您只需在此之后将其传递给ViewModel:

MyView
{
   MyView(int id)
   {
     InitializeComponent();
     ((MyViewModel)DataContext).ID = id;
   }
 }

5
您可以采用以下解决方案之一: 1)使用“Messenger”模式: 如果您正在使用MVVMLight,您可以使用Messenger模式,具体步骤如下:
在ViewModel中执行以下操作:
MyViewModel
{
     private int _id;
     public int ID
     {
        get { return _id; }
        set { _id= value; OnPropertyChanged("_id"); }
     }

     Public void InitilizeMessenger()
     {
         Messenger.Default.Register(this,"To MyViewModel", (int id) => ID = id);
     }
     public MyViewModel()
     {
        InitilizeMessenger();
     }
}

您需要通过向 Messenger 注册来使 ViewModel 准备好接收消息。
在 View 中进行如下操作:
MyView
{
  MyView(int id)
  {
    InitializeComponent();
    Messenger.Default.Send<int>(id,"To MyViewModel");
  }
}

通过附带“ To MyViewModel”标签发送消息,以便MyViewModel可以捕获它。

2)从视图中访问DataContext:

MyView
{
  MyView(int id)
  {
    InitializeComponent();
    ((MyViewModel)this.DataContext).ID = id;
  }
}

第二种方法更加直接和简单,我提供第一种方法只是为了防止出现更加复杂的情况。

2
首先,OnPropertyChanged("_id")是错误的,因为_id是一个变量,而不是属性。您必须更改为OnPropertyChanged("ID")。您可以在代码后台中分配viewModel。
class MyView
{
      MyView(int id)
        :this(new MyViewModel(id))
      {
      }

      MyView(MyViewModel viewModel)
      {
        InitializeComponent();
        this.DataContext = viewModel;
      }
}

class MyViewModel
{
     private int _id;
     public int ID
     {
        get { return _id; }
        set { _id= value; OnPropertyChanged("ID"); }
     }
     public MyViewModel(int id)
     {
        ID=id;
     }
}

0
根据医生的说法,将变量传递给视图模型是正确的做法,而将视图模型的参数赋值是错误的。让我来评论一下:
我认为这两种方式都是错误的。
首先,因为视图模型在大多数情况下也用作视图(XAML)页面的绑定/数据上下文。这个数据上下文不能有构造函数属性/输入变量,即使设置了默认值,如:public MyviewModel(int? InputVar = null){}
其次,因为在其他视图模型类中给参数赋值会变得非常糟糕,因为这些变量只会被设置一次,并且在视图模型中发生其他事情时会恢复为默认值/空值,即使不重新分配或处理该参数。这经常是我的项目遇到的问题,想要以简单的方式向其他视图模型发送数据,但总是遇到问题。我建议使用事件聚合器:以下是一个示例:
public class EventAggregator
{
    private static readonly EventAggregator instance = new EventAggregator();
    public static EventAggregator Instance => instance;

    private EventAggregator()
    {
    }

    public event EventHandler<ParameterEventArgs> ParameterEvent;

    public void PublishParameter(string parameter)
    {
        ParameterEvent?.Invoke(this, new ParameterEventArgs(parameter));
    }
}

public class ParameterEventArgs : EventArgs
{
    public ParameterEventArgs(string parameter)
    {
        Parameter = parameter;
    }

    public string Parameter
    {
        get;
    }
}

然后在ViewModel A中:
public class ViewModelA
{
    public void SomeMethod()
    {
        string parameterValue = "Hello, ViewModelB!";
        EventAggregator.Instance.PublishParameter(parameterValue);
    }
}

在ViewModel B中:
public class ViewModelB
{
    public ViewModelB()
    {
        EventAggregator.Instance.ParameterEvent += OnParameterReceived;
    }

    private void OnParameterReceived(object sender, ParameterEventArgs e)
    {
        string parameter = e.Parameter;
        // Now you can use the 'parameter' in ViewModelB.
    }
}

请提供一个解决方案,只是在评论中说其他解决方案为什么不正确就可以了。 - amitklein
1
我已经更新了我的帖子,提供了解决方案和示例。至少对我来说这个方法有效。 - jan-peter Poppe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接