Caliburn.Micro / 属性 未在 IHandle / EventAggregator 中更新

Caliburn.Micro / Property not update in IHandle / EventAggregator

这是步骤。

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

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

I make a sample project in GitHub.

点击按钮即可测试。

这是 ViewModel

    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)]"/>

Whosebug网页不喜欢长代码。 然后,我正在打字.......

在您的 属性 MyText 中,在 set 块中写入:

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

并且在 Handle 方法中删除所有 NotifyOfPropertyChange(() => MyText); 因为当你更改值 属性.

时你现在正在调用它

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

不初始化私有变量_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,只更新 public 变量 MyText

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

使用this.Set 或注释中的两行是相同的.. 他们都调用了 caliburn 中的最终方法:

    /// <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));
            });
        }
    }