2015-02-11 54 views
0

我需要一個TreeView來表示存儲在SQL Server CE數據庫中的多個表的一些分層數據。之前,數據存儲在xml中,在啓動時很簡單的反序列化,一切都很好。現在我被要求將數據移動到數據庫,並且遇到了幾個問題。如何在延遲加載的WPF MVVM TreeView中搜索?

我的第一個問題是,從數據庫中檢索多個項目並從這些項目構建一個TreeView ViewModel需要相當長的時間(仍然不確定什麼是更長的時間 - 獲取項目或構建此樹)。所以我實現了延遲加載,現在只有在TreeViewItem正在擴展時我纔會收到項目。

現在,我需要對所有節點執行文本搜索,但要使其工作,必須加載所有節點。 我試圖加載所有這些,但樹加載時UI凍結。在BackgroundWorker內部執行此操作對我來說也是不可能的,因爲這些項目存儲在ObservableCollection中,我得到「InvalidOperationException」。使用Dispatcher有助於此,但它也凍結UI ...

從我的TreeViewItem虛擬機的摘錄如下,如果需要更多的代碼,請讓我知道。也許我對我的設計完全錯誤,所以任何意見都非常感謝!

public class TreeViewItemViewModel: DisplayableItem, IItemsHost 
    { 
     internal static DummyTreeViewItemViewModel _dummy = new DummyTreeViewItemViewModel(); 

     public TreeViewItemViewModel(){} 

     public TreeViewItemViewModel(IDisplayableItem displayableItem) 
     { 
      Data = displayableItem; 
     } 

     public TreeViewItemViewModel(IDisplayableItem displayableItem, IDisplayableItem parent) 
      :this(displayableItem) 
     { 
      Parent = parent as TreeViewItemViewModel; 
     } 

     private TreeViewItemViewModel _parent; 
     public TreeViewItemViewModel Parent 
     { 
      get { return _parent; } 
      set { _parent = value; InvokePropertyChanged(new PropertyChangedEventArgs("Parent")); } 
     } 

     private IDisplayableItem _data; 
     public new IDisplayableItem Data 
     { 
      get { return _data; } 
      set { _data = value; InvokePropertyChanged(new PropertyChangedEventArgs("Data")); } 
     } 

     private bool _isSelected; 
     public new bool IsSelected 
     { 
      get { return _isSelected; } 
      set { _isSelected = value; InvokePropertyChanged(new PropertyChangedEventArgs("IsSelected")); } 
     } 

     private bool _isEnabled=true; 
     public new bool IsEnabled 
     { 
      get { return _isEnabled; } 
      set { _isEnabled = value; InvokePropertyChanged(new PropertyChangedEventArgs("IsEnabled")); } 
     } 

     private bool _isVisible = true; 
     public new bool IsVisible 
     { 
      get { return _isVisible; } 
      set { _isVisible = value; InvokePropertyChanged(new PropertyChangedEventArgs("IsVisible")); } 
     } 

     private void FillItems() 
     { 
      if (Items.Contains(_dummy)) 
      { 
       Items.Remove(_dummy); 
       var itemshost = Data as IItemsHost; 
       if (itemshost != null) 
       { 
        _items = new ObservableCollection<IDisplayableItem>(); 
        foreach (var item in itemshost.Items)//getting 'Items' actually requesting them from a database 
        { 
         var treeItem = new TreeViewItemViewModel(item, this); 
         _items.Add(treeItem); 
        } 
        InvokePropertyChanged(new PropertyChangedEventArgs("Items")); 
       } 
      } 
     } 

     protected bool _isExpanded; 
     public bool IsExpanded 
     { 
      get { return _isExpanded; } 
      set 
      { 
       if(value) 
       { 
        FillItems(); 
       } 
       _isExpanded = value; 
       InvokePropertyChanged(new PropertyChangedEventArgs("IsExpanded"));    
      } 
     } 

     protected SObservableCollection<IDisplayableItem> _items = new SObservableCollection<IDisplayableItem>(); 
     public SObservableCollection<IDisplayableItem> Items 
     { 
      get 
      { 
       var itemshost = Data as IItemsHost; 
       if (itemshost != null) 
       { 
        if (_items.Count == 0 && itemshost.Items.Count > 0) 
         _items.Add(_dummy); 
       } 
       return _items; 
      } 
      set { _items = value; InvokePropertyChanged(new PropertyChangedEventArgs("Items")); } 
     } 

更新:對於那些誰也尋找一個類似的解決方案 - 我的問題是在我的查詢方法。每當我需要執行查詢時,我都不應該打開新的SQL Server CE連接...

回答

2

如何保存整個層次結構的扁平表示並讓您的搜索邏輯查詢此表的新數據庫表?當你插入/更新/刪除其他表中的記錄時,顯然需要保持這張表更新。

新表格中的每條記錄都需要包含有關項目在層次結構中的位置的一些信息,以便當您返回搜索結果時,只能加載並填充包含「匹配」的樹節點。

0

由於從數據庫中讀取數據庫是異步完成的,所以性能瓶頸應該從ViewModel構建View。我建議以下方法:

  1. 從數據庫中讀取所有必要的模型數據在一個異步調用,並將它們存儲在一個名爲SearchHelper的對象。
  2. 向您創建的每個ViewModel添加一個簡單屬性(Model.Id或Model的哈希碼),以便查找特定模型的等效視圖模型。
  3. 創建只有可見ViewModels。 (僅適用於ViewModel的延遲加載)
  4. 使用SearchHelper查找搜索查詢的匹配項,然後使用結果的Id或哈希代碼,可以輕鬆找到它們的等效視圖模型。

請考慮:

  1. 一旦加載,SearchHelper不更新自身,所以你可能需要手動更新。
  2. 要使此方法具有最佳性能,請嘗試避免迭代所有節點。相反,存儲跟蹤項目的序列(它們的索引或Id)以便在視圖模型中查找它們。如果每個模型項目都知道它的父項,那麼回溯應該很容易。
+0

我已經使用'System.Diagnostics.Stopwatch'做了一個簡單的測試,發現即使不使用視圖(在控制檯應用程序中),迭代所有樹項目和子項目需要大約30秒,並填充它們全部。這不好,但我不知道該怎麼做這:( – lena 2015-02-12 07:25:34