HandyControl
HandyControl copied to clipboard
有没有做一个下拉树ComboTreeBox的计划?
Hi 🖐,
There is no option in HandyControl to do this but I have quickly made a control by myself that you can based on, waiting that this feature appear in HandyControl 😉 You can find the little project with the control here : Wpf Test TreeComboBox.zip
Screen of the control
Here there is a resume of the control. If you want to replicate it you can just create a UserControl TreeComboBox and replace the code by mine (It was quickly made so it is not perfect, wait for @NaBian to make a better one 😄 ) :
TreeComboBox.xaml :
<TreeView x:Class="Wpf_Test.TreeComboBox"
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:hc="https://handyorg.github.io/handycontrol"
xmlns:local="clr-namespace:Wpf_Test"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<TreeView.Template>
<ControlTemplate TargetType="TreeView">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="30"/>
</Grid.ColumnDefinitions>
<ToggleButton x:Name="toggleButton"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
IsChecked="{Binding IsPopupOpen,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}"
Style="{StaticResource ComboBoxToggleButton}"
Grid.ColumnSpan="2"/>
<Border Grid.Column="0" Margin="5,0">
<ContentPresenter Margin="{TemplateBinding Padding}" Content="{TemplateBinding SelectedItem}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" IsHitTestVisible="false" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
<Popup PlacementTarget="{Binding ElementName=toggleButton}"
StaysOpen="False"
IsOpen="{Binding IsPopupOpen,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}"
AllowsTransparency="true"
PopupAnimation="{StaticResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}"
Placement="Bottom">
<Border Effect="{StaticResource EffectShadow2}"
Width="{TemplateBinding Width}"
BorderThickness="0,1,0,0"
Margin="0,0,0,8"
CornerRadius="{Binding Path=(hc:BorderElement.CornerRadius),RelativeSource={RelativeSource TemplatedParent}}"
x:Name="dropDownBorder"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}">
<ItemsPresenter />
</Border>
</Popup>
</Grid>
</ControlTemplate>
</TreeView.Template>
</TreeView>
TreeComboBox.xaml.cs :
using System.Windows;
using System.Windows.Controls;
namespace Wpf_Test
{
/// <summary>
/// Logique d'interaction pour TreeComboBox.xaml
/// </summary>
public partial class TreeComboBox : TreeView
{
public static readonly DependencyProperty IsPopupOpenProperty = DependencyProperty.Register("IsPopupOpen", typeof(bool), typeof(TreeComboBox), new PropertyMetadata(false));
public bool IsPopupOpen { get; set; }
public TreeComboBox()
{
InitializeComponent();
}
}
}
And if you want to integrate it, because there is not "default" itemTemplate you need to create one :
MainWindow.xaml :
<Window x:Class="Wpf_Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Wpf_Test"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800"
Background="Black">
<Window.Resources>
<Style x:Key="TreeComboBoxBaseStyle" TargetType="local:TreeComboBox" BasedOn="{StaticResource TreeViewBaseStyle}">
<Setter Property="Background" Value="{StaticResource RegionBrush}"/>
<Setter Property="BorderBrush" Value="{StaticResource BorderBrush}"/>
<Setter Property="Width" Value="300"/>
<Setter Property="Height" Value="30"/>
</Style>
</Window.Resources>
<Grid>
<StackPanel>
<TextBlock Text="{Binding SelectedItem.Name, StringFormat={}{0} is selected}"
Foreground="White"
HorizontalAlignment="Center"
Margin="5"/>
<local:TreeComboBox ItemsSource="{Binding MyTree}"
Style="{StaticResource TreeComboBoxBaseStyle}"
SelectedItemChanged="TreeComboBox_SelectedItemChanged">
<local:TreeComboBox.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:MyTreeItem}"
ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
</local:TreeComboBox.ItemTemplate>
</local:TreeComboBox>
</StackPanel>
</Grid>
</Window>
and the MainWindow.xaml.cs :
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
namespace Wpf_Test
{
/// <summary>
/// Logique d'interaction pour MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
public List<MyTreeItem> MyTree { get; set; }
public MyTreeItem SelectedItem { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
public MainWindow()
{
InitializeComponent();
DataContext = this;
MyTree = new List<MyTreeItem>();
List<MyTreeItem> genericChildren = new List<MyTreeItem>();
for (int i = 0; i < 4; i++)
genericChildren.Add( new MyTreeItem($"Item {i}"));
MyTreeItem group1 = new MyTreeItem("Group 1");
MyTreeItem group2 = new MyTreeItem("Group 2");
MyTreeItem group3 = new MyTreeItem("Group 3");
group1.Children = genericChildren;
group2.Children = genericChildren;
group3.Children = genericChildren;
MyTree.Add(group1);
MyTree.Add(group2);
MyTree.Add(group3);
}
public void NotifyPropertyChanged(string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private void TreeComboBox_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
SelectedItem = (MyTreeItem)e.NewValue;
NotifyPropertyChanged("SelectedItem");
}
}
public class MyTreeItem
{
public string Name { get; set; }
public List<MyTreeItem> Children { get; set; }
public MyTreeItem(string name)
{
Name = name;
}
public override string ToString()
{
return this.Name;
}
}
}
Hope it will help 😉😊
Update :
I cheat a little bit to show the SelectedItem in the ComboBox
(ContentPresenter
) because I override ToString()
of MyTreeItem
. But there is a better way, use the SelectedValuePath
.
<local:TreeComboBox x:Name="MyTreeComboBox"
ItemsSource="{Binding MyTree}"
Style="{StaticResource TreeComboBoxBaseStyle}"
SelectedItemChanged="TreeComboBox_SelectedItemChanged"
SelectedValuePath="Name">
<local:TreeComboBox.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:MyTreeItem}"
ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
</local:TreeComboBox.ItemTemplate>
</local:TreeComboBox>
and in the TreeComboBox Control :
...
<Border Grid.Column="0" Margin="5,0">
<ContentPresenter ... Content="{TemplateBinding SelectedValue}" ... />
</Border>
...
万分感谢!!!!