簡體   English   中英

在WPF中使用BackgroundWorker更新UI

[英]Updating UI with BackgroundWorker in WPF

我目前正在編寫一個簡單的WPF 3.5應用程序,它利用SharePoint COM調用SharePoint站點並生成組和用戶信息。 由於此過程需要一段時間,因此我希望在生成組時顯示ProgressBar。 期望的過程如下:

  1. 用戶輸入url並單擊按鈕以獲取站點數據。
  2. ProgressBar開始動畫
  3. 生成組並將名稱添加到ListView
  4. 完成后,ProgressBar動畫結束

我遇到的問題是UI永遠不會更新。 ProgressBar或ListView都不做任何更改。 如果有人有任何想法來幫助下面的代碼,將不勝感激。

private void GetGroupsAndUsersButton_Click(object sender, RoutedEventArgs e)
{
    siteUrl = "";

    if (SiteURLTextBox.Text.Length > 0)
    {
        FetchDataProgressBar.IsIndeterminate = true;

        mWorker = new BackgroundWorker();
        mWorker.DoWork += new DoWorkEventHandler(worker_DoWork);
        mWorker.WorkerSupportsCancellation = true;
        mWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
        mWorker.RunWorkerAsync();
    }
    else
    {
        System.Windows.MessageBox.Show("Please enter a URL for the SharePoint site you wish to retrieve data");
    }
}

private void worker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
    siteUrl = SiteURLTextBox.Text;
    GroupListView.ItemsSource = null;

    try
    {
        using (SPSite site = new SPSite(siteUrl))
        {
            SPWeb web = site.OpenWeb();
            SPGroupCollection collGroups = web.SiteGroups;
            if (GroupNames == null)
                GroupNames = new List<string>();

            foreach (SPGroup oGroup in collGroups)
            {
                GroupListView.Items.Add(new ListViewItem() { Content = oGroup.Name });
            }

            foreach (ListViewItem item in GroupListView.Items)
            {
                item.MouseLeftButtonUp += item_MouseLeftButtonUp;
            }
        }
    }
    catch (Exception ex)
    {
        System.Windows.MessageBox.Show("Unable to locate a SharePoint site at: " + siteUrl);
    }
}

private void worker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
    FetchDataProgressBar.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
    new Action(
        delegate()
        {
            FetchDataProgressBar.IsIndeterminate = false;
        }
        ));
}

首先,您需要支持ProgressChanged事件。 BackgroundWorker初始化更新為:

GroupListView.ItemSource = null;
mWorker = new BackgroundWorker();
mWorker.DoWork += new DoWorkEventHandler(worker_DoWork);
mWorker.WorkerSupportsCancellation = true;
mWorker.WorkerReportsProgress = true;
mWorker.ProgressChanged += OnProgressChanged;
mWorker.RunWorkerCompleted +=
        new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
mWorker.RunWorkerAsync(SiteURLTextBox.Text);

之后你必須添加一個OnProgressChanged處理程序:

private void OnProgressChanged(object sender, ProgressChangedEventArgs e)
{
    FetchDataProgressBar.Value = e.ProgressPercentage;
    ListViewItem toAdd = (ListViewItem)e.UserState;
    toAdd.MouseLeftButtonUp += item_MouseLeftButtonUp;
    GroupListView.Items.Add(toAdd);
}

因此,您必須更改您的DoWork

private void worker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
    BackgroundWorker worker = (BackgroundWorker)sender;            
    try
    {
        using (SPSite site = new SPSite((String)e.Argument))
        {
            SPWeb web = site.OpenWeb();
            SPGroupCollection collGroups = web.SiteGroups;
            if(GroupNames == null)
                GroupNames = new List<string>();
            int added = 0;
            foreach(SPGroup oGroup in collGroups)
            {
                added++;
                ListViewItem tmp = new ListViewItem() {
                    Content = oGroup.Name
                };
                worker.ReportProgress((added * 100)/collGroups.Count,tmp);
            }
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show("Unable to locate a SharePoint site at: " + siteUrl);
    }
}

那是因為你不允許在DoWork上更改GUI。

之后,每個ListViewItem都單獨添加到ListView 我還建議您將URL作為參數傳遞給RunWorkerAsync

編輯 :向OnProgressChanged添加百分比。

在您的DoWork方法中,您正在操作背景線程中的代碼中的WPF控件,您不應該這樣做。 實際上,您應該收到“無法從其他線程訪問控制”等錯誤。 可能這些異常是由catch-all錯誤處理程序捕獲的,甚至MessageBox也無法在后台線程中運行。

作為快速修復,您必須創建siteURL和collGroups類字段,將使用塊之前的所有內容移動到GetGroupsAndUsersButton_Click方法,並將所有內容從第一個foreach循環開始循環到RunworkerCompleted事件,以便訪問控件的所有代碼都在UI線程。

您應該更改的另一件事是您不應該在代碼中創建ListViewItems,而是使用DataTemplate代替......但這與您的問題無關。

你需要:

mWorker.WorkerReportsProgress = true;
mWorker.ProgressChanged += 
    new ProgressChangedEventHandler(worker_ProgressChanged);

然后在您的DoWork您需要致電:

var worker = (BackgroundWorker)sender;
worker.ReportProgress(progressAmount);

這里有好的例子: http//msdn.microsoft.com/en-us/library/cc221403(v = vs95).aspx

暫無
暫無

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

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