我有基于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);
}
}
}
答案 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>