我似乎只能从ShellViewModel
处理EventAggregator事件,但我想从LoginViewModel
处理它。
ShellViewModel
将LoginViewModel
构造为其活动项。我还将其设置为从IHandle<AuthenticatedMessage>
继承,作为事件发布工作的测试。它能够处理该事件。为了简洁起见,我没有在代码中显示任何取消订阅事件。
public class ShellViewModel : Conductor<IScreen>.Collection.OneActive, IHandle<AuthenticatedMessage>
{
public ShellViewModel(IEventAggregator eventAggregator, LoginViewModel loginViewModel)
{
_eventAggregator = eventAggregator;
_loginViewModel = loginViewModel;
}
protected override async Task OnActivateAsync(CancellationToken cancellationToken)
{
await base.OnActivateAsync(cancellationToken);
_eventAggregator.SubscribeOnPublishedThread(this);
await ActivateItemAsync(_loginViewModel);
}
public async Task HandleAsync(AuthenticatedMessage authCode, CancellationToken cancellationToken)
{
// this is reached! So the event is publishing successfully.
await Task.CompletedTask;
}
}
LoginViewModel
也订阅了该事件,但它的Handle方法没有被调用。
Login
方法负责创建发布事件的LoginWindowViewModel
窗口(如下所示(。
public class LoginViewModel : Screen, IHandle<AuthenticatedMessage>
{
private IEventAggregator _eventAggregator;
private readonly IWindowManager _windowManager;
private readonly ILoginWindowViewModelFactory _LoginWindowViewModelFactory;
public LoginViewModel(IEventAggregator eventAggregator,
IWindowManager windowManager,
ILoginWindowViewModelFactory loginWindowViewModelFactory)
{
_eventAggregator = eventAggregator;
_windowManager = windowManager;
_LoginWindowViewModelFactory = loginWindowViewModelFactory;
}
protected override async Task OnActivateAsync(CancellationToken cancellationToken)
{
await base.OnActivateAsync(cancellationToken);
_eventAggregator.SubscribeOnPublishedThread(this);
}
// This is bound to a button click event. It creates a window.
public async void Login()
{
Uri loginUri = new Uri(_api.BaseLoginUrl);
await _windowManager.ShowWindowAsync(
_ndLoginWindowViewModelFactory.Create(loginUri, _eventAggregator));
}
public async Task HandleAsync(AuthenticatedMessage authCode, CancellationToken cancellationToken)
{
// why is this is never reached?
await Task.CompletedTask;
}
}
发布AuthenticatedMessage
事件的LoginWindowViewModel
:
public class LoginWindowViewModel : Screen
{
private readonly IEventAggregator _eventAggregator;
private readonly Uri _initialUri;
public NDLoginWindowViewModel(Uri initialUri, IEventAggregator eventAggregator)
{
_initialUri = initialUri;
_eventAggregator = eventAggregator;
}
// bound to the WebView2 (browser control) event
public async void NavigationStarting(object sender, CoreWebView2NavigationStartingEventArgs e)
{
string authCode = HttpUtility.ParseQueryString(new Uri(e.Uri).Query).Get("code");
// Publish event here. LoginViewModel should handle this, but currently only ShellViewModel can.
await _eventAggregator.PublishOnUIThreadAsync(new AuthenticatedMessage(authCode));
}
}
}
我在将eventAggregator.SubscribeOnPublishedThread(this);
移动到LoginViewModel
构造函数而不是OnActivateAsync()
方法后解决了这个问题。
从这里:
protected override async Task OnActivateAsync(CancellationToken cancellationToken)
{
await base.OnActivateAsync(cancellationToken);
_eventAggregator.SubscribeOnPublishedThread(this);
}
收件人:
public LoginViewModel(IEventAggregator eventAggregator,
IWindowManager windowManager,
ILoginWindowViewModelFactory loginWindowViewModelFactory)
{
_eventAggregator = eventAggregator;
_windowManager = windowManager;
_LoginWindowViewModelFactory = loginWindowViewModelFactory;
_eventAggregator.SubscribeOnPublishedThread(this);
}
编辑:
当视图第一次在ShellViewModel
中创建时,OnActivateAsync
方法没有被调用,因为它是我的根Screen和Conductor。因此,认购从未发生。
public class ShellViewModel : Conductor<IScreen>.Collection.OneActive
{
...
protected override async Task OnActivateAsync(CancellationToken cancellationToken)
{
await base.OnActivateAsync(cancellationToken);
await ActivateItemAsync(_loginViewModel);
// IsActive = false here, therefore the child Screen `_loginViewModel`
// is also not active. Result is that OnActivateAsync
// in this view model does not get called.
}
}
它直接关系到这个问题和答案。
这就解释了为什么把它移到构造函数中就解决了这个问题。
最终的解决方案是在Constructor和OnActivateAsync
方法中都添加_eventAggregator.SubscribeOnPublishedThread(this);
。这允许我在离开此视图模型并返回后重新订阅该活动。