Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
309 views
in Technique[技术] by (71.8m points)

c# - Updating UI with BackgroundWorker in WPF

I am currently writing a simple WPF 3.5 application that utilizes the SharePoint COM to make calls to SharePoint sites and generate Group and User information. Since this process takes awhile I want to show a ProgressBar while the groups are being generated. The desired process is as follows:

  1. User enters url and clicks button to fetch site data.
  2. ProgressBar begins animation
  3. Groups are generated and names are added to a ListView
  4. Upon completion ProgressBar animation ends

The problem I am running into is that the UI is never updated. Neither the ProgressBar or the ListView makes any changes. If anyone has any ideas to help with the code below it would be greatly appreciated.

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;
        }
        ));
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

At first you need to support ProgressChanged events. Update your BackgroundWorker initialization to:

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

After that you have to add a OnProgressChanged handler:

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

Therefore you have to change your 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);
    }
}

That's because you're not allowed to change GUI on DoWork.

After that, each ListViewItem is added separately to your ListView. I would also recommend, that your URL is passed as an argument to RunWorkerAsync.

Edit: Add percentage to OnProgressChanged.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...