2010-03-03 28 views
3

我想數據綁定的TreeView的佈局從:一個TreeView的佈局更改爲貌似多個列表框

alt text http://www.freeimagehosting.net/uploads/776c1333f5.png

要這樣:

alt text http://www.freeimagehosting.net/uploads/99106b4cfd.png

當然,選擇必須正常工作:

alt text http://www.freeimagehosting.net/uploads/8b628758d7.png

你對如何做到這一點有任何想法。我一直在嘗試改變模板,但我找不到一種方法來實現這種行爲。也許一個組件已經存在...

感謝您的幫助!

回答

0

我終於找到了一個辦法,但像你說的查理,它涉及到創建列表框:

  • 我創建了一個新的CustomControl它繼承控制(我不能使用沒有選擇或樹視圖,因爲我不會」 t已經能夠管理派生類中的SelectedItem屬性)
  • 在此CustomControl的模板中是一個ItemsControl。此ItemsControl將其ItemTemplate屬性設置爲包含ListBox的DataTemplate。
  • CustomControl具有類型爲int的Depth屬性。該屬性表示應該生成的ListBox的數量。
  • CustomControl自動將數據綁定在一起的ListBox:每個ListBox的ItemsSource屬性是數據綁定到Visual Tree中前一個ListBox的SelectedItem的children屬性。
  • CustomControl具有SelectedItem屬性和SelectionChanged事件(如Selector派生類)。
  • 我添加了一個IsReallySelected附加屬性到生成的ListBoxItem。這使得能夠使用ListBoxItem的IsSelected對控件後面的ViewModel類的IsSelected屬性進行數據綁定。我不得不創建一個附加屬性,因爲當選擇ListBoxItem並且父列表框的IsSelectionActive設置爲true時,它的值爲true。

我博客瞭解這個解決方案(帶源代碼)on my blog

4

這很難。它似乎需要一個HierarchicalDataTemplate,但因爲你想要的行爲需要多個ItemsControls,它不會按預期工作。我認爲沒有辦法在XAML中創建TreeView模板來執行此操作。您最好的選擇是創建某種自定義項目控件。您可能需要執行代碼中的項目綁定,而不是XAML中的項目綁定,因爲如果沒有XAML,則XAML無法理解嵌套關係。

<Window.Resources> 
    <DataTemplate x:Key="ItemTemplate"> 
     <TextBlock Text="{Binding Name}"/> 
    </DataTemplate> 
</Window.Resources> 

<StackPanel Orientation="Horizontal"> 
    <ListBox Name="Level1" Width="150" Height="150" 
      ItemsSource="{Binding Collection}" 
      ItemTemplate="{StaticResource ItemTemplate}"/> 
    <ListBox Name="Level2" Width="150" Height="150" 
      ItemsSource="{Binding ElementName=Level1, Path=SelectedValue.Children}" 
      ItemTemplate="{StaticResource ItemTemplate}"/> 
    <ListBox Name="Level3" Width="150" Height="150" 
      ItemsSource="{Binding ElementName=Level2, Path=SelectedValue.Children}" 
      ItemTemplate="{StaticResource ItemTemplate}"/> 
</StackPanel> 

哪裏Collection是你的根:

話雖這麼說,如果你保證只有2級嵌套(如你的例子),你可以用下面的加價做到這一點很容易物品集合,並且每個物品上都有一個名爲Children的物品,其中包含子集合。

但我認爲你所要求的是一個項目控件,可以支持任意數量的嵌套級別,而不僅僅是2.所以在這種情況下,我會在代碼隱藏方面做到這一點。綁定將是相同的 - 也就是說,在每個級別上,ListBox應該綁定到父級別的項目。但是您顯然需要迭代併爲每個嵌套級別創建一個ListBox

0

它太糟糕了,我沒有注意到這個問題之前,你去所有的工作。對TreeView進行重新編程很容易出現這種方式:唯一需要的代碼是一個非常簡單的附加屬性「VisibleWhenCurrentOf」。

做到這一點的方法是:

  1. 風格TreeViewItem包括在其ControlTemplate一個ListBoxItemsPresenter之外。

  2. 控制使用「VisibleWhenCurrentOf」,讓一個給定的項目只有ItemsPresenter內可見如果是列表框內當前項目的TreeViewItem模板的知名度。

改型細節

下面是相關模板的XAML:

<ControlTemplate TargetType="TreeView"> 
    <DockPanel> 

    <ListBox 
     ItemsSource="{TemplateBinding ItemsSource}" 
     IsSyncrhonizedWithCurrentItem="true" 
     Style="{DynamicResource BoxesTreeViewBoxStyle}" 
     ItemTemplate="{Binding HeaderTemplate}" 
     ItemTemplateSelector="{Binding HeaderTemplateSelector}" /> 

    <ItemsPresenter /> 
    </DockPanel> 
