WPF UI在传入WCF消息后未更新
本文关键字:消息 更新 WCF UI WPF | 更新日期: 2023-09-27 18:26:55
我有一个MVVM应用程序,我的ViewModel PingerViewModel
在其中处理传入的WCF Ping()
消息。处理这样的消息发生在Scheduler.Default
的线程池的线程上。从语义上讲,传入的WCF消息更改绑定属性CanPing
,并引发所述属性的PropertyChanged事件。
但我的UI在收到一些UI事件之前不会更新,例如聚焦/单击窗口等。
如何在事件启动后立即更新
我已尝试引发PropertyChanged事件。。。
- 在应用程序的调度器上
- 使用SynchronizationContext
没有任何运气。
我还验证了绑定属性确实设置为正确的值,并且确实有一个侦听器在使用我的PropertyChanged事件。
以下是一些代码(github上的完整代码):
我的视图的MainWindow.xaml:
的一部分值得注意的是,绑定的Command
实际上并没有在生成传入的WCF消息中发挥作用。
<Button Content="Ping" Height="23" HorizontalAlignment="Left" Margin="10,10,0,0" Name="PingBtn" VerticalAlignment="Top" Width="75" AutomationProperties.AutomationId="Ping"
IsEnabled="{Binding CanPing}"
Command="{Binding PingCommand}" />
我的部分视图MainWindow.xaml.cs
public MainWindow()
{
DataContext = new PingerViewModel();
InitializeComponent();
}
我的ViewModel 的一部分
public class PingerViewModel : INotifyPropertyChanged
public PingerViewModel()
{
Pinger = new Pinger(true);
PingCommand = new PingerPingCommand(this);
//...
}
public bool CanPing
{
get
{
if (Pinger == null) return false;
return Pinger.CanPing;
}
}
public void Ping()
{
_pingClient.Channel.Ping();
Pinger.CanPing = false;
OnPropertyChanged("CanPing");
}
protected virtual void OnPong(PongEventArgs e)
{
Pinger.CanPing = true;
OnPropertyChanged("CanPing");
}
public Pinger Pinger { get; private set; }
public ICommand PingCommand { get; private set; }
//...
}
我认为您需要从按钮中删除IsEnabled="{Binding CanPing}"。
绑定到命令就足够了,因为ICommand对象包含CanExecute和CanExecuteChanged事件处理程序。
我会在Command类中创建一个CanExecute布尔值,并在该类上实现INotifyPropertyChanged。类似这样的东西:
public class PingCommand : ICommand, INotifyPropertyChanged
{
private bool _canExecute;
public bool CanExecute1
{
get { return _canExecute; }
set
{
if (value.Equals(_canExecute)) return;
_canExecute = value;
CanExecuteChanged.Invoke(null, null);
OnPropertyChanged("CanExecute1");
}
}
public void Execute(object parameter)
{
//whatever
}
public bool CanExecute(object parameter)
{
return _canExecute;
}
public event EventHandler CanExecuteChanged;
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
然后,在ViewModel中的Ping/Pong方法上,在Command:中更新此属性
public void Ping()
{
_pingClient.Channel.Ping();
Pinger.CanPing = false;
PingCommand.CanExecute1 = false;
OnPropertyChanged("CanPing");
}
protected virtual void OnPong(PongEventArgs e)
{
Pinger.CanPing = true;
PingCommand.CanExecute1 = true;
OnPropertyChanged("CanPing");
}
如果您的CanPing属性和PingCommand的CanExecute方法都返回TRUE,那么它应该可以工作。
有时Delegate/RerelayCommand实现提供了调用RaiseCanExecuteChanged()的可能性-如果上面的语句对两者都为true并且其不起作用,请尝试此操作
顺便说一句,这是在RaiseCanExecuteChanged()中调用的
CommandManagerHelper.CallWeakReferenceHandlers(_canExecuteChangedHandlers);
您可以使用上述属性的RaiseCanExecuteChanged()
方法进行更新
例如:
this.PingCommand.RaiseCanExecuteChanged();
试试这个,我希望它能解决你的问题。