首页 文章

调用线程无法访问此对象,因为不同的线程拥有它,WPF [重复]

提问于
浏览
14

这个问题在这里已有答案:

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

现在我必须每隔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 回答

  • 27

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

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

    要么

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

    如果您由于某种原因不想使用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);
    }
    
  • 5

    试试这个:

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

相关问题