为什么 OnActivate 没有被调用?

van*_*ane 4 wpf caliburn.micro

我在这里问这个问题是因为我对试图解决这个问题感到不知所措。我已经搜索过了,所有出现的东西都是有意义的,但也不适合我的情况。

我正在使用WPFMVVMCaliburn.Micro我有一个带有相应视图模型的 shell 窗口,该视图模型是 aConductor<Screen>.Collection.OnceActive和一个继承自 的屏幕Screen。我ActivateItem在 Conductor 的构造函数中调用以显示后续屏幕,它正确显示屏幕,但从未调用 Screen 的覆盖,OnActivate并且屏幕的IsActive属性设置为False

这只发生在我第一次ActivateItem从 Conductor 调用时,所有其他调用都将正确调用OnActivateOnDeactivate

这对我来说毫无意义,我不知道发生了什么。我清理了解决方案,重建,甚至重新启动,但它仍然无法正常工作。下面是代码:

家长指挥

[Export]
public sealed class ShellViewModel : Conductor<Screen>.Collection.OneActive, IHandle<SimpleMessage>
{
    private readonly DashboardViewModel m_Dash;
    private readonly LoginViewModel m_Login;
    private readonly IEventAggregator m_MsgBus;

    [ImportingConstructor]
    public ShellViewModel(DashboardViewModel dash, LoginViewModel login, IEventAggregator msgBus)
    {
        this.m_MsgBus = msgBus;
        this.m_Dash = dash;
        this.m_Login = login;

        this.ActivateItem(this.m_Login);
    }

    protected override void OnActivate()
    {
        this.m_MsgBus.Subscribe(this); //called correctly
    }

    protected override void OnDeactivate(bool close)
    {
        this.m_MsgBus.Unsubscribe(this); //called correctly
    }

    public void Handle(SimpleMessage message)
    {
        switch (message)
        {
            case SimpleMessage.LoginSuccess:
                this.ActivateItem(this.m_Dash);
                break;

            case SimpleMessage.Logout:
                this.ActivateItem(this.m_Login);
                break;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

儿童屏幕

[Export]
public sealed class LoginViewModel : Screen
{
    private readonly IEventAggregator m_MsgBus;

    [ImportingConstructor]
    public LoginViewModel(IEventAggregator msgBus)
    {
        this.m_MsgBus = msgBus;
    }

    protected override void OnActivate()
    {
        //NOT called the first time, but is called every other time
        MessageBox.Show("ACTIVATE TEST");
    }

    protected override void OnDeactivate(bool close)
    {
        //NOT called the first time, but is called every other time
        MessageBox.Show("DEACTIVATE TEST");
    }

    public void CmdLogin(string password)
    {
        this.m_MsgBus.PublishOnUIThread(SimpleMessage.LoginSuccess);
    }

    public string Username { get; set; }

    public string Password { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

更新

我下载了 Caliburn Micro 源代码,这样我就可以进入该ActivateItem函数并查看发生了什么。由于某种原因,当我第一次ActivateItem从 Conductor 调用时,Conductor 的IsActive属性设置为 false,这会导致 Caliburn 跳过调用OnActivate覆盖。我不知道为什么该财产会是假的。

ConductorBaseWithActiveItem.cs

protected virtual void ChangeActiveItem(T newItem, bool closePrevious) {
    ScreenExtensions.TryDeactivate(activeItem, closePrevious);

    newItem = EnsureItem(newItem);

    //Problem is here, IsActive is false the first time around in the conductor
    if(IsActive)
        ScreenExtensions.TryActivate(newItem);

    activeItem = newItem;
    NotifyOfPropertyChange("ActiveItem");
    OnActivationProcessed(activeItem, true);
}
Run Code Online (Sandbox Code Playgroud)

看起来IsActive导体中的原因是错误的,因为我的导体是使用创建的根视图DisplayRootViewFor,并且看起来该函数没有将IsActive属性设置为 true。

那么,知道了这一点,我是否只是简单地实现了这个错误,而 Conductor 不能/不应该是根视图?我是否需要有第二个子视图,即指挥(看起来有点多)?

van*_*ane 5

我想通了,这基本上是我没有想到的。在conductor/root视图的构造函数中激活视图无法正常工作,因为它尚未被激活。在调用IsActiveconductor/root 视图之前不会设置为true 。OnActivate

这在某些时候可能会出现问题,因为即使被调用,导体也不会处于活动状态,OnInitialize并且这意味着是一次性初始化函数并且OnActivate可以被多次调用。就我而言,这会很好,因为我的指挥是根视图,因此OnActivate只会被调用一次。

ActivateItem这个故事的寓意是,当指挥是根视图时,不要调用指挥的构造函数。