2014-03-14 37 views
0

我有一個基於TreeView自定義控件,需要添加到基於TreeViewItemCheckBox綁定到CheckedTreeViewItem.IsEnabled財產我CheckedTreeViewItem添加複選框。 我嘗試添加CheckBoxTreeView.ItemTemplate,但如果這樣寫:如何在CustomControl基於WPF的TreeView

<TreeView.ItemTemplate> 
    <HierarchicalDataTemplate> 
     <CheckBox IsChecked="{Binding Path=IsSelected,Mode=TwoWay}" Name="ItemCheckBox" Content="{TemplateBinding ContentPresenter.Content}" VerticalAlignment="Center"/> 
    </HierarchicalDataTemplate> 
</TreeView.ItemTemplate> 

CheckBox只出現在第一CheckedTreeViewItem。如果我寫這樣的

但中只有複選框可見。

更新:對不起,沒有添加代碼,我現在不是說這是如此重要。我用CheckedObjects邏輯編寫TreeView,因爲我無法在我的項目中將我的對象包裹在ViewModel中。我已經用該邏輯編寫了ListBox,對我來說非常有用。

XAML:

<TreeView x:Class="TestControlsLibrary.CheckedTreeView" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:testControlsLibrary="clr-namespace:TestControlsLibrary" 
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"> 
    <!-- Need specify that for each CheckedTreeViewItem need draw CheckBox, with possibility to use DisplayMemberPath for content in item--> 
</TreeView> 

後臺代碼:

