调用线程无法访问此对象,因为另一个线程拥有它,WPF

Viv*_*rav 15 c# wpf multithreading

我有一个通过插座连接的硬件,

现在我必须每隔5秒检查硬件是否已连接,复选框显示

我已经实现了一个功能:

private static System.Timers.Timer aTimer;
public MainWindow()
{
    InitializeComponent();
    client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client);
    aTimer = new System.Timers.Timer();
    aTimer.AutoReset = true;
    aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);

    aTimer.Interval = 2000;
    aTimer.Enabled = true;
}

private void OnTimedEvent(object source, ElapsedEventArgs e)
{
    if (client.Connected == true)
    {
        Console.WriteLine("Not Connected");
        CheckBox.IsChecked = false;
    }
    else
    {
        Console.WriteLine("Connected");
        CheckBox.IsChecked = false;
    }
}
Run Code Online (Sandbox Code Playgroud)

但是当我运行应用程序时,它会抛出错误.

调用线程无法访问此对象,因为另一个线程拥有它.

我研究并了解了Dispatcher.Invoke但未能在我的代码中实现它.

Muj*_*han 30

ui elememt只能由一个UI线程访问.CheckBox需要UI线程,您的计时器在不同的线程上运行.使用Dispatcher的简单代码

if (client.Connected == true)
{
    Dispatcher.Invoke(()=> {
        // Code causing the exception or requires UI thread access
        CheckBox.IsChecked =true;
    });
}
Run Code Online (Sandbox Code Playgroud)

要么

if (client.Connected == true)
{
    Dispatcher.Invoke(new Action(()=> {
        // Code causing the exception or requires UI thread access
        CheckBox.IsChecked =true;
    }));
}
Run Code Online (Sandbox Code Playgroud)

如果您收到错误,请An object reference is required for the non-static field, method, or property使用此

 Application.Current.Dispatcher.Invoke(() =>
 {
     // Code causing the exception or requires UI thread access
 });
Run Code Online (Sandbox Code Playgroud)


Fay*_*ilt 5

如果您由于某种原因不想使用Dispatcher,可以使用SynchronizationContext.没有太大的区别,但是在使用SynchronizationContext时我感觉不那么内疚,因为它不是WPF特定的类:

private static System.Timers.Timer aTimer;
private SynchronizationContext _uiContext = SynchronizationContext.Current;

public MainWindow()
{
    InitializeComponent();

    client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client);
    aTimer = new System.Timers.Timer();
    aTimer.AutoReset = true;
    aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);

    aTimer.Interval = 2000;
    aTimer.Enabled = true;
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{

    _uiContext.Post(new SendOrPostCallback(new Action<object>(o => {
        if (client.Connected == true)
        {
            Console.WriteLine("Not Connected");
            CheckBox.IsChecked = false;
        }
        else
        {
            Console.WriteLine("Connected");
            CheckBox.IsChecked = false;
        }
    })), null);
}
Run Code Online (Sandbox Code Playgroud)