2013-02-14 56 views
5

Tôi đang làm việc trên một công cụ hỗ trợ hiển thị nhiều TabItem s trong một TabControl. Mỗi TabItem đại diện cho một nhân viên và trong mỗi nhân viên này, Tab có một số khác là TabControl có chứa thêm TabItem s. Những TabItem s đại diện cho các thư mục Outlook cho nhân viên đó (như "Làm việc", "Đã hoàn tất", v.v.). Mỗi thư mục trong số các thư mục TabItem s này chứa ListBox được gắn với một số ObservableCollection của MailItem s liên quan đến thư mục Outlook đó. Đây không phải là những bộ sưu tập khổng lồ - chỉ có một tá hoặc nhiều mặt hàng trên mỗi ListBox. Mặc dù, tổng cộng, trên tất cả các TabItem s có thể hình dung được 100 mục hoặc hơn.Bí quyết tạo giao diện người dùng WPF đáp ứng khi điền nhiều ListBox là gì?

Cách tôi hiện đang xây dựng ứng dụng là ứng dụng sẽ kích hoạt và điền vào màn hình với các tab và tab phụ của nhân viên thích hợp. Quá trình này khá nhanh và tôi rất vui. Tôi đã tạo ra một Static Global.System.Timer rằng tất cả thư mục của mã sau TabItem được đồng bộ với. Vì vậy, cứ sau 5 phút ứng dụng sẽ xóa tất cả ObserverableCollection và quét lại các thư mục Outlook.

Vấn đề là quá trình quét sẽ khiến ứng dụng ngừng hoạt động. Tôi đã cố gắng sử dụng một BackgroundWorker để thu thập email từ Outlook như một quá trình nền, sau đó vượt qua một đối tượng List<MailItem> đến một phương pháp RunWorkerCompleted rằng sau đó chạy một quá trình this.Dispatcher.BeginInvoke mà xóa tương ứng ObservableCollection sau đó thêm các mục từ List<MailItem> trở lại ObservableCollection. Tôi thậm chí đã đặt số này Dispatcher thành mức độ ưu tiên thấp hơn.

Mặc dù vậy, ứng dụng là cảm giác rất clunky trong quá trình quét/điền. Tôi không rõ ràng về cách thiết kế tốt hơn điều này và tôi thừa nhận tôi có phần mới với điều này. Tôi nhận ra rằng việc xóa từng số ObservableCollection s không hiệu quả, nhưng các sự kiện thay đổi thư mục Outlook không đáng tin cậy, vì vậy tôi cần quét lại một lần để đảm bảo tất cả các số MailItem được biểu diễn.

Dưới đây là mã của tôi cho điều khiển WPF có chứa ListBox. Hãy nhớ rằng có khoảng 10 trong số các điều khiển ListBox này hoạt động cùng một lúc.

// This entire UserControl is essentially a ListBox control 
public partial class TicketListView : UserControl 
    { 
     private TicketList _ticketList; //this is the ObservableCollection object 
     private Folder _folder;   // Outlook Folder 

     public TicketListView(Folder folder) 
     { 
      InitializeComponent(); 

      _ticketList = this.FindResource("TicketList") as TicketList; 
      _folder = folder; 

      GlobalStatics.Timer.Elapsed += new System.Timers.ElapsedEventHandler(Timer_Elapsed); 
     } 

     private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) 
     { 
      Refresh(); 
     } 

     private void Refresh() 
     { 
      BackgroundWorker worker = new BackgroundWorker(); 

      worker.DoWork += new DoWorkEventHandler(worker_DoWork); 
      worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted); 
      worker.RunWorkerAsync(); 
     } 

     private void worker_DoWork(object sender, DoWorkEventArgs e) 
     { 
      List<MailItem> tickets = new List<MailItem>(); 
      string filter = TicketMonitorStatics.TicketFilter(14); 
      Items items = _folder.Items.Restrict(filter); 

      try 
      { 
       foreach (MailItem mi in items.OfType<MailItem>()) 
       { 
        tickets.Add(mi); 
       } 
      } 
      catch (System.Exception) { } 

      e.Result = tickets; 
     } 

     private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
     { 
      List<MailItem> tickets = e.Result as List<MailItem>; 

      this.Dispatcher.BeginInvoke(new System.Action(delegate 
       { 
        _ticketList.Clear(); 
        PopulateList(tickets); 
       })); 

      BackgroundWorker worker = sender as BackgroundWorker; 
      worker.Dispose(); 
     } 

     private void PopulateList(List<MailItem> ticketList) 
     { 
      foreach (MailItem mi in ticketList) 
      { 
       this.Dispatcher.BeginInvoke(new System.Action(delegate 
        { 
         _ticketList.Add(mi); 
        }), System.Windows.Threading.DispatcherPriority.SystemIdle); 
      } 
     } 
    } 
