获取错误:调用线程无法访问此对象,因为另一个线程在WPf应用程序中拥有它

时间:2013-02-04 04:38:22

标签: c# wpf multithreading serial-port

  

可能重复:
  The calling thread cannot access this object because a different thread owns it

我在我的Serialport程序中遇到此错误:

  

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

我有一个定时器功能来更新我的用户界面,同时用户可以按任意按钮与串口进行通信。

public MainWindow()
{
    InitializeComponent();

    OpenPort();

    Timer aTimer = new System.Timers.Timer();
    aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
    aTimer.Interval = 5000;
    aTimer.Enabled = true;
}

这是我的两个功能:

private void OnTimedEvent(object sender, EventArgs e)
{
    CheckStatus(); // this function will update my UI base of information will receive from serial port         
}

private void Processing()
{
    // Do stuff with serial port
}

3 个答案:

答案 0 :(得分:2)

  

我有一个定时器功能来更新我的UI

使用Dispatcher.Invoke从其他线程修改GUI。

  

在WPF中,只有创建DispatcherObject的线程才能访问   那个对象。例如,从中分离出的后台线程   主UI线程无法更新Button的内容   在UI线程上创建。为了后台线程   访问Button的Content属性,后台线程必须   将工作委托给与UI线程关联的Dispatcher。   这是通过使用Invoke或BeginInvoke来完成的。调用是   synchronous和BeginInvoke是异步的。

答案 1 :(得分:2)

问题是,正如您的错误所说,您启动了具有特定功能的线程。在您的情况下,当您使用OnTimedEvent启动线程时,此函数在与主应用程序不同的范围内运行:

enter image description here

这意味着:无论您尝试从与主程序相关的OnTimedEvent访问,还是反之,都会失败,因为它不在同一范围内运行。你能做什么?我使用代表团。

首先,您需要知道运行主应用程序的Context。因此,为主应用程序创建一个全局变量:

private SynchronizationContext uiContext;

然后,当您启动应用程序时,请捕获上下文的状态:

public MainWindow()
{
    uiContext = SynchronizationContext.Current;
}

通过这种方式,您可以了解应用程序或不同功能的真实背景。因此,如果您想知道您的OnTimedEvent是否在不同的上下文中运行并委托它,您将执行此操作:

if (SynchronizationContext.Current != uiContext)
{
    uiContext.Post(delegate { EnableMenuAndButtons(o, args); }, null);
}
else
{
    // Do your normal stuff here
}

然后,您应该能够在线程和vivecersa中使用变量。

o args 是我传递的变量。我使用WPF,但您可以将此示例与常规Windows窗体一起使用(但您必须使用它的特定方法)。 您需要的库是System.Threading

澄清:对你来说,就像这样:

private void OnTimedEvent(object sender, EventArgs e)
{
    if (SynchronizationContext.Current != uiContext)
    {
        uiContext.Post(delegate { EnableMenuAndButtons(sender, e); }, null);
    }
    else
    {
        // Do your normal stuff here
        CheckStatus(); // this function will update my UI base of information will receive from serial port 
    }
}

}

答案 2 :(得分:0)

请注意,对于System.Timers.Timer,tick事件是在与主UI线程不同的另一个线程中生成的。您可以使用

轻松验证
System.Diagnostics.Debug.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId);

在这种情况下,您需要调用Dispatcher.Invoke来更新UI元素,就像@Habib指出的那样。

另一方面,您也可以使用DispatcherTimer(WPF引入的计时器)而不是System.Timers.Timer。使用DispatcherTimer,将在主UI线程中引发tick事件,您可以毫无问题地修改UI。