public partial class CheckedTreeView : TreeView 
    { 
    public CheckedTreeView() 
    { 
     InitializeComponent(); 
    } 

    public static readonly DependencyProperty CheckedItemsProperty; 
    public static readonly RoutedEvent CheckedChangedEvent; 
    public static readonly RoutedEvent ItemCheckedEvent; 
    public static readonly RoutedEvent ItemUnCheckedEvent; 
    public static readonly RoutedEvent CheckedItemsChangedEvent; 

    static CheckedTreeView() 
    { 
     CheckedItemsProperty = DependencyProperty.Register("CheckedItems", typeof (IEnumerable), typeof (CheckedTreeView), 
     new FrameworkPropertyMetadata(new ArrayList(), new PropertyChangedCallback(OnCheckedItemsChanged))); 
     CheckedChangedEvent = EventManager.RegisterRoutedEvent("CheckedChanged", RoutingStrategy.Bubble, 
     typeof (RoutedPropertyChangedEventHandler<bool>), typeof (CheckedTreeViewItem)); 
     ItemCheckedEvent = EventManager.RegisterRoutedEvent("ItemChecked", RoutingStrategy.Bubble, 
     typeof (RoutedPropertyChangedEventHandler<object>), typeof (CheckedTreeView)); 
     ItemUnCheckedEvent = EventManager.RegisterRoutedEvent("ItemUnChecked", RoutingStrategy.Bubble, 
     typeof (RoutedPropertyChangedEventHandler<object>), typeof (CheckedTreeView)); 
     CheckedItemsChangedEvent = EventManager.RegisterRoutedEvent("CheckedItemsChanged", RoutingStrategy.Bubble, 
     typeof (RoutedPropertyChangedEventHandler<IEnumerable>), typeof (CheckedTreeView)); 
     EventManager.RegisterClassHandler(typeof (CheckedTreeView), CheckedTreeViewItem.CheckedEvent, 
     new RoutedEventHandler(checkedEventHandler)); 
     EventManager.RegisterClassHandler(typeof (CheckedTreeView), CheckedTreeViewItem.UnCheckedEvent, 
     new RoutedEventHandler(unCheckedEventHandler)); 
    } 

    private static void checkedEventHandler(object sender, RoutedEventArgs e) 
    { 
     var checkedTreeView = (CheckedTreeView) sender; 
     var item = (CheckedTreeViewItem) e.OriginalSource; 
     var collection = checkedTreeView.CheckedItems; 
     collection.Add(checkedTreeView.Items); 
     checkedTreeView.CheckedItems = new ArrayList(collection); 
    } 

    private static void unCheckedEventHandler(object sender, RoutedEventArgs e) 
    { 
     var checkedTreeView = (CheckedTreeView) sender; 
     var item = (CheckedTreeViewItem) e.OriginalSource; 
     var collection = checkedTreeView.CheckedItems; 
     collection.Remove(item.Items); 
     checkedTreeView.CheckedItems = new ArrayList(collection); 
    } 


    public event RoutedPropertyChangedEventHandler<IEnumerable> CheckedItemsChanged 
    { 
     add { AddHandler(CheckedItemsChangedEvent, value); } 
     remove { RemoveHandler(CheckedItemsChangedEvent, value); } 
    } 

    public event RoutedPropertyChangedEventHandler<object> ItemChecked 
    { 
     add { AddHandler(ItemCheckedEvent, value); } 
     remove { RemoveHandler(ItemCheckedEvent, value); } 
    } 

    public event RoutedPropertyChangedEventHandler<object> ItemUnChecked 
    { 
     add { AddHandler(ItemUnCheckedEvent, value); } 
     remove { RemoveHandler(ItemUnCheckedEvent, value); } 
    } 

    public IEnumerable CheckedItems 
    { 
     get { return (IEnumerable) GetValue(CheckedItemsProperty); } 
     set { SetValue(CheckedItemsProperty, value); } 
    } 

    private static void OnCheckedItemsChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 
    { 
     var checkedTreeView = (CheckedTreeView) sender; 
     var args = new RoutedPropertyChangedEventArgs<IEnumerable>((IEnumerable) e.OldValue, (IEnumerable) e.NewValue); 
     args.RoutedEvent = CheckedTreeView.CheckedItemsChangedEvent; 
     checkedTreeView.RaiseEvent(args); 
    } 

    protected override bool IsItemItsOwnContainerOverride(object item) 
    { 
     return (item is CheckedTreeViewItem); 
    } 

    protected override DependencyObject GetContainerForItemOverride() 
    { 
     return new CheckedTreeViewItem(); 
    } 
    } 

    public class CheckedTreeViewItem : TreeViewItem 
    { 
    public static DependencyProperty IsCheckedProperty; 
    public static readonly RoutedEvent CheckChangedEvent; 
    public static readonly RoutedEvent CheckedEvent; 
    public static readonly RoutedEvent UnCheckedEvent; 

    public bool? IsChecked 
    { 
     get { return (bool?) GetValue(IsCheckedProperty); } 
     set { SetValue(IsCheckedProperty, value); } 
    } 

    public event RoutedPropertyChangedEventHandler<bool> CheckChanged 
    { 
     add { AddHandler(CheckChangedEvent, value); } 
     remove { RemoveHandler(CheckChangedEvent, value); } 
    } 


    static CheckedTreeViewItem() 
    { 
     IsCheckedProperty = DependencyProperty.Register("IsChecked", typeof (bool?), typeof (CheckedTreeViewItem), 
     new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnCheckChanged))); 
     CheckChangedEvent = EventManager.RegisterRoutedEvent("CheckChanged", RoutingStrategy.Bubble, 
     typeof (RoutedPropertyChangedEventHandler<bool>), typeof (CheckedTreeViewItem)); 
     CheckedEvent = EventManager.RegisterRoutedEvent("Checked", RoutingStrategy.Bubble, typeof (RoutedEventHandler), 
     typeof (CheckedTreeViewItem)); 
     UnCheckedEvent = EventManager.RegisterRoutedEvent("UnChecked", RoutingStrategy.Bubble, typeof (RoutedEventHandler), 
     typeof (CheckedTreeViewItem)); 
    } 

    private static void OnCheckChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 
    { 
     var CheckedTreeViewItem = (CheckedTreeViewItem) sender; 
     var oldValue = (bool?) e.OldValue; 
     var newValue = (bool?) e.NewValue; 
     if ((bool) e.NewValue && !(bool) e.OldValue) 
     { 
     var argch = new RoutedEventArgs(CheckedTreeViewItem.CheckedEvent); 
     CheckedTreeViewItem.RaiseEvent(argch); 
     } 
     else if (!(bool) e.NewValue && (bool) e.OldValue) 
     { 
     var argun = new RoutedEventArgs(CheckedTreeViewItem.UnCheckedEvent); 
     CheckedTreeViewItem.RaiseEvent(argun); 
     } 
     var args = new RoutedPropertyChangedEventArgs<bool?>(oldValue, newValue); 
     args.RoutedEvent = CheckedTreeViewItem.CheckChangedEvent; 
     CheckedTreeViewItem.RaiseEvent(args); 
    } 

    private static IEnumerable<CheckedTreeViewItem> GetListItems(CheckedTreeViewItem treeViewItem) 
    { 
     foreach (var item in treeViewItem.Items) 
     { 
     yield return (CheckedTreeViewItem)treeViewItem.ItemContainerGenerator.ContainerFromItem(item); 
     } 
    } 


    private void SetIsChecked(bool? value, bool updateChildren, bool updateParent) 
    { 
     if (value == IsChecked) 
     return; 

     IsChecked = value; 

     if (updateChildren && IsChecked.HasValue) 
     GetListItems(this).ToList().ForEach(c => c.SetIsChecked(IsChecked, true, false)); 

     if (updateParent && this.Parent != null) 
     (this.Parent as CheckedTreeViewItem).VerifyCheckState(); 

    // this.OnPropertyChanged("IsChecked"); 
    } 

    private void VerifyCheckState() 
    { 
     bool? state = null; 
     foreach (var item in GetListItems(this)) 
     { 
     bool? current = item.IsChecked; 
     //if (i == 0) 
     //{ 
     // state = current; 
     //} 
     //else if (state != current) 
     //{ 
     // state = null; 
     // break; 
     //} 
     } 
     this.SetIsChecked(state, false, true); 
    } 
    } 
} 
+0

