Updating UI with BackgroundWorker in WPF

后端 未结 3 553
生来不讨喜
生来不讨喜 2020-12-19 02:23

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 pr

相关标签:
3条回答
  • 2020-12-19 02:53

    In your DoWork method, you are manipulating WPF controls in code on a background thread, which you are not supposed to do. Actually, you should receive errors like "Cannot access control from other thread". Probably those exceptions are caught by your catch-all error handler, and maybe even the MessageBox doesn't work from the background thread.

    As a quick fix, you would have to make siteURL and collGroups class fields, move everything before the using block to your GetGroupsAndUsersButton_Click method, and everything starting with the first foreach loop to the RunworkerCompleted event, so that all code which accesses controls runs on the UI thread.

    Another thing you should change is that you should not create ListViewItems in code, but use a DataTemplate instead... this is not connected to your problem, though.

    0 讨论(0)
  • 2020-12-19 02:55

    You'll need:

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

    Then in your DoWork you'll need to call:

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

    Good worked example here: http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx

    0 讨论(0)
  • 2020-12-19 02:58

    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.

    0 讨论(0)
提交回复
热议问题