【问题标题】:Why isn't OnActivate being called?为什么不调用 OnActivate?
【发布时间】:2016-10-27 10:01:06
【问题描述】:

我在这里问这个问题是因为我试图弄清楚这一点不知所措。我已经搜索过,所有出现的都是有意义的,但也不适用于我的情况。

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

这只发生在我第一次从指挥部呼叫ActivateItem 时,所有其他呼叫都会正确呼叫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;
        }
    }
}

子屏幕

[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; }
}

更新

我下载了 Caliburn Micro 源代码,这样我就可以进入 ActivateItem 函数并查看发生了什么。出于某种原因,当我第一次从 Conductor 调用 ActivateItem 时,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);
}

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

那么,知道了这一点,我只是简单地实现了这个错误并且指挥者不能/不应该是根视图吗?我是否需要有第二个子视图,即指挥(这似乎有点多)?

【问题讨论】:

    标签: wpf caliburn.micro


    【解决方案1】:

    我想通了,基本上是我没有想到。在导体/根视图的构造函数中激活视图不能正常工作,因为它还没有被激活。 IsActive 在调用指挥者/根视图的 OnActivate 之前不会设置为 true。

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

    故事的寓意是,当指挥者是根视图时,不要在指挥者的构造函数中调用ActivateItem

    【讨论】:

    • 我也为此苦苦挣扎,直到找到您的答案。那是上周。今天我正在研究其他东西,发现caliburnmicro.com/documentation/composition 的文档中特别提到了这种行为: > 如果您在导体中激活一个本身不活动的项目,则该项目实际上不会被激活,直到导体被激活。
    猜你喜欢
    • 1970-01-01
    • 2017-09-14
    • 2011-12-14
    • 1970-01-01
    • 2016-07-15
    • 2020-03-28
    • 2019-03-18
    • 2011-05-04
    • 2019-11-04
    相关资源
    最近更新 更多