2013-02-14 6 views
5

TabControlに複数のTabItemを表示するサポートツールを開発中です。各TabItemは従業員を表し、これらの従業員Tabの中には、別のTabControlがあり、これにはさらにTabItemが含まれています。これらのTabItemは、その従業員のOutlookフォルダ(「作業中」、「完了済み」など)を表します。これらの各フォルダTabItemには、ObservableCollectionMailItemにバインドされたListBoxが含まれています。このフォルダはOutlookフォルダに関連しています。これらは巨大なコレクションではなく、ListBoxごとに12個ほどのアイテムしかありません。合計で、TabItemには100アイテム程度あると思われます。複数のリストボックスにデータを入力する際のレスポンスWPF UIの作成の秘訣は何ですか?

私が現在アプリケーションを構築しているのは、アプリケーションが起動して、適切な従業員のタブとサブタブが画面に表示されるということです。このプロセスはかなり速く、私は満足しています。私はすべてのフォルダTabItemのコードビハインドが同期されているStatic Global.System.Timerを作成しました。したがって、アプリケーションはすべて5分ごとにObserverableCollectionをすべてクリアし、Outlookフォルダを再スキャンします。

問題は、スキャン処理によってアプリケーションが停止することです。私は、次いで、それぞれObservableCollectionをクリアバックObservableCollectionList<MailItem>への項目を追加this.Dispatcher.BeginInvokeプロセスを実行RunWorkerCompleted方法List<MailItem>オブジェクトを渡し、バックグラウンドプロセスとしてOutlookからメールを収集するBackgroundWorkerを用いて試みました。私はこのDispatcherをより低い優先度に設定しました。

これにもかかわらず、アプリケーションはスキャン中に非常にclunky感じ/人口ListBoxプロセスです。私はこれをよりうまく設計する方法が不明であり、私はこれにいくらか新しいことを認めている。 ObservableCollectionのそれぞれをクリアするのは非効率ですが、Outlookフォルダの変更イベントは特に信頼できるものではないので、すべてMailItemが確実に表示されるようにしばらく毎回再スキャンを実行する必要があります。

以下は、ListBoxを含むWPFコントロール用のコードです。これらのコントロールのうち約10個が同時にアクティブになることに注意してください。

// 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

は点で最大5000 +アイテムとフォルダが含まれ、タブ付きの見通しmailreaderあなたは、このような小さなデータでこのような大きなパフォーマンスの問題を抱えている奇数ビットが、私は同様のアプリを持っているようだし、これは、UIがハングアップしません。どのような 'Timer'が' GlobalStatics.Timer'なのか、 'BackgroundWorker'の必要性を排除する' Threading.Timer'を使用します。これらのメールアイテムに関連する画像もありますか? –

+0

RunWorkerCompletedハンドラは、BackgroundWorkerが作成されたスレッドで実行されませんか?このような場合は、既にUIスレッド上にあるため、Dispatcherを使用してUIスレッドでコードを実行する必要はありません。 – Andy

答えて

1

特に、WPFでは、タイマーまたはバックグラウンドワーカーを使用してビューを応答しないでください。代わりに、MVVMパターンでアプリケーションを設計する必要があります。 MVVMはモデル、ビュー、およびビューモデルです。モデルに変更がある場合、モデルはビューモデルを更新し、ビューモデルはビューを更新します。これは、 "INotifyPropertyChanged"インタフェースを継承することによって行われます。

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

とは.csパート

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

} 

いいえ]ボタンをクリックすると、あなたのモデルスケジューラによってトリガー更新であることを想像する:ここでは

は、一部の簡単な例

XAMLではありませんビューを更新するためにプロパティー変更イベントをトリガーする最初に更新されます。

このパターンを使用すると、コードの信頼性が向上します。

こちらがお役に立てば幸いです。

よろしく Jegan

+0

Ehh。あなたのビューモデルはどこですか?私はビューとモデルのみを参照してください。 –

+0

あなたが指摘したとおりにコードが編集されました! – Jegan

+0

あなたのコードは問題ありませんが、MVMCと呼べるかどうかは分かりません。私はVMがMを継承しているのを見たことがない –

関連する問題