2011-03-28 46 views
3

我是WPF世界中的新手,我試圖根據MVVM設計模式實現應用程序。在使用treeviews時我遇到了一些問題。用不同的源分組樹視圖

My Model是具有以下屬性的日誌消息(來自不同應用程序)的列表:消息,嚴重性,應用程序。我有一個包含6個屬於兩個不同應用程序的集合。我希望我的樹視圖如下所示:

應用一個
       錯誤
               第一個錯誤消息(AAA)
               二錯誤信息(bbb)
       警告
               第一警告消息(CCC)
應用B
       警告
               第一警告消息(DDD)
       信息
               首先Info消息(EEE)
               二Info消息(FFF)

我現在的理解是,預計將有一個項目與兒童的名單,所以爲了創建我想要的視圖,我需要創建一個包含字符串(應用程序名稱)的列表以及包含子項列表(顯示消息)的子項列表(不同嚴重級別)。

這對我來說沒有意義,因爲我在View和Model之間創建了一個依賴關係,假設將來我需要添加另一個層次結構層,我將需要更改我的數據結構以便支持它。

有沒有辦法只使用一個不同分組的列表?

謝謝。

回答

1

在邏輯意義上,您將不得不創建一個視圖,這將創建分層數據模板所需的嵌套。如果我的理解正確,則表示您的應用程序收到日誌事件的時間表。

如果您不想改變基本集合(adapted from this post),您可以利用一些嵌套的CollectionViewSource s嵌套TreeView。不過,我不知道這是否會尊重網上更新到底層集合我已經決定是對數據上下文屬性Messages

<!-- First level grouping on the application name --> 
<CollectionViewSource x:Key="ApplicationGroups" 
         Source="{Binding Messages}"> 
    <CollectionViewSource.GroupDescriptions> 
     <PropertyGroupDescription PropertyName="Application" /> 
    </CollectionViewSource.GroupDescriptions> 
</CollectionViewSource> 

然後你設置爲應用程序和嚴重性級別的模板:

<HierarchicalDataTemplate x:Key="ApplicationTemplate"> 
    <!-- Nested tree view for the severity --> 
    <TreeView> 
     <TreeView.Resources> 
      <!-- Since this TreeView will receive a Group as its DataContext 
       we will bind to its Items property, containing the objects 
       which are a member of its group 
      --> 
      <CollectionViewSource x:Key="SeverityGroups" 
            Source="{Binding Items}"> 
       <CollectionViewSource.GroupDescriptions> 
        <PropertyGroupDescription PropertyName="Severity" /> 
       </CollectionViewSource.GroupDescriptions> 
      </CollectionViewSource> 

      <!-- Message Template --> 
      <DataTemplate x:Key="MessageTemplate"> 
       <TextBlock Text="{Binding Message}" /> 
      </DataTemplate> 

      <!-- Severity Hierarchy Template --> 
      <HierarchicalDataTemplate x:Key="SeverityTemplate" 
             ItemsSource="{Binding Items}" 
             ItemsTemplate="{StaticResource MessageTemplate}"> 
       <TextBlock Text="{Binding Name}" /> 
      </HierarchicalDataTemplate> 
     </TreeView.Resources> 

     <!-- Application sub-Tree View --> 
     <TreeViewItem Header="{Binding Name}" 
         ItemsSource="{Binding Groups, Source={StaticResource SeverityGroups}}" 
         ItemTemplate="{StaticResource SeverityTemplate}" /> 
    </TreeView> 
</HierarchicalDataTemplate> 

然後你有你的TreeView設置其ItemsSource以集合視圖的Groups財產,像這樣:

<TreeView ItemsSource="{Binding Groups, Source={StaticResource ApplicationGroups}}" 
      ItemTemplate="{StaticResource ApplicationTemplate}" /> 

通常,不是經歷這個麻煩,我會創建一個翻譯層,轉換爲自然的ViewModel層次結構,但是,如果您的嚴重性級別可能發生變化,這可能是一個更好的選擇。

一些商業數據網格解決方案爲嵌套分組提供了很好的靈活性,但是我沒有足夠的經驗來推薦一個。

+0

這是一個很好的方法。有關更多信息,您可能還需要查看Bea的博客(http://bea.stollnitz.com/blog/?p=18),該博客更詳細地討論了CollectionViewSource。 – 2011-03-28 20:47:14

+1

這看起來過於複雜,似乎沒有使用HierarchicalDatatemplates的遞歸性質。 – 2011-03-28 21:10:43

+0

@ H.B .:在查看你的答案後,我同意。我很少使用'CollectionViewSource',顯然它顯示:) – user7116 2011-03-28 21:35:14

3

您可以輕易地將你用一CollectionView數據,即使在嵌套方式:

ObservableCollection<LogEntry> data = new ObservableCollection<LogEntry>(new LogEntry[] 
{ 
    new LogEntry("App1", "Warning", "Msg1"), 
    new LogEntry("App1", "Error", "Msg2"), 
    new LogEntry("App1", "Warning", "Msg3"), 
    new LogEntry("App2", "Error", "Msg4"), 
    new LogEntry("App2", "Info", "Msg5"), 
    new LogEntry("App2", "Info", "Msg6"), 
}); 
ListCollectionView view = (ListCollectionView)CollectionViewSource.GetDefaultView(data); 
view.GroupDescriptions.Add(new PropertyGroupDescription("Application")); 
view.GroupDescriptions.Add(new PropertyGroupDescription("Severity")); 
Data = view; 

(你也可以創建XAML中的CollectionView看來,這只是一個例子)

現在你可顯示此使用DataTemlates:

<TreeView ItemsSource="{Binding Data.Groups}"> 
    <TreeView.Resources> 
     <HierarchicalDataTemplate DataType="{x:Type CollectionViewGroup}" ItemsSource="{Binding Items}"> 
      <TextBlock Text="{Binding Name}"/> 
     </HierarchicalDataTemplate> 
     <DataTemplate DataType="{x:Type local:LogEntry}"> 
      <TextBlock Text="{Binding Message}"/> 
     </DataTemplate> 
    </TreeView.Resources> 
</TreeView> 

看起來像這樣:
http://i52.tinypic.com/xeeut5.png

+0

+1,比我的更簡單的方法。在這些情況下,我經常使用BindableLinq。 – user7116 2011-03-28 21:35:37

+0

@sixlettervariables謝謝;實際上我從來沒有在我的任何應用程序中使用過'CollectionViews',我在第一次遇到這個問題時遇到了這個問題,這是我第二次使用它:)從未使用過'BindableLinq',但如果您使用大量數據,它確實聽起來很有趣且有用。 – 2011-03-28 21:44:47