2011-01-21 28 views
5

kể từ hai ngày tôi đang cố gắng giải quyết vấn đề sau: Tôi có một điều khiển WPF nơi WrapPanel được ràng buộc với một ObservableCollection. Một hành động thay đổi nội dung của ObservableCollection. Nội dung được tải trong một BackgroundWorker. Ngay sau khi hành động gây ra thay đổi nội dung, nội dung mới là cần thiết trong vòng lặp foreach. Vấn đề là tải nội dung chậm, vì vậy nó cần một chút để sẵn sàng.Làm thế nào để cập nhật ObservableCollection từ bên trong một BackgroundWorker bằng cách sử dụng MVVM?

Nỗ lực đầu tiên của tôi là đợi nhân viên nền cho đến khi thuộc tính IsBusy được đặt thành false. Nhưng tài sản IsBusy không bao giờ thay đổi trong khi chờ đợi! Nỗ lực thứ hai là cố gắng thao tác ObservableCollection trực tiếp từ BackgroundWorker. Tất nhiên không thành công vì ObservableCollection nằm trong một luồng khác với BackgroundWorker.

Tôi đã đọc rất nhiều về cách thao tác nội dung trong toàn chuỗi. Nhưng không ai trong số họ làm việc. Đã thử các giải pháp với Người điều phối, "ThreadSafeObservableCollection", .....

Có ai cho tôi biết cách tôi có thể giải quyết vấn đề đó không? Có cách nào đơn giản để chỉnh sửa nội dung của chuỗi giao diện người dùng trong chuỗi khác không? Hoặc làm cách nào để tôi đợi chính xác cho BackgroundWorker hoàn tất?

EDIT: Nhưng làm cách nào tôi có thể đợi BackgroundWorker hoàn thành ???

Trả lời

4

Đẩy ObservableCollection.Add vào bộ điều phối của chuỗi giao diện người dùng sẽ hoạt động.

App.Current.Dispatcher.Invoke(new Action(() => collection.Add(item))); 
+0

này không giúp tiết kiệm thời gian, nó chạy nhưng trên cùng một sợi! –

1

BackGroundWorker kích hoạt sự kiện khi nó kết thúc. Những gì tôi đã và đang làm trong một tình huống tương tự là:

Tôi có một danh sách đó không phải là một observablecollecion

  • Set enabled = false trong cửa sổ của tôi và hiển thị một spinner
  • nhân nền
  • Bắt đầu
  • trong DoWork i điền vào danh sách
  • trong RunWorkerSự kiện đã hoàn thành i sao chép nội dung danh sách vào quan sát của tôi và bật công cụ và ẩn spinner

vì vậy tất cả sự tương tác với bộ sưu tập là trên cùng một luồng - việc sao chép thường không phải là phần đắt tiền.

2

Bạn có thể cập nhật bộ sưu tập của mình trong trình xử lý sự kiện BackgroundWorker.RunWorkerCompleted. Nó chạy trong cùng một bối cảnh đồng bộ hóa, bạn bắt đầu nó là một chủ đề UI thường để bạn có thể sử dụng một cách an toàn bất kỳ công cụ liên quan đến giao diện người dùng nào từ đó.

8

BackgroundWorker có thể giúp bạn theo hai cách.

Để cập nhật bộ sưu tập trong khi BGWorker đang chạy, hãy sử dụng sự kiện ProgressChanged. Tên của sự kiện này gây hiểu lầm - trong khi bạn có thể cập nhật tiến trình của một tác vụ, bạn có thể sử dụng nó cho bất kỳ thứ gì cần thực hiện trong giao diện người dùng (gọi) bằng cách truyền một đối tượng bằng thuộc tính UserState của ProgressChangedEventArgs.

BGWorker cũng có sự kiện khi nó kết thúc.Một lần nữa, bạn có thể chuyển bất kỳ thông tin nào về nó mà bạn muốn trong thuộc tính Result của RunWorkerCompletedEventArgs trong sự kiện RunWorkerCompleted.

Các mã sau đây là từ another thread mà tôi đã trả lời về BackgroundWorker:

BackgroundWorker bgWorker = new BackgroundWorker(); 
ObservableCollection<int> mNumbers = new ObservableCollection<int>(); 

public Window1() 
{ 
    InitializeComponent(); 
    bgWorker.DoWork += 
     new DoWorkEventHandler(bgWorker_DoWork); 
    bgWorker.ProgressChanged += 
     new ProgressChangedEventHandler(bgWorker_ProgressChanged); 
    bgWorker.RunWorkerCompleted += 
     new RunWorkerCompletedEventHandler(bgWorker_RunWorkerCompleted); 
    bgWorker.WorkerReportsProgress = true; 

    btnGenerateNumbers.Click += (s, e) => UpdateNumbers(); 

    this.DataContext = this; 
} 

void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    progress.Visibility = Visibility.Collapsed; 
    lstItems.Opacity = 1d; 
    btnGenerateNumbers.IsEnabled = true; 
} 

void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) 
{ 
    List<int> numbers = (List<int>)e.UserState; 
    foreach (int number in numbers) 
    { 
     mNumbers.Add(number); 
    } 

    progress.Value = e.ProgressPercentage; 
} 

void bgWorker_DoWork(object sender, DoWorkEventArgs e) 
{ 
    Random rnd = new Random(); 
    List<int> numbers = new List<int>(10); 

    for (int i = 1; i <= 100; i++) 
    { 
     // Add a random number 
     numbers.Add(rnd.Next());    

     // Sleep from 1/8 of a second to 1 second 
     Thread.Sleep(rnd.Next(125, 1000)); 

     // Every 10 iterations, report progress 
     if ((i % 10) == 0) 
     { 
      bgWorker.ReportProgress(i, numbers.ToList<int>()); 
      numbers.Clear(); 
     } 
    } 
} 

public ObservableCollection<int> NumberItems 
{ 
    get { return mNumbers; } 
} 

private void UpdateNumbers() 
{ 
    btnGenerateNumbers.IsEnabled = false; 
    mNumbers.Clear(); 
    progress.Value = 0; 
    progress.Visibility = Visibility.Visible; 
    lstItems.Opacity = 0.5; 

    bgWorker.RunWorkerAsync(); 
} 
Các vấn đề liên quan