C# 调用线程无法访问此对象,因为其他线程拥有它。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(); }

每当我刷新标签时,都会出现以下错误:调用线程无法访问此对象,因为另一个线程拥有它。我尝试调用,但失败。我用的是WPF表格

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