我有一个DropDownView
,其中包含DropDownList,如下所示
<ComboBox Grid.Column="1" ItemsSource="{Binding Path=MyList}"
SelectedItem="{Binding Path=Item}" Height="30"/>
DropDownViewModel
有2个属性如下
private ObservableCollection<string> _myList;
public ObservableCollection<string> MyList {
get { return _myList; }
set {
if (_myList == value)
return;
_myList = value;
RaisePropertyChanged("MyList");
}
}
private string _item;
public string Item {
get { return _item; }
set {
if (_item == value)
return;
_item = value;
Messenger.Default.Send(_item); //line1
RaisePropertyChanged("Item");
}
}
现在,我有多个ViewModel,它创建了这个DropdownViewModel
的多个实例,如下所示。每个ViewModel都属于一个单独的View,并且不会互连。 (为简单起见,只考虑创建2个视图模型。)
ViewModel1
public class ViewModel1
{
private readonly DropDownViewModel _ddVM1;
public ViewModel1(){
_ddVM1 = new DropDownViewModel();
Messenger.Default.Register<string>(this, this.GetItem1);
}
private void string GetItem1(string obj){
//perform some function
}
}
ViewModel2
public class ViewModel2
{
private readonly DropDownViewModel _ddVM2;
public ViewModel2(){
_ddVM2 = new DropDownViewModel();
Messenger.Default.Register<string>(this, this.GetItem2);
}
void string GetItem2(string obj){
//perform some function
}
}
现在,当我运行应用程序并从任何一个View的DropDownList
中选择一个值时,始终会调用第一个注册函数(在本例中为GetItem1
)。我只在一个Messenger.Default.Register
中测试了只有一个ViewModel
的代码,应用运行正常。我还测试了代码是否正在创建DropDownView
和DropDownViewModel
的多个实例。那个地区似乎也没有问题。
我不明白为什么在多个ViewModel的情况下出现这种情况,因为每个ViewModel
都有自己的DropDownView
和DropDownViewModel
实例。那么内部究竟发生了什么?当创建多个line1
实例时,为什么应用程序在DropDownViewModel
上以奇怪的方式运行?如何解决这个问题?
答案 0 :(得分:1)
在我看来,问题不是与MVVM相关的WPF,而是与此代码相关:
Messenger.Default.Send(_item); //line1
问题是Messenger.Default看起来像一个静态类,这个静态默认信使不会改变。这是对的吗?我无法在你的机器上进行调试,但这看起来像是一种代码味道。
作为旁注,您应该能够毫无问题地切换和更改视图模型。要解决您的设计问题,请在视图模型中添加您的信使实例,这样您就不会拥有共享的全局状态。
&#34;为什么在创建了多个DropDownViewModel实例时应用程序冻结在第1行?&#34;
很可能与WPF代码无关,但与Messenger.Default.Send方法代码无关。
对于你的binging代码,你可以不用编写:&#34; Path&#34;只是:
<ComboBox Grid.Column="1" ItemsSource="{Binding MyList}"
SelectedItem="{Binding Item}" Height="30"/>
它应该适用于我所知道的所有情况。
答案 1 :(得分:0)
我想这是你正在使用的MVVMLight。 Messenger知道哪些收件人发送邮件的定义因素是TMessage
,邮件的类型:
public virtual void Register<TMessage>(object recipient, Action<TMessage> action)
所以用你的行
Messenger.Default.Register<string>(this, this.GetItem1);
ViewModel现在将收到任何类型为string的消息。发送字符串类型消息时,将执行这两种方法(GetItem1
和GetItem2
)。
正常情况是每个Message都有一个复杂的类型,所以你可以使用类似的东西,DropDownId镜像你附加到每个DropDownViewModel的唯一标识符。
public class DropDownSelectedItemMessage
{
public string DropDownId { get; set; }
public string SelectedItem { get; set; }
}
然后你就像这样注册
Messenger.Default.Register<DropDownSelectedItemMessage>(this, this.GetItem1);
发送消息
Messenger.Default.Send(new DropDownSelectedItemMessage() { DropDownId = _id, SelectedItem = _item });
并在消息处理程序中,您比较ID:
private void string GetItem1(DropDownSelectedItemMessage message)
{
if (message.DropDownId == _ddVM1.Id)
{
//perform some function
}
}
然而,我的两分钱:忘掉DropDownViewModel(在你的实际ViewModel上保留SelectedItem和ItemsSource属性),完全不使用Mediator模式。引入实现和处理INotifyPropertyChanged的基类,以便您可以再次在一行上写入属性。 Here我使用的是什么。