簡體   English   中英

來自Background worker的UI訪問問題

[英]Issue with UI access from Background worker

我正在將一個項目從winforms轉移到WPF。 當我的代碼基於WinForms時,我使用(this.InvokeRequired)檢查線程是否具有訪問權限。 現在我使用基於Mainform的以下代碼:

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

我遇到的問題是Listbox沒有更新。 沒有錯誤或異常,我嘗試更新其他UI控件。 LogMessage正在寫入Output窗口,所以我很難過。

這是控制台輸出的示例:

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

我已經嘗試更新其他UI控件只是為了檢查它是否是我的列表框的問題,但沒有運氣。

除了切換到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

但形式沒有變化。 這非常令人困惑!

我剛開始使用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;
            }
        }

我終於解決了這個問題

我的問題是,當我從另一個線程和另一個類調用LogUpdate方法時,因此我需要將包含listbox的主窗體的引用傳遞給此類,而不是在輔助節點中創建主窗體的新實例類。

所以不要在我的二級課程中使用此聲明:

public MainWindow MainForm = new MainWindow();

我需要將表單的引用傳遞給輔助類中的方法:

    public void Plot(BackgroundWorker worker, MainWindow MainForm)

在WPF中,所有UI控件都派生自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);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM