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 中得到一个包含不同项目的列表。然后由您决定是否要为每条消息发送显示一个项目(只需添加每条收到的消息)或过滤掉重复的字符串(应用检查)。
我是 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 中得到一个包含不同项目的列表。然后由您决定是否要为每条消息发送显示一个项目(只需添加每条收到的消息)或过滤掉重复的字符串(应用检查)。