C# 调用线程无法访问此对象,因为其他线程拥有它。WPF

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10795948/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 15:17:01  来源:igfitidea点击:

The calling thread cannot access this object because a different thread owns it.WPF

c#.netwpfmultithreadingdispatcher

提问by Yasser

Whenever I refresh a label, I got this error: The calling thread cannot access this object because a different thread owns it.I tried to invoke but it's failed. I'm using WPF Form.

每当我刷新标签时,都会收到此错误: 调用线程无法访问此对象,因为其他线程拥有它。我试图调用但它失败了。我正在使用 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;
    }

采纳答案by Habib

Use Dispatcher.InvokeMethod.

使用Dispatcher.Invoke方法。

Executes the specified delegate synchronously on the thread the Dispatcher is associated with.

在 Dispatcher 关联的线程上同步执行指定的委托。

Also

In WPF, only the thread that created a DispatcherObject may access that object. For example, a background thread that is spun off from the main UI thread cannot update the contents of a Button that was created on the UI thread. In order for the background thread to access the Content property of the Button, the background thread must delegate the work to the Dispatcher associated with the UI thread. This is accomplished by using either Invoke or BeginInvoke. Invoke is synchronous and BeginInvoke is asynchronous. The operation is added to the event queue of the Dispatcher at the specified DispatcherPriority.

在 WPF 中,只有创建 DispatcherObject 的线程才能访问该对象。例如,从主 UI 线程分出后台线程无法更新在 UI 线程上创建的 Button 的内容。为了让后台线程访问 Button 的 Content 属性,后台线程必须将工作委托给与 UI 线程关联的 Dispatcher。这是通过使用 Invoke 或 BeginInvoke 来完成的。Invoke 是同步的,而 BeginInvoke 是异步的。操作被添加到指定 DispatcherPriority 的 Dispatcher 的事件队列中。

You are getting the error because your label is created on UI thread and you are trying to modify its content via another thread. This is where you would require Dispatcher.Invoke.

您收到错误是因为您的标签是在 UI 线程上创建的,并且您正尝试通过另一个线程修改其内容。这是您需要 Dispatcher.Invoke 的地方。

Check out this article WPF Threads Build More Responsive Apps With The Dispatcher

查看这篇文章 WPF Threads Build More Responsive Apps With The Dispatcher

回答by gaurawerma

You can use Dispatcher for this. Your code becomes...

为此,您可以使用 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");
        }
    }
));

回答by Tilak

use Dispatcher.Invoke

使用Dispatcher.Invoke

Example

例子

    void modi()
    {
        if(!Dispatcher.CheckAccess())
        {
            Dispatcher.Invoke(
                    ()=>label1.Content = "df",DispatcherPriority.Normal);
        }
        else
        {
            label1.Content = "df";
        }
    }

回答by Kishore Kumar

private void imgPayment_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            Dispatcher.BeginInvoke(DispatcherPriority.Input, new ThreadStart(() =>
            {
                try
                {
                    label1.Content = "df";
                }
                catch
                {
                    lostfocs ld = new lostfocs(up);
                    object obj = new object();
                    ld.Invoke("sdaf");
                }
            }));
        }

回答by brewmanz

Several suggestions to use BeginInvoke, but no mention of EndInvoke. Good Practice is that 'every BeginInvoke has a matching EndInvoke' and certainly there needs to be some safeguard against race conditions (Think: what happens with multiple BeginInvoke of code but none have finished processing yet?)

使用 BeginInvoke 的几个建议,但没有提到 EndInvoke。好的做法是“每个 BeginInvoke 都有一个匹配的 EndInvoke”,当然需要有一些针对竞争条件的保护措施(想想:代码的多个 BeginInvoke 会发生什么,但没有完成处理?)

It's easy to forget, and I've seen this error (and, yes, it isan error) in both MSDN examples and published books on WinForms

很容易忘记,我在 MSDN 示例和已出版的 WinForms 书籍中都看到过这个错误(而且,是的,这一个错误)

回答by Srikanth Dornala

I started one non-UI Thread and within this thread I stared one UI thread too. So my requirement is like running an UI thread within a non-UI thread. When handling this scenario I got the following exception. "Exception: The calling thread cannot access this object because a different thread owns it."

我启动了一个非 UI 线程,在这个线程中我也启动了一个 UI 线程。所以我的要求就像在非 UI 线程中运行 UI 线程。在处理这种情况时,我遇到了以下异常。 “异常:调用线程无法访问此对象,因为其他线程拥有它。”

In this case I used the Dispatcher.Invoke method of the UI element as follows and it worked well.

在这种情况下,我使用了 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;
    }));                            
}