Made a CheckBoxTreeView by creating a UserControl and change the inheritance from UserControl to TreeView. CheckBoxTreeView adds the CheckedItems ObservableCollection.
The sorting arrows could be better locking but they are from msdn..
Here is an example where the Control to the left is a CheckBoxTreeView and the ListBox to the right is using CheckBoxTreeView.CheckedItems as ItemsSource.
c_listBox.ItemsSource = c_treeView.CheckedItems;
It can be used from Xaml like this.
<Window x:Class="CheckBoxTreeViewItems.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:CheckBoxTreeView"
Title="MainWindow"
Height="350"
Width="525">
<Window.Resources>
<HierarchicalDataTemplate x:Key="Level1" ItemsSource="{Binding Path=CheckedItems}">
<TextBlock Text="{Binding Path=Name}"/>
</HierarchicalDataTemplate>
</Window.Resources>
<StackPanel Orientation="Horizontal">
<c:CheckBoxTreeView x:Name="c_treeView"
ItemTemplate="{StaticResource Level1}"/>
<ListBox Name="c_listBox"
DisplayMemberPath="Name"
ItemsSource="{Binding ElementName=c_treeView, Path=CheckedItems}"/>
<Button />
</StackPanel>
</Window>
CheckBoxTreeView.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
namespace CheckBoxTreeView
{
/// <summary>
/// Interaction logic for CheckBoxTreeView.xaml
/// </summary>
public partial class CheckBoxTreeView : TreeView
{
public static DependencyProperty CheckedItemsProperty;
static CheckBoxTreeView()
{
CheckedItemsProperty = DependencyProperty.Register("CheckedItems", typeof(ObservableCollection<object>), typeof(CheckBoxTreeView));
}
public ObservableCollection<object> CheckedItems
{
get
{
return (ObservableCollection<object>)base.GetValue(CheckedItemsProperty);
}
set
{
base.SetValue(CheckedItemsProperty, value);
}
}
public CheckBoxTreeView() : base()
{
InitializeComponent();
CheckedItems = new ObservableCollection<object>();
}
public T GetVisualParent<T>(object childObject) where T : Visual
{
DependencyObject child = childObject as DependencyObject;
// iteratively traverse the visual tree
while ((child != null) && !(child is T))
{
child = VisualTreeHelper.GetParent(child);
}
return child as T;
}
private void c_isCheckedCheckBox_Checked(object sender, RoutedEventArgs e)
{
CheckBox checkBox = sender as CheckBox;
TreeViewItem treeViewItem = GetVisualParent<TreeViewItem>(checkBox);
object checkedItem = treeViewItem.Header;
CheckedItems.Add(checkedItem);
}
private void c_isCheckedCheckBox_Unchecked(object sender, RoutedEventArgs e)
{
CheckBox checkBox = sender as CheckBox;
TreeViewItem treeViewItem = GetVisualParent<TreeViewItem>(checkBox);
object unCheckedItem = treeViewItem.Header;
CheckedItems.Remove(unCheckedItem);
}
}
}
CheckBoxTreeView.xaml
<TreeView x:Class="CheckBoxTreeView.CheckBoxTreeView"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<TreeView.Resources>
<SolidColorBrush x:Key="GlyphBrush" Color="#444"/>
<LinearGradientBrush x:Key="NormalBrush" EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#EEE" Offset="0.0"/>
<GradientStop Color="#CCC" Offset="1.0"/>
</LinearGradientBrush>
<Style x:Key="TreeViewItemFocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ExpandCollapseToggleStyle" TargetType="{x:Type ToggleButton}">
<Setter Property="Focusable" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border Background="Transparent" Padding="5,0,0,0">
<StackPanel Orientation="Horizontal">
<Rectangle x:Name="Rectangle"
Margin="0,0,0,0"
Fill="Transparent"
Stroke="{DynamicResource NormalBorderBrush}" />
<Path x:Name="ExpandPath"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Margin="1,1,1,1"
Fill="{StaticResource GlyphBrush}"
Data="M 2 0 L 6 4 L 2 8 Z"/>
</StackPanel>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="False"/>
<Trigger Property="IsMouseOver" Value="True"/>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Data" TargetName="ExpandPath"
Value="M -2 -2 L 6 -2 L 2 2 Z"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
<Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
<Setter Property="Padding" Value="1,0,0,0"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="FocusVisualStyle" Value="{StaticResource TreeViewItemFocusVisual}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TreeViewItem}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="15" Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" MinHeight="15"/>
<RowDefinition/>
</Grid.RowDefinitions>
<ToggleButton x:Name="Expander" ClickMode="Press" IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource ExpandCollapseToggleStyle}"/>
<Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Column="1" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
<StackPanel Orientation="Horizontal">
<CheckBox Margin="0,2,4,0" x:Name="c_isCheckedCheckBox" IsChecked="False" Checked="c_isCheckedCheckBox_Checked" Unchecked="c_isCheckedCheckBox_Unchecked"/>
<ContentPresenter x:Name="PART_Header" ContentSource="Header" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</StackPanel>
</Border>
<ItemsPresenter x:Name="ItemsHost" Grid.ColumnSpan="2" Grid.Column="1" Grid.Row="1"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="false">
<Setter Property="Visibility" TargetName="ItemsHost" Value="Collapsed"/>
</Trigger>
<Trigger Property="HasItems" Value="false">
<Setter Property="Visibility" TargetName="Expander" Value="Hidden"/>
</Trigger>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true"/>
<Condition Property="IsSelectionActive" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
</MultiTrigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="VirtualizingStackPanel.IsVirtualizing" Value="true">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<VirtualizingStackPanel/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</TreeView.Resources>
</TreeView>