22

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

6 回答 6

42

使用Dispatcher.Invoke方法。

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

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

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

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

于 2012-05-29T08:59:43.833 回答
17

您可以为此使用 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");
        }
    }
));
于 2012-05-29T09:02:24.627 回答
11

使用Dispatcher.Invoke

例子

    void modi()
    {
        if(!Dispatcher.CheckAccess())
        {
            Dispatcher.Invoke(
                    ()=>label1.Content = "df",DispatcherPriority.Normal);
        }
        else
        {
            label1.Content = "df";
        }
    }
于 2012-05-29T09:06:05.140 回答
1

我启动了一个非 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;
    }));                            
}
于 2014-02-19T12:51:44.577 回答
0
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");
                }
            }));
        }
于 2012-05-29T09:51:26.060 回答
0

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

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

于 2014-01-07T03:11:13.890 回答