如何在基于treeviewwpf的自定义控件中添加复选框



我有基于TreeView的自定义控件,需要添加到基于TreeViewItemCheckedTreeViewItem, 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上。

如果我这样写:

但是只有复选框可见。

更新:抱歉没有添加代码,我现在不知道这是如此重要。我写TreeView与CheckedObjects逻辑,因为我不能包装我的对象在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);
    }
  }
} 

通常,如果将默认 DataTemplates放在TreeView.Resources(或其他适当的资源字典)中,您会发现TreeView更容易使用。

你想通过复选框获得的特定技巧可以通过使用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>

相关内容

  • 没有找到相关文章

最新更新