因为不同的线程拥有它,所以调用线程无法访问此对象 - WPF

19

我有一个通过套接字连接的硬件设备。

我需要每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;
    }
}

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

The calling thread cannot access this object because a different thread owns it.

我研究了解了 Dispatcher.Invoke,但是无法在我的代码中实现它。

3个回答

36

UI元素只能由一个UI线程访问。CheckBox需要UI线程,而计时器运行在不同的线程上。使用Dispatcher的简单代码。

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

如果你收到错误 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
 });

Duad Khan:上面的示例代码出现了错误:无法将 Lambda 表达式转换为“System.delegate”,因为它不是委托类型。 - Vivek Saurav
1
检查我所做的编辑。有关此错误的更多信息:(https://dev59.com/jGkw5IYBdhLWcg3w8O-o) - Mujahid Daud Khan
完美男人。谢谢! :) :D - Vivek Saurav

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);
}

很棒 @Fayilt 你的代码对我来说运行良好 :) :) - Vivek Saurav

4

试试这个:

System.Windows.Application.Current.Dispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.Normal, (Action)delegate
{
    // Update UI component here
    CheckBox.IsChecked = false;
});

1
这真的帮了大忙,其他一切都失败了。 - IneedHelp
无法看出它是如何工作的。上述代码中参数的顺序不正确。 - dotNET
@dotNET:它在与Dispatcher相关联的线程上以指定的优先级同步执行指定的线程。也许您正在期望Invoke方法的另一个重载。参数的顺序在上面的代码中绝对正确,请参阅msdn:https://msdn.microsoft.com/en-us/library/ms591593(v=vs.110).aspx - Ramashankar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接