</ControlTemplate> 

<ControlTemplate TargetType="TreeViewItem"> 
    <DockPanel 
    local:VisibilityHelper.VisibleWhenCurrentOf="{Binding ItemsSource, RelativeSource={RelativeSource FindAncestor,HeaderedItemsControl,2}"> 

    <ListBox 
     ItemsSource="{TemplateBinding ItemsSource}" 
     IsSyncrhonizedWithCurrentItem="true" 
     Style="{DynamicResource BoxesTreeViewBoxStyle}" 
     ItemTemplate="{Binding HeaderTemplate}" 
     ItemTemplateSelector="{Binding HeaderTemplateSelector}" /> 

    <ItemsPresenter /> 
    </DockPanel> 
</ControlTemplate> 

這兩個模板是除有條件的公開程度相同。工作方式是樹項前面的「+」變爲ListBox,除ListBox中選擇的項以外的所有項都被隱藏。

您的BoxesTreeViewBoxStyle應在ListBox周圍設置邊距,以便它們能夠正確放置。實際上,通過將ListBox屬性值放入樣式中可以進一步簡化這一操作,但我發現將它們設置在ControlTemplate中更方便,因此我可以重新設置ListBox而不必記住這些設置。

附加屬性

下面是VisibleWhenCurrentOf附加屬性代碼:

public class VisibilityHelper : DependencyObject 
{ 

    // VisibleWhenCurrentOf 
    public static object GetVisibleWhenCurrentOf(DependencyObject obj) { return (object)obj.GetValue(VisibleWhenCurrentOfProperty); } 
    public static void SetVisibleWhenCurrentOf(DependencyObject obj, object value) { obj.SetValue(VisibleWhenCurrentOfProperty, value); } 
    public static readonly DependencyProperty VisibleWhenCurrentOfProperty = DependencyProperty.RegisterAttached("VisibleWhenCurrentOf", typeof(object), typeof(VisibilityHelper), new UIPropertyMetadata 
    { 
    PropertyChangedCallback = (sender, e) => 
    { 
     var element = sender as FrameworkElement; 
     if(e.OldValue!=null) 
     { 
     var oldView = e.OldValue as ICollectionView ?? CollectionViewSource.GetDefaultView(e.OldValue); 
     oldView.CurrentChanged -= UpdateVisibilityBasedOnCurrentOf; 
     if(e.NewValue==null) element.DataContextChanged -= UpdateVisibilityBasedOnCurrentOf; 
     } 
     if(e.NewValue!=null) 
     { 
     var newView = e.NewValue as ICollectionView ?? CollectionViewSource.GetDefaultView(e.OldValue); 
     newView.CurrentChanged += UpdateVisibilityBasedOnCurrentOf; 
     if(e.OldValue==null) element.DataContextChanged += UpdateVisibilityBasedOnCurrentOf; 
     } 
     UpdateVisibilityBasedOnCurrentOf(sender); 
    } 
    }); 

    static void UpdateVisibilityBasedOnCurrentOf(object sender, DependencyPropertyChangedEventArgs e) { UpdateVisibilityBasedOnCurrentOf(sender); } 
    static void UpdateVisibilityBasedOnCurrentOf(object sender, EventArgs e) { UpdateVisibilityBasedOnCurrentOf(sender); } 
    static void UpdateVisibilityBasedOnCurrentOf(object sender) 
    { 
    var element = sender as FrameworkElement; 

    var source = GetVisibleWhenCurrentOf(element); 
    var view = source==null ? null : source as ICollectionView ?? CollectionViewSource.GetDefaultView(source); 

    var visible = view==null || view.CurrentItem == element.DataContext; 

    element.Visibility = visible ? Visibility.Visible : Visibility.Collapsed; 
    } 

} 

沒有什麼複雜在這裏:任何時候DataContext或視圖的Current變化,公開程度重新計算。 PropertyChangedCallback只是設置事件處理程序來檢測這些條件,並且UpdateVisibiltyBasedOnCurrentOf處理程序重新計算可見性。該解決方案

由於該解決方案的

優勢是一個真正的TreeView:

  1. 你的所有選擇處理功能是免費的。
  2. 它適用於任何數量的樹級別。
  3. 您可以使用HierarchicalDataTemplate所有功能,包括HeaderTemplateHeaderTemplateSelector
  4. 您可以在每個級別使用不同ItemsSource綁定,而不是每次採集要求「孩子」 proerty
  5. 這是少了很多的代碼比定製控制
+0

嗨Ray, 感謝您花時間分享您的解決方案。它看起來比我的自定義控件好多了!然而,我找不到一種方法使其工作......我認爲在附加屬性的代碼中存在拼寫錯誤,但仍然無效。你可以分享一個可下載的檔案嗎? – japf