【问题标题】:Caliburn.Micro / Property not update in IHandle / EventAggregatorCaliburn.Micro / IHandle / EventAggregator 中的属性未更新
【发布时间】:2018-11-02 17:14:49
【问题描述】:

这是步骤。

  1. 触发 EventAggregator 并发送消息。
  2. 在 IHandle 中捕获消息。
  3. 更新一个TextBlock。(根本不更新TextBlock绑定:(

这是一个简单的逻辑。但不适用于 Caliburn.Micro。请检查我的代码。

I make a sample project in GitHub.

您只需单击按钮即可对其进行测试。

这是视图模型

    public void PublishOnBackgroundThread(int flag) {

        Debug.WriteLine($"PublishOnBackgroundThread/{flag}");
        ix++;
        if( flag == 0)
        {
            _eventAggregator.PublishOnBackgroundThread(new HelloMessage(ix.ToString(), false));
        }
        else if( flag == 1)
        {
            _eventAggregator.PublishOnBackgroundThread(new HelloMessage(ix.ToString(), true));
        }
    }

    public void PublishOnCurrentThread(int flag)
    {
        Debug.WriteLine($"PublishOnCurrentThread/{flag}");
        ix++;
        if (flag == 0)
        {
            _eventAggregator.PublishOnCurrentThread(new HelloMessage(ix.ToString(), false));
        }
        else if (flag == 1)
        {
            _eventAggregator.PublishOnCurrentThread(new HelloMessage(ix.ToString(), true));
        }
    }
    public void PublishOnUIThread(int flag)
    {
        Debug.WriteLine($"PublishOnUIThread/{flag}");
        ix++;
        if (flag == 0)
        {
            _eventAggregator.PublishOnUIThread(new HelloMessage(ix.ToString(), false));
        }
        else if (flag == 1)
        {
            _eventAggregator.PublishOnUIThread(new HelloMessage(ix.ToString(), true));
        }
    }
    public void PublishOnUIThreadAsync(int flag)
    {
        Debug.WriteLine($"PublishOnUIThreadAsync/{flag}");
        ix++;
        if (flag == 0)
        {
            _eventAggregator.PublishOnUIThreadAsync(new HelloMessage(ix.ToString(), false));
        }
        else if (flag == 1)
        {
            _eventAggregator.PublishOnUIThreadAsync(new HelloMessage(ix.ToString(), true));
        }
    }

    public void Handle(HelloMessage message)
    {

        Debug.WriteLine($"Handle(HelloMessage message)/{message.UiAsync}/{message.msg}");
        if (message.UiAsync)
        {
            Execute.OnUIThreadAsync(() =>
            {
                _myText = message.msg;
                MyText = _myText;

            });
            /*Execute.OnUIThread(() =>
            {
                _myText = message.msg;
                MyText = _myText;

            });*/
        }
        else
        {
            _myText = message.msg;
            MyText = _myText;
        }
    }

    private int ix = 0;
    private String _myText = "Update Number at Here !";
    public String MyText
    {
        get { return _myText; }
        set
        {
            Debug.WriteLine($"this.Set(ref _myText, value);");
            this.Set(ref _myText, value);
        }
    }

xaml 不存在。

        <StackPanel.Resources>
            <Style TargetType="{x:Type Button}">
                <Setter Property="Margin" Value="5"/>
            </Style>
        </StackPanel.Resources>

        <TextBlock Text="{Binding MyText, Mode=TwoWay}" Margin="50" />
        <Button Content="PublishOnBackgroundThread" cal:Message.Attach="[Event Click]=[Action PublishOnBackgroundThread(0)]"/>
        <Button Content="PublishOnCurrentThread" cal:Message.Attach="[Event Click]=[Action PublishOnCurrentThread(0)]"/>
        <Button Content="PublishOnUIThread" cal:Message.Attach="[Event Click]=[Action PublishOnUIThread(0)]"/>
        <Button Content="PublishOnUIThreadAsync" cal:Message.Attach="[Event Click]=[Action PublishOnUIThreadAsync(0)]"/>


        <Button Content="PublishOnBackgroundThread + Execute.OnUIThreadAsync" cal:Message.Attach="[Event Click]=[Action PublishOnBackgroundThread(1)]"/>
        <Button Content="PublishOnCurrentThread + Execute.OnUIThreadAsync" cal:Message.Attach="[Event Click]=[Action PublishOnCurrentThread(1)]"/>
        <Button Content="PublishOnUIThread + Execute.OnUIThreadAsync" cal:Message.Attach="[Event Click]=[Action PublishOnUIThread(1)]"/>
        <Button Content="PublishOnUIThreadAsync + Execute.OnUIThreadAsync" cal:Message.Attach="[Event Click]=[Action PublishOnUIThreadAsync(1)]"/>

StackOverFlow 网页不喜欢长代码。 然后,我在打字…………

【问题讨论】:

    标签: events caliburn.micro


    【解决方案1】:

    如果你想要一个干净的代码:

    不要初始化私有变量_myText,而是在构造函数中初始化MyText

        private readonly IEventAggregator _eventAggregator;
        public BaseViewModel()
        {
            MyText = "Update Number at Here !";
            _eventAggregator = IoC.Get<IEventAggregator>();
        }
    

    如果你使用依赖注入会更好:

        private readonly IEventAggregator _eventAggregator;
        public BaseViewModel(IEventAggregator _eventAggregator)
        {
            MyText = "Update Number at Here !";
            this._eventAggregator = _eventAggregator;
        }
    

    然后声明属性:

    private String _myText;
    public String MyText
    {
        get { return _myText; }
        set
        {
            Debug.WriteLine($"this.Set(ref _myText, value);");
            this.Set(ref _myText, value); // or
            //_myText = value;
            //NotifyOfPropertyChange(() => MyText);
        }
    }
    

    最后是句柄:

        public void Handle(HelloMessage message)
        {
            Debug.WriteLine($"Handle(HelloMessage message)/{message.UiAsync}/{message.msg}");
            if (message.UiAsync)
            {
                Execute.OnUIThreadAsync(() =>
                {
                    MyText = message.msg;
    
                });
                /*Execute.OnUIThread(() =>
                {
                    _myText = message.msg;
                    MyText = _myText;
    
                });*/
            }
            else
            {
                MyText = message.msg;
            }
        }
    

    不要更新私有变量_myText,只更新公共变量MyText

    每次更新 MyText 变量时,NotifyOfPropertyChange 都会将更新发送到视图。

    使用 this.Set 或者 cmets 中的两行是一样的.. 两者都调用了 caliburn 中的 final 方法:

        /// <summary>
        /// Notifies subscribers of the property change.
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        // Token: 0x060000BF RID: 191 RVA: 0x0000342C File Offset: 0x0000162C
        public virtual void NotifyOfPropertyChange([CallerMemberName] string propertyName = null)
        {
            if (this.IsNotifying && this.PropertyChanged != null)
            {
                this.OnUIThread(delegate
                {
                    this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
                });
            }
        }
    

    【讨论】:

    • 你好 Frenchy ,在我看来。我认为“this.Set(ref _myText, value);”等同于“NotifyOfPropertyChange(() => MyText);”..... 不一样?我应该始终使用两者吗?根据我的经验,有时,UI 只能使用“this.Set”进行更新。然后,我很困惑。请教我更多...
    • 对不起,我在复制/粘贴中出错了,是的代码行 this.Set(ref _myText, value);等于 cmets 中的两行
    • 谢谢。我有另一种经历。通常,"this.Set" 工作得很好,但是如果我们使用 EventAggregator + IHandle,我们必须使用 "NotifyOfPropertyChange(() => MyText);"在 IHandle 中。这是真的 ?我必须在 MyText=NewValue; 之后运行 NotifyOfPropertyChange;你认为 ?你知道原因吗?
    • 我不明白为什么你必须......没有它你的代码是好的(如果你更新属性)。 EventAggregator 用于发送或订阅事件。订阅事件时调用 Ihandle...
    【解决方案2】:

    在您的财产MyText 中,在set 块中写下:

    set {
        Debug.WriteLine($ "this.Set(ref _myText, value);");
        this.Set(ref _myText, value);
        NotifyOfPropertyChange(() => MyText);
    }
    

    Handle 方法中删除所有NotifyOfPropertyChange(() =&gt; MyText);,因为您现在在更改值属性时调用它。

    【讨论】:

    • 请再教我一次。在 IHandle 内部,我们需要调用“NotifyOfPropertyChange”。它工作得很好。但在 IHandle 之外,通常调用“MyText = _myText;”就足够了仅用于更新绑定。为什么我们需要 IHandle 中的 NotifyOfPropertyChange ?我很困惑。我以为 NotifyOfPropertyChange == this.Set。有什么不同吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-15
    • 1970-01-01
    • 1970-01-01
    • 2017-09-01
    • 2012-02-04
    相关资源
    最近更新 更多