子ViewModel如何提示父ViewModel在Caliburn.Micro中导航?

时间:2019-05-17 00:01:58

标签: c# navigation caliburn.micro

在Caliburn.Micro中,我有一个Shell ViewModel,它具有3个IShell属性,分别对应于关联的View中的3个内容控件。它们是“完整”,“列表”和“详细信息”。 “ Full”位于其他两个上方,并且与宿主Form一样宽。 “列表”位于左侧第一行,而“详细信息”与右侧“列表” 1列在同一行。

应用程序启动时,Login ViewModel绑定到“ Full”,其他两个都没有绑定。屏幕仅显示登录屏幕。用户应登录,完成后,“完整”内容控件应从显示登录ViewModel切换到AccountViewModel。

为此,我需要LoginViewModel告诉ShellViewModel(其父级)导航到AccountViewModel。

我该怎么做?

public class ShellViewModel : Screen
{
    #region Fields

    private string _title = "License Manager";

    private Conductor<IScreen> _fullFrameConductor;
    private Conductor<IScreen> _listFrameConductor;
    private Conductor<IScreen> _detailFrameConductor;

    #endregion

    public ShellViewModel()
    {
        _fullFrameConductor = new Conductor<IScreen>();
        _listFrameConductor = new Conductor<IScreen>();
        _detailFrameConductor = new Conductor<IScreen>();

        FullFrame = Framework.GetContainer().Resolve<LoginViewModel>();            
    }

    #region Properties

    public string Title { get => _title; set => _title = value; }

    public IScreen FullFrame
    {
        get { return _fullFrameConductor.ActiveItem; }
        set {
            _fullFrameConductor.ActivateItem(value);
            NotifyOfPropertyChange(nameof(FullFrame));
        }
    }

    public IScreen ListFrame
    {
        get { return _listFrameConductor.ActiveItem; }
        set {
            _listFrameConductor.ActivateItem(value);
            NotifyOfPropertyChange(nameof(ListFrame));
        }
    }

    public IScreen DetailFrame
    {
        get { return _detailFrameConductor.ActiveItem; }
        set {
            _detailFrameConductor.ActivateItem(value);
            NotifyOfPropertyChange(nameof(DetailFrame));
        }
    }


    #endregion

    #region Commands

    public void ShowProducts()
    {
        ListFrame = Framework.GetContainer().Resolve<ProductListViewModel>();
        DetailFrame = Framework.GetContainer().Resolve<ProductViewModel>();
    }

    public void ShowLicenses()
    {
        ListFrame = Framework.GetContainer().Resolve<LicenseListViewModel>();
        DetailFrame = Framework.GetContainer().Resolve<LicenseViewModel>();
    }


    #endregion
}


public class LicenseViewModel : Screen
{

    public void Login()
    {
        // This should process the login and then tell the Shell it is done
        // then the shell should navigate to the Account ViewModel sharing
        // the user info with the AccountViewModel via a memory cache

        // How do I alert the screen ViewModel causing it to close this viewmodel
        // without causing a threading problem?
    }
}

1 个答案:

答案 0 :(得分:0)

您可以利用Event Aggregator在LoginViewModel和ShellViewModel之间进行通信。您可以在此处阅读有关Event Aggregator的更多信息。

首先,您需要创建一个消息类

public class AuthenticationSuccessMessage
{
    public bool IsValidLogin{get;set;}
}

然后下一步是使用EventAggregator从LicenseViewModel通知ShellViewModel。

private IEventAggregator _eventAggregator;
 public LicenseViewModel (IEventAggregator eventAggregator) 
 {
    _eventAggregator = eventAggregator;
 }

 public void Login()
 {
    _eventAggregator.PublishOnUIThread(new AuthenticationSuccessMessage{IsValidLogin=true});
 }

最后一步是在ShellViewModel中订阅事件。

public class ShellViewModel:Screen, IHandle<AuthenticationSuccessMessage>
{
   private readonly IEventAggregator _eventAggregator;

   public ShellViewModel:Screen(IEventAggregator eventAggregator) {
        _eventAggregator = eventAggregator;
        _eventAggregator.Subscribe(this);
    }
    void Handle<AuthenticationSuccessMessage>(AuthenticationSuccessMessage message)
    {
        if(message.IsValidLogin)
        {
            // Do Task
        }
    }
}

您可以阅读有关事件聚合器here的更多信息。

更新:不要忘记在ShellViewModel中订阅Event Aggregator。