Microsoft Prism 事件聚合器发送值或地址

Microsoft Prism Event Aggregator send value or address

我是 Prism 新手,对事件聚合器有疑问。我修改了微软给的HelloWorld例子来说明我的问题,在最后描述。

首先,我定义了一个 MyMessage class 作为事件的有效负载发送,如下所示:

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);
    }

这里,消息是 属性 in public partial class Shell : Window class.

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

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 个消息对象,而您正在更改该对象。这就是引用类型的基本工作方式。

A reference type contains a pointer to another memory location that holds the data. Reference types include the following:

  • String
  • All arrays, even if their elements are value types
  • Class types, such as Form
  • Delegates

来源: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 上看不到它,但是当您调试代码时,该值已经更改(因为我们仍在谈论相同的 1 个单消息对象)。


如何解决?

  • 将 属性 放在您的 shell 上,保存对 Message 对象的引用,在上述情况下,保存对它的引用是没有用的。如果您想跟踪是否必须发送 hello1 或 hello2,您可以使用简单的布尔值或字符串标志来完成。
  • 通过 EventAggregator 发送消息时,请始终创建一个新对象,因为它是您发送的新消息。

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