Вопрос по wpf, c#, multithreading, .net – Вызывающий поток не может получить доступ к этому объекту, так как он принадлежит другому потоку. WPP

22

Всякий раз, когда я обновляю ярлык, я получаю эту ошибку:The calling thread cannot access this object because a different thread owns it. Я пытался вызвать, но это не удалось. Я использую форму 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;
    }
почему вы используете блок try catch? Tilak
возможный дубликатthe calling thread cannot access this object because a different thread owns it in wpf markus

Ваш Ответ

6   ответов
40

использованиеDispatcher.Invoke Метод.

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

Также

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.

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

Проверьте эту статью WPF Threads создает более отзывчивые приложения с помощью Dispatcher

Это большое спасибо Yasser
@yasser, пожалуйста
0

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

использованиеDispatcher.Invoke

пример

    void modi()
    {
        if(!Dispatcher.CheckAccess())
        {
            Dispatcher.Invoke(
                    ()=>label1.Content = "df",DispatcherPriority.Normal);
        }
        else
        {
            label1.Content = "df";
        }
    }
Спасибо, что включили бит Dispatcher.CheckAccess, это был последний шаг, который я пропустил в связанной проблеме!
17

Вы можете использовать Диспетчер для этого. Ваш код становится ...

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");
        }
    }
));
это УДИВИТЕЛЬНО Большое спасибо Yasser
0

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

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

Очевидно, неправильный ответ.
@ Синатр: Вы говорите, что можно использовать BeginInvoke без EndInvoke? Или это другая часть моего ответа, которая неверна? Я проверил это и не вижу ошибок. Пожалуйста, объясните, почему вы сделали свой комментарий "Очевидно, неправильный ответ"
Вы получили комментарий в другом своем ответе. Вwpf Dispatcher не имеет метода EndInvoke.
1

Я запустил один не-пользовательский поток, и в этом потоке я тоже смотрел один пользовательский поток. Таким образом, мое требование похоже на запуск потока пользовательского интерфейса в потоке без пользовательского интерфейса. При обработке этого сценария я получил следующее исключение. "Exception: The calling thread cannot access this object because a different thread owns it."

В этом случае я использовал метод Dispatcher.Invoke элемента 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;
    }));                            
}
Если кто-то ищет проблему с настройкой владельца окна из другого потока:stackoverflow.com/questions/14896111/…

Похожие вопросы