Вызывающий поток не может получить доступ к этому объекту, потому что другой поток владеет.В WPF

всякий раз, когда я обновляю метку, я получаю эту ошибку:вызывающий поток не может получить доступ к этому объекту, потому что другой поток владеет. я пыталась вызвать, но это не удалось. Я использую форму 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;
    }

6 ответов


использовать диспетчер.Invoke метод.

выполняет указанный делегат синхронно в потоке Диспетчер связан с.

и

в WPF только поток, который создал DispatcherObject может получить доступ этот объект. Например,фоновый поток, который отключен от основной поток пользовательского интерфейса не может обновить содержимое кнопки, которая была создано в потоке пользовательского интерфейса. В заказать фоновый поток для доступ к свойству Content кнопки, фоновый поток должен делегируйте работу диспетчеру, связанному с потоком пользовательского интерфейса. Это достигается с помощью Invoke или BeginInvoke. Ссылаться на это синхронный и асинхронный метод BeginInvoke. Операция добавляется в очередь событий диспетчера в указанном DispatcherPriority.

вы получаете ошибку, потому что ваша метка создается в потоке пользовательского интерфейса, и вы пытаются изменить его содержимое с помощью другого потока. Здесь вам понадобится диспетчер.Взывать.

ознакомьтесь с этой статьей потоки WPF создают более отзывчивые приложения с помощью Диспетчера


для этого можно использовать 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");
        }
    }
));

использовать диспетчер.Invoke

пример

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

Я начал один не-UI поток, и в этом потоке я тоже смотрел один поток UI. Поэтому мое требование похоже на запуск потока пользовательского интерфейса в потоке без пользовательского интерфейса. При обработке этого сценария я получил следующее исключение. "исключение: вызывающий поток не может получить доступ к этому объекту, потому что другой поток владеет."

в этом случае я использовал диспетчер.Вызовите метод элемента UI следующим образом, и он работал хорошо.

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

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

несколько предложений по использованию BeginInvoke, но без упоминания EndInvoke. Хорошая практика заключается в том, что "каждый BeginInvoke имеет соответствующий EndInvoke", и, конечно, должна быть какая-то защита от условий гонки (подумайте: что происходит с несколькими BeginInvoke кода, но никто еще не закончил обработку?)

легко забыть, и я видел эту ошибку (и, да, это is ошибка) как в примерах MSDN, так и в опубликованных книгах по WinForms