Проблема с доступом к пользовательскому интерфейсу из Фонового работника - PullRequest
6 голосов
/ 22 июня 2011

Я перевожу проект с winforms на WPF.Когда мой код был основан на WinForms, я использовал (this.InvokeRequired), чтобы проверить, имеет ли поток доступ.Теперь я использую следующий код, основанный на моей главной форме:

    // this is the delegate declaration to Allow Background worker thread to write to Log Output
    delegate void LogUpdateCallBack(String LogMessage);

    // method to update the Log Window from the Background Thread
    public void LogUpdate(String LogMessage)
    {
        Console.WriteLine("Entering");
        if (!Application.Current.Dispatcher.CheckAccess())
        {
            Console.WriteLine("Thread doesn't have UI access");
            LogUpdateCallBack callback = new LogUpdateCallBack(LogUpdate);
            Application.Current.Dispatcher.Invoke(callback, LogMessage);
        }
        else
        {
            Console.WriteLine("Thread has UI access");
            listBox_Output.Items.Add(LogMessage);
            Console.WriteLine(LogMessage);
            // listBox_Output.TopIndex = listBox_Output.Items.Count - 1;
        }
        Console.WriteLine("Exiting");
    }

У меня проблема в том, что список не обновляется.Там нет ошибок или исключений, я пытался обновить другие элементы управления пользовательского интерфейса.LogMessage пишет в окно вывода, поэтому я в тупике.

Вот пример вывода консоли:

Entering
Thread doesn't have UI access
Entering
Thread has UI access
My LogMessage is output here 
Exiting
Exiting
Entering
Thread doesn't have UI access
Entering
Thread has UI access
My LogMessage is output here 
Exiting
Exiting

Я попытался обновить другие элементы управления пользовательским интерфейсом, просто чтобы проверить, не связана ли это с моим списком, но безуспешно.

Другоекроме переключения на CheckAccess (), единственное другое важное изменение, которое я сделал в новом коде WPF, - это основание всего кода, работающего в фоновом режиме, в другом классе. Я не уверен, может ли это быть частью проблемы?.

-

@ JonRaynor

Я попробовал вашу идею:

Application.Current.Dispatcher.BeginInvoke(new LogUpdateCallBack(LogUpdate), LogMessage)

Однако мой список все еще не 'Обновление, если я вывожу

Console.WriteLine(listBox_Output);

Я вижу рост массива списка:

System.Windows.Controls.ListBox Items.Count:2020
System.Windows.Controls.ListBox Items.Count:2021
System.Windows.Controls.ListBox Items.Count:2022
System.Windows.Controls.ListBox Items.Count:2023
System.Windows.Controls.ListBox Items.Count:2024
System.Windows.Controls.ListBox Items.Count:2025

Но никаких изменений в форме.Это очень сбивает с толку!

Ответы [ 3 ]

2 голосов
/ 22 июня 2011

Я только начал работать с WPF и мне пришлось переучиваться по старому образу WinForms.Я использовал BeginInvoke () и этот тип синтаксиса на моих экранах (формах) ...

public delegate void WorkCompleted();

        /// <summary>
        /// Marks the end of the progress
        /// </summary>
        private void ProgressComplete()
        {
            if (!this.Dispatcher.CheckAccess())
            {
                this.Dispatcher.BeginInvoke(new WorkCompleted(ProgressComplete), System.Windows.Threading.DispatcherPriority.Normal, null);
            }
            else
            {
                this.buttonClose.Visibility = Visibility.Visible;
                this.progressBarStatus.IsIndeterminate = false;
            }
        }
1 голос
/ 28 июня 2011

Я наконец-то решил это.

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

так что вместо этого объявления в моем втором классе:

public MainWindow MainForm = new MainWindow();

Мне нужно было передать ссылку формы в метод второго класса:

    public void Plot(BackgroundWorker worker, MainWindow MainForm)
0 голосов
/ 23 июня 2011

В WPF все элементы управления пользовательского интерфейса получены из DispatcherObject. Это означает, что ваш элемент управления ListBox сам по себе является объектом с возможностью отправки. Попробуйте вызвать Dispatcher для этого объекта, а не полагаться на саму форму. Извлеките параметр в вашем делегате (поскольку у вас все равно есть доступ к переменной LogMessage), и он будет выглядеть примерно так:

public void LogUpdate(string LogMessage)
{
    Console.WriteLine("Entering");
    if (listBox_Output.Dispatcher.CheckAccess())
    {
        listBox_Output.Dispatcher.Invoke(new LogUpdateCallBack(delegate
        {
            listBox_Output.Items.Add(LogMessage);
        }));
        Console.WriteLine(LogMessage);
    }
}
...