你不需要覆蓋樹型視圖的'Template'。你爲什麼這樣做? –

+0

您需要使用CheckBox編寫HierarchicalDataTemplate.ItemTemplate。 –

+0

@RohitVats因爲這段代碼可以很好地處理'ListBox',我仍然可以使用DisplayMemberPath並通過每個ListBoxItem上的CheckBox和Content來獲取所需的視圖。但可能是我走錯了路。 – Nightingale

回答

0

你會發現TreeView更容易的工作,作爲一項規則,如果你把默認DataTemplatesTreeView.Resources(或一些其他適當的資源字典)。

您試圖通過複選框獲得的特定技巧可以通過使用RelativeSource="{RelativeSource AncestorType=TreeViewItem}"來拉動。

我會推薦這樣的事情(我把彌補夫婦啞數據類型的自由):

<TreeView ItemsSource="{Binding Path=Nodes}"> 
     <TreeView.Resources> 
      <HierarchicalDataTemplate DataType="{x:Type local:Folder}" 
             ItemsSource="{Binding Path=Children}"> 
       <StackPanel> 
        <Label Content="{Binding Name}" /> 
        <CheckBox Content="Selected" 
           IsEnabled="False" 
           IsChecked="{Binding RelativeSource={RelativeSource AncestorType=TreeViewItem}, Path=IsSelected, Mode=OneWay}" /> 
       </StackPanel> 
      </HierarchicalDataTemplate> 
      <DataTemplate DataType="{x:Type local:File}"> 
       <StackPanel> 
        <Label Content="{Binding Name}" /> 

        <CheckBox Content="Selected" 
           IsEnabled="False" 
           IsChecked="{Binding RelativeSource={RelativeSource AncestorType=TreeViewItem}, Path=IsSelected, Mode=OneWay}" /> 
       </StackPanel> 
      </DataTemplate> 
     </TreeView.Resources> 
    </TreeView> 
+0

這很有用,但我更新了我的帖子。抱歉。 – Nightingale

+0

對不起。我以爲你試圖在'TreeView.ItemTemplate'上添加一個CheckBox。 – mcwyrm