ViewModel 不会处理 EventAggregator 事件

ViewModel won't handle a EventAggregator event

我似乎只能处理来自 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 Window(如下所示)。

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 方法,因为它是我的根屏幕和导体。所以订阅从未发生。

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);。这允许我在离开此视图模型并返回后重新订阅事件。