2013-05-24 43 views
8

Tôi hiện đang viết một ứng dụng WPF 3.5 đơn giản sử dụng SharePoint COM để thực hiện cuộc gọi đến các trang SharePoint và tạo thông tin Nhóm và Người dùng. Vì quá trình này mất một lúc, tôi muốn hiển thị ProgressBar trong khi các nhóm đang được tạo. Quy trình mong muốn như sau:Cập nhật giao diện người dùng với BackgroundWorker trong WPF

  1. Người dùng nhập url và nút nhấp để tìm nạp dữ liệu trang web.
  2. ProgressBar bắt đầu hoạt hình
  3. Các nhóm được tạo ra và tên được thêm vào một ListView
  4. Khi hoạt hình hoàn ProgressBar kết thúc

Vấn đề tôi đang chạy vào đó là giao diện người dùng không bao giờ được cập nhật. Cả ProgressBar hoặc ListView đều không thực hiện bất kỳ thay đổi nào. Nếu bất cứ ai có bất kỳ ý tưởng để giúp với các mã dưới đây nó sẽ được đánh giá rất nhiều.

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

Trả lời

7

Lúc đầu bạn cần hỗ trợ ProgressChanged sự kiện. Cập nhật BackgroundWorker khởi tạo của bạn để:

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

Sau đó bạn phải thêm một handler 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); 
} 

Vì vậy, bạn cần phải thay đổi bạn 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); 
    } 
} 

Đó là bởi vì bạn' không được phép thay đổi GUI trên DoWork.

Sau đó, mỗi ListViewItem được thêm riêng vào ListView của bạn. Tôi cũng khuyên bạn nên, URL của bạn được chuyển làm đối số cho RunWorkerAsync.

Chỉnh sửa: Thêm tỷ lệ phần trăm vào OnProgressChanged.

+0

Cảm ơn bạn đã trả lời. Đáng buồn thay, không có bản cập nhật GUI nào. Ngoài ra, trong khi gỡ lỗi, sự kiện thay đổi tiến trình không bao giờ bị tấn công. Nó ngay lập tức phá vỡ tại worker_RunWorkerCompleted mặc dù (???) – pstricker

+0

bạn đã bao giờ đạt được vòng lặp vào try/catch? – Kooki

+0

Sau một chút tinkering tôi đã có thể đạt được thử/bắt bằng cách di chuyển mã tham chiếu đến các yếu tố giao diện người dùng (GroupListView và SiteUrlTextBox) đến sự kiện nhấn nút tuy nhiên bây giờ nó là một ngoại lệ khi khởi tạo ListViewItem: "Chuỗi gọi phải là STA, vì nhiều thành phần giao diện người dùng yêu cầu điều này ". – pstricker

1

Bạn sẽ cần:

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

Sau đó, trong bạn DoWork bạn sẽ cần phải gọi:

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

Tốt làm việc ví dụ ở đây: http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx

+0

Cảm ơn bạn đã trả lời. Rất tiếc, tôi không cố gắng cập nhật thanh tiến trình có giá trị, tôi chỉ muốn hiển thị hoạt ảnh Không xác định. – pstricker

+0

Nếu trường hợp đó, bạn không cần phải gọi cuộc gọi đến '.IsIndeterminate = true;' giống như bạn thực hiện cuộc gọi đến '.IsIndeterminate = false; ' – paul

2

Trong phương pháp DoWork, bạn đang điều khiển các điều khiển WPF bằng mã trên một chuỗi nền mà bạn không được phép làm. Trên thực tế, bạn sẽ nhận được các lỗi như "Không thể truy cập điều khiển từ chuỗi khác". Có lẽ những ngoại lệ đó bị bắt bởi trình xử lý lỗi bắt tất cả của bạn và thậm chí cả MessageBox không hoạt động từ chuỗi nền. Để sửa chữa nhanh chóng, bạn sẽ phải tạo các trường lớp siteURL và collGroups, di chuyển mọi thứ trước khối sử dụng đến phương thức GetGroupsAndUsersButton_Click của bạn và mọi thứ bắt đầu với vòng lặp foreach đầu tiên cho sự kiện RunworkerCompleted, để tất cả các mã truy cập điều khiển chạy trên chuỗi giao diện người dùng.

Một điều bạn nên thay đổi là bạn không nên tạo ListViewItems trong mã, nhưng sử dụng một DataTemplate thay vì ... điều này không được kết nối với vấn đề của bạn, mặc dù.

Các vấn đề liên quan