可能重复:
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
}
答案 0 :(得分:2)
我有一个定时器功能来更新我的UI
使用Dispatcher.Invoke从其他线程修改GUI。
在WPF中,只有创建DispatcherObject的线程才能访问 那个对象。例如,从中分离出的后台线程 主UI线程无法更新Button的内容 在UI线程上创建。为了后台线程 访问Button的Content属性,后台线程必须 将工作委托给与UI线程关联的Dispatcher。 这是通过使用Invoke或BeginInvoke来完成的。调用是 synchronous和BeginInvoke是异步的。
答案 1 :(得分:2)
问题是,正如您的错误所说,您启动了具有特定功能的线程。在您的情况下,当您使用OnTimedEvent
启动线程时,此函数在与主应用程序不同的范围内运行:
这意味着:无论您尝试从与主程序相关的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。