C# 调用线程无法访问此对象,因为其他线程拥有它。WPF
每当我刷新标签时,都会出现以下错误:调用线程无法访问此对象,因为另一个线程拥有它。我尝试调用,但失败。我用的是WPF表格C# 调用线程无法访问此对象,因为其他线程拥有它。WPF,c#,.net,wpf,multithreading,dispatcher,C#,.net,Wpf,Multithreading,Dispatcher,每当我刷新标签时,都会出现以下错误:调用线程无法访问此对象,因为另一个线程拥有它。我尝试调用,但失败。我用的是WPF表格 delegate void lostfocs(string st); private void imgPayment_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { Thread t = new Thread(modi); t.Start(); }
delegate void lostfocs(string st);
private void imgPayment_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Thread t = new Thread(modi);
t.Start();
}
void modi()
{
try
{
label1.Content = "df";
}
catch
{
lostfocs ld = new lostfocs(up);
// ld.Invoke("df");
object obj=new object();
ld.Invoke("sdaf");
}
}
void up(string st)
{
label1.Content = st;
}
使用方法
在线程上同步执行指定的委托
调度程序与关联
也
在WPF中,只有创建DispatcherObject的线程才能访问
那个物体。例如,从中剥离的背景线程
主UI线程无法更新已删除的按钮的内容
在UI线程上创建。为了让后台线程
访问按钮的内容属性时,后台线程必须
将工作委托给与UI线程关联的调度程序。
这是通过使用Invoke或BeginInvoke来实现的。调用是
同步和BeginInvoke是异步的。该操作被添加到
位于指定DispatcherPriority的调度程序的事件队列
出现错误是因为您的标签是在UI线程上创建的,并且您正试图通过另一个线程修改其内容。这就是您需要Dispatcher.Invoke的地方
看看这篇文章
您可以使用Dispatcher进行此操作。你的代码变成
private void imgPayment_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Dispatcher.BeginInvoke(DispatcherPriority.Input, new ThreadStart(() =>
{
try
{
label1.Content = "df";
}
catch
{
lostfocs ld = new lostfocs(up);
// ld.Invoke("df");
object obj=new object();
ld.Invoke("sdaf");
}
}
));
使用
范例
void modi()
{
if(!Dispatcher.CheckAccess())
{
Dispatcher.Invoke(
()=>label1.Content = "df",DispatcherPriority.Normal);
}
else
{
label1.Content = "df";
}
}
关于使用BeginInvoke的一些建议,但没有提到EndInvoke。好的实践是“每个BeginInvoke都有一个匹配的EndInvoke”,当然需要一些防止争用条件的保护措施(想想:多个BeginInvoke的代码会发生什么,但没有一个代码完成了处理?)
这很容易忘记,我在MSDN示例和WinForms上出版的书籍中都看到过这个错误(是的,这是一个错误)我启动了一个非UI线程,在这个线程中我也启动了一个UI线程。所以我的要求就像在非UI线程中运行UI线程。在处理这个场景时,我遇到了以下异常。 “异常:调用线程无法访问此对象,因为其他线程拥有它。” 在本例中,我使用了UI元素的Dispatcher.Invoke方法,如下所示,它运行良好
if (m_contextWindow == null)
{
System.Threading.Thread newWindowThread = new System.Threading.Thread(new ThreadStart( () =>
{
// Create and show the Window
m_contextWindow = new ContextWindow();
m_contextWindow.DataContext = this;
m_contextWindow.Show();
// Start the Dispatcher Processing
System.Windows.Threading.Dispatcher.Run();
}));
// Set the apartment state
newWindowThread.SetApartmentState(ApartmentState.STA);
// Make the thread a background thread
newWindowThread.IsBackground = true;
// Start the thread
newWindowThread.Start();
}
else
{
this.m_contextWindow.Dispatcher.Invoke(new ThreadStart(() =>
{
m_contextWindow.DataContext = this;
if (m_contextWindow.Visibility == System.Windows.Visibility.Collapsed
|| m_contextWindow.Visibility == System.Windows.Visibility.Hidden)
m_contextWindow.Visibility = System.Windows.Visibility.Visible;
}));
}
你为什么要使用try-catch-block?@Sinatr:你是说不用EndInvoke就可以使用BeginInvoke吗?还是我回答的另一部分错了?我已经检查过了,没有发现错误。请解释为什么你的评论“显然是错误的答案”你在另一个答案中有评论。在wpf中没有EndInvoke方法。感谢您包含Dispatcher.CheckAccess位,这是我在相关问题中遗漏的最后一步!如果有人在其他线程中搜索设置窗口所有者的问题:
if (m_contextWindow == null)
{
System.Threading.Thread newWindowThread = new System.Threading.Thread(new ThreadStart( () =>
{
// Create and show the Window
m_contextWindow = new ContextWindow();
m_contextWindow.DataContext = this;
m_contextWindow.Show();
// Start the Dispatcher Processing
System.Windows.Threading.Dispatcher.Run();
}));
// Set the apartment state
newWindowThread.SetApartmentState(ApartmentState.STA);
// Make the thread a background thread
newWindowThread.IsBackground = true;
// Start the thread
newWindowThread.Start();
}
else
{
this.m_contextWindow.Dispatcher.Invoke(new ThreadStart(() =>
{
m_contextWindow.DataContext = this;
if (m_contextWindow.Visibility == System.Windows.Visibility.Collapsed
|| m_contextWindow.Visibility == System.Windows.Visibility.Hidden)
m_contextWindow.Visibility = System.Windows.Visibility.Visible;
}));
}