Microsoft Prism Event Aggregator发送值或地址

时间:2015-11-16 14:36:19

标签: c# wpf prism

我是Prism的新手,并且遇到了Event Aggregator的问题。我修改了微软给出的HelloWorld示例,以显示我的问题,最后对此进行了描述。

首先,我将一个MyMessage类定义为事件的有效负载,如下所示:

public class MyMessage
{
    public int id { get; set; }
    public string content { get; set; }

    public override string ToString()
    {
        return this.content;
    }
}

其次,我将事件定义如下

public class MessageArrivedEvent : PubSubEvent<MyMessage>
{
}

之后,我向Shell.xaml添加一个按钮,其点击功能如下

private void button_Click(object sender, RoutedEventArgs e)
    { 
        message.content = message.content == "hello1" ? "hello2" : "hello1";

        ServiceLocator.Current.GetInstance<IEventAggregator>()
                .GetEvent<MessageArrivedEvent>()
                .Publish(message);
    }

这里,message是公共部分类Shell:Window类中的一个属性。

此外,我向HelloWorldView添加了一个组合框,并将ItemsSource绑定到其对应的viewmodel。

private ObservableCollection<MyMessage> _comboboxitemsource;

    public ObservableCollection<MyMessage> comboboxitemsource
    {
        get { return this._comboboxitemsource; }
        set
        {
            this._comboboxitemsource = value;
            this.OnPropertyChanged("comboboxitemsource");
        }
    }

我处理事件的方式如下:

public HelloWorldViewModel()
    {
        this.comboboxitemsource = new ObservableCollection<MyMessage>();
        ServiceLocator.Current.GetInstance<IEventAggregator>().GetEvent<MessageArrivedEvent>().Subscribe(this.MessageArrived, ThreadOption.UIThread, false);
    }

    private void MessageArrived(MyMessage message)
    {
        for (int i = 0; i < this.comboboxitemsource.Count; i++)
        {
            if (this.comboboxitemsource[i].id == message.id)
            {
                this.comboboxitemsource[i].content = message.content;
                break;
            }
        }

        if (this.comboboxitemsource.Count == 0)
            this.comboboxitemsource.Add(message);

    }

现在我将Shell部分中的消息内容设置为“hello1”。单击该按钮时,其内容将更改为“hello2”,然后将消息发送到HelloWorldModule。由于此时,在comboboxitemsource中没有元素,该消息将被添加到此itemsource中。再次单击该按钮时,消息的内容将更改为“hello1”,并且消息将发送到模块。问题是在MessageArrived函数中更改消息之前,内容已自动更改为“hello1”。运行MessageArrived后,下拉列表中的内容仍然是“hello2”,而不是“hello1”。

任何人都可以帮忙解释一下这个问题吗?谢谢

1 个答案:

答案 0 :(得分:1)

真正的问题是,您在整个应用程序中使用了单个消息对象,并且您正在更改该单个对象。这基本上就是参考类型的工作原理。

  

引用类型包含指向另一个内存位置的指针   保存数据。参考类型包括以下内容:

     
      
  • 字符串
  •   
  • 所有数组,即使它们的元素是值类型
  •   
  • 类类型,例如Form
  •   
  • 代表
  •   

来源:https://msdn.microsoft.com/en-us/library/t63sy5hs.aspx

回顾一下你实际做的事情:

  • 您创建了一个消息对象(id=1 content="hello1")并将其引用存储在您的Shell上的属性中。
  • 当您点击按钮content="hello2"并使用EventAggregator将消息(参考)发送给模块时。
  • 由于ComboBox为空,请添加此消息。

现在你最终得到了多个指针(一个在你的属性中,一个在你的ObservableCollection中,指向内存中的同一个Message对象。

  • 您再次点击该按钮,然后更新content="hello1"。由于它在任何地方引用了1个对象,因此所有变量都已经看到content="hello1"

请注意,如果没有INotifyPropertyChanged,您在ComboBox的UI上看不到它,但是当您调试代码时,该值已经更改(因为我们仍在讨论相同的单个消息对象) )。

如何解决?

  • 在shell上删除属性,并保留对Message对象的引用,在上面描述的场景中,保留对它的引用没有用处。如果要跟踪是否必须发送hello1或hello2,可以使用简单的布尔值或字符串标记来执行此操作。
  • 通过EventAggregator发送消息时,请始终创建一个新对象,因为它是您要发送的新消息。

这样,您最终会得到ObservableCollection中不同项的列表。然后由您来决定是否要为每个消息发送显示一个项目(只需添加每个传入的消息)或过滤掉重复的字符串(应用检查)。