C# 另一个线程中的循环ping+;更新用户界面

C# 另一个线程中的循环ping+;更新用户界面,c#,.net,wpf,multithreading,C#,.net,Wpf,Multithreading,我正在实现循环ping功能,该功能的输出应反映在UI按钮的启用状态中(即,当ping结果!=成功时,按钮应被禁用)。我将WPF与MVVM模型结合使用,因此我不会与代码中的控件交互,而是使用绑定和通知机制 问题如下: 我正在用网络启动应用程序ok 按钮是灰色的 我单击UI区域中的某个位置,按钮立即处于活动状态 现在我断开网络电缆-按钮保持其状态 我单击UI区域中的某个位置-按钮立即处于非活动状态 等等。因此,存储连接状态的datapoint值的更改不会反映在UI更改中——只有在刷新UI视图时才

我正在实现循环ping功能,该功能的输出应反映在UI按钮的启用状态中(即,当ping结果!=成功时,按钮应被禁用)。我将WPF与MVVM模型结合使用,因此我不会与代码中的控件交互,而是使用绑定和通知机制

问题如下:

  • 我正在用网络启动应用程序ok
  • 按钮是灰色的
  • 我单击UI区域中的某个位置,按钮立即处于活动状态
  • 现在我断开网络电缆-按钮保持其状态
  • 我单击UI区域中的某个位置-按钮立即处于非活动状态
等等。因此,存储连接状态的datapoint值的更改不会反映在UI更改中——只有在刷新UI视图时才会反映。我在我的整个应用程序中使用了相同的通知机制,效果很好

我还尝试在DB类的构造函数中只调用ping一次,然后在启动应用程序时,当我的网络打开时,屏幕上的按钮变为活动状态,当网络断开时,该按钮变为非活动状态。所以通知机制起作用了

以下是ping站点的代码:

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之前

我还尝试在
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;
        }
}