【发布时间】:2016-03-07 09:44:43
【问题描述】:
在我的 Prism 6 WPF MVVM 模块化应用程序(使用 Unity DI)中,我想使用松散耦合事件在模块之间进行通信 - 一个模块是发布者,其他模块是订阅者。在 AuthorizationViewModel 类的发布者方面,我特别有以下方法:
public class AuthorizationViewModel : BindableBase
{
. . . . .
// This method is called from the command method when user clicks button in the view.
private void authenticateUser(string userName, string userPassword, Action<UserAuthorizationLevel> successCallback, Action<string> failureCallback)
{
Task task = Task.Run(() =>
this.getUsers((users) =>
{
// Get authenticated user information.
var userAuthenticated = GetUserByNameAndPassword(userName, userPassword, users);
// Call method publishing loosely coupled event if the user exists. Else display the error message.
if (userAuthenticated != null)
successCallback(userAuthenticated.AuthorizationLevel);
else
failureCallback("Authentification failed.");
}));
}
. . . . .
}
下面是 AuthorizationViewModel 类中的 successCalback 定义:
private void successCalback(UserAuthorizationLevel authorizationLevel)
{
// Publish loosely coupled event.
this._eventAggregator.GetEvent<UserAuthorizationLevelDeterminedEvent>().Publish(authorizationLevel);
}
这里的UserAuthorizationLevel 是在我的应用程序解决方案的一个公共位置定义的枚举类型,我不在这里显示它。 UserAuthorizationLevelDeterminedEvent 是在我的应用程序解决方案的公共位置也定义的事件类型。下面我展示一下:
public class UserAuthorizationLevelDeterminedEvent : PubSubEvent<UserAuthorizationLevel>
{
}
successCalback 方法在必要时运行及其代码行
this._eventAggregator.GetEvent<UserAuthorizationLevelDeterminedEvent>().Publish(authorizationLevel);
执行得很好,所以事件被发布,但订阅者根本不对事件做出反应!订阅者端没有对事件的响应!下面我在订阅者端显示代码:
public class CalibrationNavigationItemViewModel : BindableBase
{
. . . . .
private IEventAggregator _eventAggregator;
. . . . .
// The constructor; creates instance of CalibrationNavigationItemViewModel.
public CalibrationNavigationItemViewModel(IRegionManager regionManager, IEventAggregator eventAggregator)
{
. . . . .
this._eventAggregator = eventAggregator;
this._eventAggregator.GetEvent<UserAuthorizationLevelDeterminedEvent>().Subscribe(this.setRadiobuttonVisualStatus, ThreadOption.BackgroundThread);
. . . . .
}
. . . . .
// Changes visual status of Radiobutton in the View.
private void setRadiobuttonVisualStatus(UserAuthorizationLevel userAuthorizationLevel)
{
if (userAuthorizationLevel == UserAuthorizationLevel.Manufacturer)
this.IsVisible = Visibility.Visible;
else
this.IsVisible = Visibility.Collapsed;
}
// Controls visual status of Radiobutton in the View; the Visibility property
// of Radiobutton in the View is bound to this property.
public Visibility IsVisible
{
get { return this._isVisible; }
set { this.SetProperty(ref this._isVisible, value); }
}
}
(请原谅,我将在这里做一个坏事:我正在控制模块中 Radiobutton 的可见性状态,而不是动态加载模块本身,因为我的应用程序必须有机会在同一个用户中更改用户会话。Prism 模块在初始化后无法卸载。)现在,回到我们的羊身上;我在订阅者端设置了 ThreadOption.BackgroundThread,因为发布者在 TPL 任务中发布事件,而不是在 UI 线程中。我想知道:为什么订阅者对发布的事件完全没有反应?我做错了什么?请帮帮我。
【问题讨论】:
-
您的
CalibrationNavigationItemViewModel在事件触发时还活着吗?单独的订阅不会阻止它被 gc'ed。 -
加载并初始化到触发事件的时刻。
-
然后我看不到任何阻止事件触发的东西。抓住一根稻草,eventtaggregator 是同一个实例吗?在奇怪的情况下,它可能没有注册为单例或使用不同的容器来解析。
-
我在 AuthorizationViewModel 构造函数(发布者端)和 CalibrationNavigationItemViewModel 构造函数(订阅者端)中创建了一个 EventAggregator 实例。在这两个地方初始化值都是构造函数参数。
-
订阅者看起来不错,你没有在那里创建一个事件聚合器,但你得到了它应该被注入的东西。如果发布方以相同的方式进行操作,它应该可以工作。你能在两个构造函数中断点并检查事件聚合器实例是否真的相同吗?