如何在CustomControl中添加CheckBox基于TreeView Wpf

时间:2014-03-14 07:42:20

标签: c# wpf checkbox treeview itemtemplate

我有基于TreeView的自定义控件,需要根据绑定到CheckedTreeViewItem属性的TreeViewItem CheckBox添加到我的CheckedTreeViewItem.IsEnabled。 我尝试将CheckBox添加到TreeView.ItemTemplate,但如果写下这个:

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

CheckBox仅在第一个CheckedTreeViewItem出现。

如果我这样写:                                                                                                                                                                     

但只有CheckBoxes可见。

更新:很抱歉没有添加代码,我现在不太重要。我用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);
    }
  }
} 

1 个答案:

答案 0 :(得分:0)

如果您将{em>默认 TreeView放在DataTemplates(或其他一些合适的资源词典)中,您会发现TreeView.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>