标签:closed on() bottom lte image rgs protected contain csharp
实现思路:
1.继承ComboBox
2.重写ComboBox的模板,把列表控件替换成树形控件
3.重写SelectedItem, SelectedValue,DisplayMemberPath,SelectedValuePath
效果截图:
XAML代码
<!--TreeSelect普通样式--> <Style x:Key="DefaultTreeSelectStyle" TargetType="{x:Type controls:TreeSelect}"> <Setter Property="Foreground" Value="{DynamicResource TextBrush}" /> <Setter Property="Background" Value="{DynamicResource ControlBackgroundBrush}" /> <Setter Property="HorizontalContentAlignment" Value="Stretch" /> <Setter Property="VerticalContentAlignment" Value="Center" /> <Setter Property="BorderThickness" Value="1" /> <Setter Property="BorderBrush" Value="{DynamicResource TextBoxBorderBrush}" /> <Setter Property="controls:ControlAttachProperty.FocusBackground" Value="Transparent" /> <Setter Property="controls:ControlAttachProperty.FocusBorderBrush" Value="{DynamicResource TextBoxFocusBorderBrush}" /> <Setter Property="controls:ControlAttachProperty.MouseOverBorderBrush" Value="{DynamicResource TextBoxMouseOverBorderBrush}" /> <Setter Property="controls:ControlAttachProperty.PopupBackground" Value="{DynamicResource WhiteBrush}" /> <Setter Property="FontFamily" Value="{DynamicResource ContentFontFamily}" /> <Setter Property="FontSize" Value="{DynamicResource ContentFontSize}" /> <Setter Property="SnapsToDevicePixels" Value="True" /> <Setter Property="MaxDropDownHeight" Value="200" /> <Setter Property="ScrollViewer.CanContentScroll" Value="False" /> <Setter Property="MinHeight" Value="22" /> <Setter Property="Padding" Value="2" /> <Setter Property="ItemTemplate"> <Setter.Value> <HierarchicalDataTemplate ItemsSource="{Binding Children}"> <StackPanel MinHeight="22" Orientation="Horizontal" Background="Transparent" HorizontalAlignment="Left" > <TextBlock Text="{TemplateBinding Content}" VerticalAlignment="Center" HorizontalAlignment="Left"/> </StackPanel> </HierarchicalDataTemplate> </Setter.Value> </Setter> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type controls:TreeSelect}"> <Grid x:Name="PART_Root"> <Border x:Name="Bg" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" /> <Grid x:Name="PART_InnerGrid" Margin="0"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" /> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="21" /> </Grid.ColumnDefinitions> <!--Label区域--> <ContentControl x:Name="Label" Template="{TemplateBinding controls:ControlAttachProperty.LabelTemplate}" IsTabStop="False" IsHitTestVisible="False" Content="{TemplateBinding controls:ControlAttachProperty.Label}" Margin="1,1,0,1"/> <!--附加内容区域--> <Border x:Name="PART_AttachContent" Panel.ZIndex="2" Grid.Column="2" VerticalAlignment="Center" HorizontalAlignment="Center" > <ContentControl VerticalAlignment="Center" VerticalContentAlignment="Center" Template="{TemplateBinding controls:ControlAttachProperty.AttachContent}" /> </Border> <!--下拉按钮--> <ToggleButton x:Name="PART_DropDownToggle" Panel.ZIndex="1" IsTabStop="False" Style="{StaticResource ComboToggleButton}" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Grid.Column="1" Grid.ColumnSpan="3" IsEnabled="{Binding Path=IsReadOnly,RelativeSource={RelativeSource TemplatedParent}, Converter={x:Static controls:XConverter.TrueToFalseConverter},Mode=OneWay}" Margin="2 1 10 1" Background="{TemplateBinding controls:ControlAttachProperty.FocusBackground}"/> <!--水印--> <Border Grid.Column="1"> <TextBlock x:Name="Message" Padding="0" Visibility="Collapsed" Text="{TemplateBinding controls:ControlAttachProperty.Watermark}" Foreground="{TemplateBinding Foreground}" IsHitTestVisible="False" Opacity="0.6" HorizontalAlignment="Left" TextAlignment="Center" VerticalAlignment="Center" Margin="5,2,5,2" /> </Border> <!--内容区--> <Grid Grid.Column="1" Margin="2 0 0 0"> <!--文本编辑--> <TextBox x:Name="PART_EditableTextBox" Style="{StaticResource EditableTextBoxStyle}" FontSize="{TemplateBinding FontSize}" HorizontalAlignment="Stretch" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" IsHitTestVisible="True" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" IsReadOnly="{TemplateBinding IsReadOnly}" FontFamily="{TemplateBinding FontFamily}" Foreground="{TemplateBinding Foreground}" Text="{Binding Path=Text,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}" /> </Grid> <!--弹出多选列表--> <Popup x:Name="PART_Popup" AllowsTransparency="True" Focusable="False" StaysOpen="False" IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Placement="Bottom"> <Grid Width="{Binding ActualWidth, RelativeSource={RelativeSource TemplatedParent}}" MaxHeight="{Binding MaxDropDownHeight, RelativeSource={RelativeSource TemplatedParent}}"> <Border x:Name="PopupBorder" BorderThickness="{TemplateBinding BorderThickness}" HorizontalAlignment="Stretch" Height="Auto" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding controls:ControlAttachProperty.PopupBackground}"/> <controls:ExtendedTreeView x:Name="PART_TreeView" Margin="2" ItemsSource="{Binding ItemsSource,RelativeSource={RelativeSource TemplatedParent}}" MaxHeight="{TemplateBinding MaxDropDownHeight}" ItemTemplate="{TemplateBinding ItemTemplate}" Style="{StaticResource DefaultMetroTreeView}"> </controls:ExtendedTreeView> </Grid> </Popup> </Grid> </Grid> <!--触发器--> <ControlTemplate.Triggers> <!--1.显示水印--> <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Text}" Value=""> <Setter TargetName="Message" Property="Visibility" Value="Visible" /> </DataTrigger> <!--编辑模式--> <Trigger Property="IsEditable" Value="True"> <Setter TargetName="PART_DropDownToggle" Property="Grid.Column" Value="3" /> <Setter TargetName="PART_DropDownToggle" Property="Grid.ColumnSpan" Value="1" /> <Setter TargetName="PART_DropDownToggle" Property="Background" Value="Transparent" /> <Setter Property="IsTabStop" Value="false" /> <Setter TargetName="PART_DropDownToggle" Property="Focusable" Value="False" /> </Trigger> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="BorderBrush" Value="{Binding Path=(controls:ControlAttachProperty.MouseOverBorderBrush),RelativeSource={RelativeSource Self}}"/> </Trigger> <Trigger Property="IsFocused" Value="True"> <Setter Property="BorderBrush" Value="{Binding Path=(controls:ControlAttachProperty.FocusBorderBrush),RelativeSource={RelativeSource Self}}"/> </Trigger> <Trigger Property="IsKeyboardFocusWithin" Value="True"> <Setter Property="BorderBrush" Value="{Binding Path=(controls:ControlAttachProperty.FocusBorderBrush),RelativeSource={RelativeSource Self}}"/> </Trigger> <Trigger Property="IsEnabled" Value="False"> <Setter TargetName="PART_Root" Property="Opacity" Value="{DynamicResource DisableOpacity}"></Setter> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style>
cs代码
/// <summary> /// TreeSelect.xaml 的交互逻辑 /// </summary> [TemplatePart(Name = "PART_TreeView", Type = typeof(TreeView))] public partial class TreeSelect : ComboBox { public bool IsMulti { get { return (bool)GetValue(IsMultiProperty); } set { SetValue(IsMultiProperty, value); } } public static readonly DependencyProperty IsMultiProperty = DependencyProperty.Register("IsMulti", typeof(bool), typeof(TreeSelect), new PropertyMetadata(false)); public new string DisplayMemberPath { get { return (string)GetValue(DisplayMemberPathProperty); } set { SetValue(DisplayMemberPathProperty, value); } } public new static readonly DependencyProperty DisplayMemberPathProperty = DependencyProperty.Register("DisplayMemberPath", typeof(string), typeof(TreeSelect)); public new string SelectedValuePath { get { return (string)GetValue(SelectedValuePathProperty); } set { SetValue(SelectedValuePathProperty, value); } } public new static readonly DependencyProperty SelectedValuePathProperty = DependencyProperty.Register("SelectedValuePath", typeof(string), typeof(TreeSelect)); /// <summary> /// Selected item of the TreeView /// </summary> public new object SelectedItem { get { return (object)GetValue(SelectedItemProperty); } set { SetValue(SelectedItemProperty, value); } } public new static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem", typeof(object), typeof(TreeSelect), new PropertyMetadata(null, new PropertyChangedCallback(OnSelectedItemChanged))); private static void OnSelectedItemChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { ((TreeSelect)sender).UpdateSelectedItem(); } public new object SelectedValue { get { return (object)GetValue(SelectedValueProperty); } set { SetValue(SelectedValueProperty, value); } } public new static readonly DependencyProperty SelectedValueProperty = DependencyProperty.Register("SelectedValue", typeof(object), typeof(TreeSelect), new PropertyMetadata(null)); public new string Text { get { return (string)GetValue(TextProperty); } set { SetValue(TextProperty, value); } } public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(TreeSelect)); /// <summary> /// Gets or sets text separator. /// </summary> public string TextSeparator { get { return (string)GetValue(TextSeparatorProperty); } set { SetValue(TextSeparatorProperty, value); } } public static readonly DependencyProperty TextSeparatorProperty = DependencyProperty.Register("TextSeparator", typeof(string), typeof(TreeSelect), new PropertyMetadata(",")); /// <summary> /// Gets or sets max text length. /// </summary> public int? MaxTextLength { get { return (int?)GetValue(MaxTextLengthProperty); } set { SetValue(MaxTextLengthProperty, value); } } public static readonly DependencyProperty MaxTextLengthProperty = DependencyProperty.Register("MaxTextLength", typeof(int?), typeof(TreeSelect)); /// <summary> /// Gets or sets text filler when text length exceeded. /// </summary> public string ExceededTextFiller { get { return (string)GetValue(ExceededTextFillerProperty); } set { SetValue(ExceededTextFillerProperty, value); } } public static readonly DependencyProperty ExceededTextFillerProperty = DependencyProperty.Register("ExceededTextFiller", typeof(string), typeof(TreeSelect), new PropertyMetadata("...")); static TreeSelect() { DefaultStyleKeyProperty.OverrideMetadata(typeof(TreeSelect), new FrameworkPropertyMetadata(typeof(TreeSelect))); } public TreeSelect() { Loaded -= TreeSelect_Loaded; Loaded += TreeSelect_Loaded; SizeChanged -= TreeSelect_SizeChanged; SizeChanged += TreeSelect_SizeChanged; } private ExtendedTreeView _treeView; public override void OnApplyTemplate() { base.OnApplyTemplate(); this._treeView = Template.FindName("PART_TreeView", this) as ExtendedTreeView; if (this._treeView != null) { //this._treeView.SelectedItemChanged += _TreeView_SelectedItemChanged; _treeView.OnHierarchyMouseUp += new MouseEventHandler(OnTreeViewHierarchyMouseUp); _treeView.AddHandler(System.Windows.Controls.TreeViewItem.SelectedEvent, new System.Windows.RoutedEventHandler(treeview_Selected)); } } //protected override void OnDropDownClosed(EventArgs e) //{ // base.OnDropDownClosed(e); // this.SelectedItem = _treeView.SelectedItem; // this.UpdateText(); //} //protected override void OnDropDownOpened(EventArgs e) //{ // base.OnDropDownOpened(e); // this.UpdateText(); //} /// <summary> /// Handles clicks on any item in the tree view /// </summary> private void OnTreeViewHierarchyMouseUp(object sender, MouseEventArgs e) { //This line isn‘t obligatory because it is executed in the OnDropDownClosed method, but be it so this.SelectedItem = _treeView.SelectedItem; this.UpdateText(); base.SelectedItem = this.SelectedItem; this.IsDropDownOpen = false; } private void treeview_Selected(object sender, RoutedEventArgs e) { TreeViewItem item = (e.OriginalSource as TreeViewItem); if (item != null) { item.BringIntoView(); } } protected override bool IsItemItsOwnContainerOverride(object item) { if (item is ComboBoxItem) return true; else return false; } protected override void PrepareContainerForItemOverride(DependencyObject element, object item) { var uie = element as FrameworkElement; if (!(item is ComboBoxItem)) { var textBinding = new Binding(DisplayMemberPath); textBinding.Source = item; uie.SetBinding(ContentPresenter.ContentProperty, textBinding); } base.PrepareContainerForItemOverride(element, item); } private void TreeSelect_SizeChanged(object sender, SizeChangedEventArgs e) { if (!IsLoaded) return; UpdateText(); } private void TreeSelect_Loaded(object sender, RoutedEventArgs e) { UpdateText(); } private void UpdateSelectedItem() { UpdateText(); base.SelectedItem = this.SelectedItem; if (this.SelectedItem == null || string.IsNullOrEmpty(this.SelectedValuePath)) { SelectedValue = null; } else { SelectedValue = this.SelectedItem.GetType().GetProperty(SelectedValuePath).GetValue(this.SelectedItem, null); } } private void _TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e) { if (!IsLoaded) return; UpdateText(); base.SelectedItem = this.SelectedItem; } private void UpdateText() { if (IsMulti == false) { Text = GenerateText(SelectedItem); } else { Text = GenerateText(); } } public string GenerateText(object selectedItem) { var text = ""; if (selectedItem == null) { text = ""; } else if (selectedItem is ComboBoxItem) { var msi = selectedItem as ComboBoxItem; text += msi.Content.ToString(); } else { if (!string.IsNullOrEmpty(DisplayMemberPath) && selectedItem.GetType().GetProperty(DisplayMemberPath) != null) text += selectedItem.GetType().GetProperty(DisplayMemberPath).GetValue(selectedItem, null).ToString(); else text += selectedItem.ToString(); if (selectedItem.GetType().GetProperty("IsSelected") != null) { selectedItem.GetType().GetProperty("IsSelected").SetValue(selectedItem, true); } } return text; } public string GenerateText() { var text = ""; var isFirst = true; foreach (var item in Items) { if (!isFirst) text += TextSeparator; else isFirst = false; if (item is ComboBoxItem) { var msi = item as ComboBoxItem; text += msi.Content.ToString(); } else { if (item.GetType().GetProperty("IsSelected") != null && item.GetType().GetProperty("IsSelected").GetValue(item, null).ToString() == "true") { if (!string.IsNullOrEmpty(DisplayMemberPath) && item.GetType().GetProperty(DisplayMemberPath) != null) text += item.GetType().GetProperty(DisplayMemberPath).GetValue(item, null).ToString(); else text += item.ToString(); } } if (MaxTextLength == null) { if (!ValidateStringWidth(text + ExceededTextFiller)) { if (text.Length == 0) return null; text = text.Remove(text.Length - 1); while (!ValidateStringWidth(text + ExceededTextFiller)) { if (text.Length == 0) return null; text = text.Remove(text.Length - 1); } return text + ExceededTextFiller; } } else if (text.Length >= MaxTextLength) { return text.Cut((int)MaxTextLength, ExceededTextFiller); } } return text; } private bool ValidateStringWidth(string text) { var size = MeasureString(text); if (size.Width > (ActualWidth - Padding.Left - Padding.Right - 30)) return false; else return true; } private Size MeasureString(string candidate) { var formattedText = new FormattedText(candidate, System.Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface(FontFamily, FontStyle, FontWeight, FontStretch), FontSize, Brushes.Black, new NumberSubstitution(), TextFormattingMode.Display); return new Size(formattedText.Width, formattedText.Height); } }
使用:
<util:TreeSelect Width="200" ItemsSource="{Binding Data}" SelectedItem="{Binding SelectedData}" ItemTemplate="{x:Null}" DisplayMemberPath="Name" xmlns:util="https://astudio.github.io/utilcontrol"> <util:TreeSelect.Resources> <HierarchicalDataTemplate DataType="{x:Type viewmodel:Person}" ItemsSource="{Binding Path=Children}"> <StackPanel Orientation="Horizontal"> <Path x:Name="IconPath" Width="18" Height="18" Stretch="Fill" Fill="Black" Data="F1 M 24.0033,56.0078L 24.0033,38.0053L 22.0031,40.0056L 19.0027,35.0049L 38.0053,20.0028L 45.0063,25.5299L 45.0063,21.753L 49.0068,21.0029L 49.0068,28.6882L 57.008,35.0049L 54.0075,40.0056L 52.0073,38.0053L 52.0073,56.0078L 24.0033,56.0078 Z M 38.0053,26.9204L 27.0038,36.005L 27.0038,53.0074L 33.0046,53.0074L 33.0046,42.006L 43.006,42.006L 43.006,53.0074L 49.0068,53.0074L 49.0068,36.005L 38.0053,26.9204 Z " /> <Grid Margin="2,0,2,0"> <TextBlock x:Name="txtName" Text="{Binding Name, Mode=TwoWay}" Width="Auto" /> </Grid> </StackPanel> </HierarchicalDataTemplate> </util:TreeSelect.Resources> </util:TreeSelect>
完成,这个还支持多选的,没有完全完成,待续。
标签:closed on() bottom lte image rgs protected contain csharp
原文地址:https://www.cnblogs.com/akwkevin/p/14199966.html