Caliburn.Micro / 属性 未在 IHandle / EventAggregator 中更新
Caliburn.Micro / Property not update in IHandle / EventAggregator
这是步骤。
- 触发 EventAggregator 并发送消息。
- 在 IHandle 中捕获消息。
- 更新 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));
});
}
}
这是步骤。
- 触发 EventAggregator 并发送消息。
- 在 IHandle 中捕获消息。
- 更新 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));
});
}
}