C# 另一个线程中的循环ping+;更新用户界面
我正在实现循环ping功能,该功能的输出应反映在UI按钮的启用状态中(即,当ping结果!=成功时,按钮应被禁用)。我将WPF与MVVM模型结合使用,因此我不会与代码中的控件交互,而是使用绑定和通知机制 问题如下:C# 另一个线程中的循环ping+;更新用户界面,c#,.net,wpf,multithreading,C#,.net,Wpf,Multithreading,我正在实现循环ping功能,该功能的输出应反映在UI按钮的启用状态中(即,当ping结果!=成功时,按钮应被禁用)。我将WPF与MVVM模型结合使用,因此我不会与代码中的控件交互,而是使用绑定和通知机制 问题如下: 我正在用网络启动应用程序ok 按钮是灰色的 我单击UI区域中的某个位置,按钮立即处于活动状态 现在我断开网络电缆-按钮保持其状态 我单击UI区域中的某个位置-按钮立即处于非活动状态 等等。因此,存储连接状态的datapoint值的更改不会反映在UI更改中——只有在刷新UI视图时才
- 我正在用网络启动应用程序ok
- 按钮是灰色的
- 我单击UI区域中的某个位置,按钮立即处于活动状态
- 现在我断开网络电缆-按钮保持其状态
- 我单击UI区域中的某个位置-按钮立即处于非活动状态
public sealed class DB
{
Action _update= null;
Ping _ping;
Thread thread;
static bool result;
System.Runtime.CompilerServices.TaskAwaiter<PingReply> _pingAwaiter;
MachineState machineState;
private DB() //Constructor
{
machineState = GlobalData.Instance.gMachineState; //GlobalData is a Singleton
_ping = new Ping();
_update= Update;
thread = new Thread(new ThreadStart(CyclicTest));
thread.Start();
}
private void CyclicTest()
{
while (true)
{
Thread.Sleep(500);
_pingAwaiter = _ping.SendPingAsync(new IPAddress(new byte[] { 10, 10, 1, 11 }), 100).GetAwaiter();
_pingAwaiter.OnCompleted(Update);
}
}
private void UpdateConnectionStatus()
{
if (_pingAwaiter.GetResult().Status = IPStatus.Success)
result = true;
else
result = false;
machineState.DBLinkActive = result;
}
}
下面是ObserveObject抽象类的NotifyPropertyChanged方法:
public abstract class ObservableObject : INotifyPropertyChanged
{
public void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
下面是负责设置按钮启用状态(谓词)的代码
为什么会这样
我已经知道,线程可能是问题所在。如果我将MessageBox放在\u dbLinkActive=value之前在public属性中,我得到了一个接一个的多个MessageBoex,因为它停止了调用线程的执行,并且显示了许多MessageBoex,这证明了引发了许多线程
我还尝试在NotifyPropertyChanged
方法中将Invoke
更改为BeginInvoke
,但结果相同。如果在循环中使用async/await
和await Task.Delay()
,则可以替换所有这些代码。如果异步方法被UI线程调用,在每次wait
之后,您将返回UI线程,允许您修改任何UI元素。多线程肯定不是原因,因为绑定引擎设计为在多线程环境中工作。您需要将视图的代码放在发布按钮周围进行诊断。只有在Ui线程上引发Notify propertychanged时,它才会起作用。看起来您在另一个线程上将其提升到ui。我同意panagiotis Async Wait,任务延迟会更简单。会有用的。嗨,谢谢你的意见。我已经使用了代码,结果发现问题出在绑定到按钮的CanRefreshOrders谓词中。我将按钮的内容连接到同一viewmodel中的ConnectionOnion状态值,它可以工作,即。该按钮根据连接状态更改其文本-但该按钮的启用状态仅在与UI交互后更改。所以现在的问题是刷新按钮谓词,而不是ping。顺便说一句,NotifyPropertyChanged使用Invoke方法,所以我们确定该事件将在UI任务中引发。您好,在进一步调查后,我注意到,在切换到x86版本后,所描述的情况不会立即发生。将代码编译为64位可以实现这种行为。奇怪的事情如果在循环中使用async/await
和await Task.Delay()
,您可以替换所有这些代码。如果异步方法被UI线程调用,在每次wait
之后,您将返回UI线程,允许您修改任何UI元素。多线程肯定不是原因,因为绑定引擎设计为在多线程环境中工作。您需要将视图的代码放在发布按钮周围进行诊断。只有在Ui线程上引发Notify propertychanged时,它才会起作用。看起来您在另一个线程上将其提升到ui。我同意panagiotis Async Wait,任务延迟会更简单。会有用的。嗨,谢谢你的意见。我已经使用了代码,结果发现问题出在绑定到按钮的CanRefreshOrders谓词中。我将按钮的内容连接到同一viewmodel中的ConnectionOnion状态值,它可以工作,即。该按钮根据连接状态更改其文本-但该按钮的启用状态仅在与UI交互后更改。所以现在的问题是刷新按钮谓词,而不是ping。顺便说一句,NotifyPropertyChanged使用Invoke方法,所以我们确定该事件将在UI任务中引发。您好,在进一步调查后,我注意到,在切换到x86版本后,所描述的情况不会立即发生。将代码编译为64位可以实现这种行为。怪事
public abstract class ObservableObject : INotifyPropertyChanged
{
public void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public sealed class UnfinishedOrdersVM : ObservableObject
{
private MachineState _machineStateData; //this is the same object as in DB class
private bool CanRefreshOrders()
{
return _machineStateData.DBLinkActive;
}
}