+0

Có vẻ một chút lẻ bạn đang gặp như vậy vấn đề hiệu suất lớn với dữ liệu nhỏ như vậy, tôi có một ứng dụng tương tự, Tabbed triển vọng mailreader bao gồm các thư mục với tối đa 5000 mặt hàng và điều này không treo UI , Loại 'Timer' là' GlobalStatics.Timer', tôi sử dụng 'Threading.Timer' để loại bỏ nhu cầu của' BackgroundWorker', Có hình ảnh nào liên kết với các mục thư này không? –

+0

Trình xử lý RunWorkerCompleted có chạy trên luồng mà BackgroundWorker đã được tạo không? Nếu đó là trường hợp bạn không cần sử dụng Bộ điều phối để chạy mã trên chuỗi giao diện người dùng vì bạn đã ở trên chuỗi giao diện người dùng. – Andy

Trả lời

1

cho yêu cầu của bạn, đặc biệt trong WPF, bạn không nên sử dụng bộ đếm thời gian hoặc nhân viên nền để duy trì chế độ xem. Thay vào đó, bạn nên thiết kế ứng dụng của mình với mẫu MVVM. MVVM là Mô hình, Chế độ xem và Chế độ xem, nếu có thay đổi trong mô hình, mô hình sẽ cập nhật Mô hình xem và mô hình chế độ xem sẽ cập nhật chế độ xem. Điều này được thực hiện bằng cách kế thừa giao diện "INotifyPropertyChanged".

Đây là một ví dụ đơn giản

XAML phần:

<Window x:Class="SimpleMVVM.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="259" Width="445"> 
    <Grid Margin="0,0,2,-3"> 
     <Button x:Name="button" Content="Button" HorizontalAlignment="Left" Margin="10,33,0,0" VerticalAlignment="Top" Width="75"/> 
     <Label x:Name="label" Content="{Binding Name}" HorizontalAlignment="Left" Margin="103,23,0,0" VerticalAlignment="Top" Width="220" BorderBrush="Black" BorderThickness="1" Height="32" Padding="0"/> 

    </Grid> 
</Window> 

Và Các cs Phần

using System.ComponentModel; 
using System.Windows; 

namespace SimpleMVVM 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     private AnimalViewModel _animal= new AnimalViewModel(); 

     public MainWindow() 
     { 
      InitializeComponent(); 

      DataContext = _animal; 
      button.Click += (sender, e) => _animal.Name = "Taylor" ; 
     } 
    } 

    public class AnimalViewModel : AnimalModel 
    { 
     public AnimalViewModel() 
     { 
     }   
    } 

    public class AnimalModel : INotifyPropertyChanged 
    { 
     private string _name; 

     public event PropertyChangedEventHandler PropertyChanged; 

     public string Name 
     { 
      get { return _name; } 
      set 
      { 
       if (_name != value) 
       { 
        _name = value; 
        OnPropertyChanged("Name"); 
       } 
      } 
     } 

     private void OnPropertyChanged(string propertyName) 
     { 
      if (PropertyChanged != null) 
      { 
       PropertyChangedEventArgs args = new PropertyChangedEventArgs(propertyName); 
       PropertyChanged(this, args); 
      } 
     } 
    } 

} 

Không tưởng tượng rằng các nút bấm là bản cập nhật kích hoạt bởi scheduler, bạn mô hình được cập nhật đầu tiên kích hoạt sự kiện đã thay đổi thuộc tính để cập nhật chế độ xem.

Sử dụng mẫu này mã của bạn sẽ đáng tin cậy hơn nhiều.

Tôi hy vọng điều này sẽ hữu ích.

Trân Jegan

+0

Ehh. Viewmodel của bạn ở đâu? Tôi chỉ thấy chế độ xem và mô hình. –

+0

Mã đã được chỉnh sửa như bạn đã chỉ ra! – Jegan

+0

Mã của bạn là ổn, nhưng tôi không chắc chắn nếu bạn có thể gọi nó là MVMC. Tôi đã không bao giờ nhìn thấy VM kế thừa từ M –

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