Avalonia下拉可搜索树(TreeComboBox)

news/发布时间2024/5/22 3:20:50

1.需求分析

  树形下拉的功能是ComboBox和TreeView的功能结合起来,再结合数据模板来实现这一功能。

2.代码实现

  1.创建UserControl集成TreeView控件
`
public class TreeComboBox : TreeView
{
private bool _isPushTextChangedEvent = true;

private Button ClearButton;
private string _fixedPlaceholderText;
private TextBox ComboBoxText;private object? _selectItem;public TreeComboBox()
{TemplateApplied += (sender, args) =>{ClearButton = args.NameScope.Find<Button>("ClearButton");ComboBoxText = args.NameScope.Find<TextBox>("ComboBoxText");ComboBoxText.TextChanged += (sender, args) => { OwenTextChanged?.Invoke(sender, args); };};PlaceholderTextProperty.Changed.Subscribe(new AnonymousObserver<AvaloniaPropertyChangedEventArgs<string>>((s) =>{if (s.Sender != this) return;if (!string.IsNullOrWhiteSpace(_fixedPlaceholderText)) return;_fixedPlaceholderText = s.NewValue.Value;})!);IsDropDownOpenProperty.Changed.Subscribe(new AnonymousObserver<AvaloniaPropertyChangedEventArgs<bool>>((s) =>{if (s.Sender != this) return;if (s.NewValue == false && SelectedItem != null){SetDisplay(SelectedItem);PlaceholderText = _fixedPlaceholderText;_isPushTextChangedEvent = true;}})!);SelectedItemProperty.Changed.Subscribe(new AnonymousObserver<AvaloniaPropertyChangedEventArgs<object>>((s) =>{if (s.Sender != this) return;if (s.NewValue == null){SetCurrentValue<string>(SelectTextProperty, string.Empty);}}));SelectionChanged += (sender, args) =>{_isPushTextChangedEvent = false;if (args.AddedItems.Count <= 0){this.SetCurrentValue<string>(SelectTextProperty, string.Empty);ComboBoxText?.Focus();return;}if (string.IsNullOrEmpty(DisplayMember)) return;var item = args.AddedItems[0];if (!string.IsNullOrEmpty(LeafMember)){var type = item.GetType();var property = type.GetProperty(LeafMember);if (property != null){int.TryParse(property.GetValue(item).ToString(), out var leaf);if (leaf == 0){SelectedItem = _selectItem;args.Handled = true;return;}_selectItem = SelectedItem;}}SetDisplay(item);};
}private void SetDisplay(object item)
{var type = item.GetType();var property = type.GetProperty(DisplayMember);this.SetCurrentValue<string>(SelectTextProperty, property.GetValue(item).ToString());ClearButton?.Focus();
}public EventHandler<TextChangedEventArgs>? OwenTextChanged { get; set; }public static readonly StyledProperty<string> SelectTextProperty = AvaloniaProperty.Register<TreeComboBox, string>("SelectText");public string SelectText
{get => GetValue(SelectTextProperty);set => SetValue(SelectTextProperty, value);
}public static readonly StyledProperty<string> DisplayMemberProperty =AvaloniaProperty.Register<TreeComboBox, string>("DisplayMember");/// <summary>
/// 显示的字段
/// </summary>
public string DisplayMember
{get => GetValue(DisplayMemberProperty);set => SetValue(DisplayMemberProperty, value);
}public static readonly StyledProperty<string> LeafMemberProperty = AvaloniaProperty.Register<TreeComboBox, string>("LeafMember");/// <summary>
/// 是否过滤不能选中的节点,需要过滤节点的字段
/// </summary>
public string LeafMember
{get => GetValue(LeafMemberProperty);set => SetValue(LeafMemberProperty, value);
}/// <summary>
/// Defines the <see cref="P:Avalonia.Controls.ComboBox.PlaceholderText" /> property.
/// </summary>
public static readonly StyledProperty<string?> PlaceholderTextProperty =AvaloniaProperty.Register<TreeComboBox, string>(nameof(PlaceholderText));/// <summary>Gets or sets the PlaceHolder text.</summary>
public string? PlaceholderText
{get => this.GetValue<string>(TreeComboBox.PlaceholderTextProperty);set => this.SetValue<string>(TreeComboBox.PlaceholderTextProperty, value);
}/// <summary>
/// Defines the <see cref="P:Avalonia.Controls.ComboBox.IsDropDownOpen" /> property.
/// </summary>
public static readonly StyledProperty<bool> IsDropDownOpenProperty =AvaloniaProperty.Register<TreeComboBox, bool>(nameof(IsDropDownOpen));public bool IsDropDownOpen
{get => this.GetValue<bool>(TreeComboBox.IsDropDownOpenProperty);set { this.SetValue<bool>(TreeComboBox.IsDropDownOpenProperty, value); }
}public void Clear()
{this.SetCurrentValue<string>(SelectTextProperty, string.Empty);SelectedItems.Clear();_selectItem = null;PlaceholderText = _fixedPlaceholderText;if (ComboBoxText != null){ComboBoxText.Text = "";ComboBoxText.Focus();}
}private Popup? _popup;protected override void OnPointerPressed(PointerPressedEventArgs e)
{base.OnPointerPressed(e);if (!e.Handled && e.Source is Visual source){Popup popup = this._popup;if ((popup != null ? (popup.IsInsidePopup(source) ? 1 : 0) : 0) != 0){e.Handled = true;return;}}this.PseudoClasses.Set(":pressed", true);
}protected override void OnPointerReleased(PointerReleasedEventArgs e)
{if (SelectedItem != null){PlaceholderText = SelectText;SelectText = string.Empty;ComboBoxText.Focus();}if (!e.Handled && e.Source is Visual source){Popup popup = this._popup;if ((popup != null ? (popup.IsInsidePopup(source) ? 1 : 0) : 0) != 0){if (this.UpdateSelectionFromEventSource(e.Source)){this._popup?.Close();e.Handled = true;}}else{this.SetCurrentValue<bool>(TreeComboBox.IsDropDownOpenProperty, !this.IsDropDownOpen);e.Handled = true;}}this.PseudoClasses.Set(":pressed", false);base.OnPointerReleased(e);
}

}
`
2.将ComboBox模板代码,和必要属性集成到新建的UserControl中

 <ControlTheme x:Key="{x:Type control:TreeComboBox}" TargetType="control:TreeComboBox"><Setter Property="Template"><ControlTemplate TargetType="Calendar"><Grid ColumnDefinitions="*,12,32"><Borderx:Name="Background"Grid.Column="0"Grid.ColumnSpan="3"MinWidth="{DynamicResource ComboBoxThemeMinWidth}"MinHeight="{DynamicResource ComboBoxDefaultHeight}"Background="{TemplateBinding Background}"BorderBrush="{TemplateBinding BorderBrush}"BorderThickness="{TemplateBinding BorderThickness}"CornerRadius="{TemplateBinding CornerRadius}" /><StackPanel Grid.Column="0" ><TextBoxx:Name="ComboBoxText"Margin="{TemplateBinding Padding}"Width="{Binding $parent.Bounds.Width}"HorizontalAlignment="Left"VerticalAlignment="Center"Watermark="{Binding $parent[control:TreeComboBox].PlaceholderText}"Foreground="{TemplateBinding Foreground}"IsVisible="{Binding $parent[control:TreeComboBox].SelectText,Converter={x:Static StringConverters.IsNullOrEmpty}}"></TextBox><TextBoxWidth="{Binding $parent.Bounds.Width}"Margin="{TemplateBinding Padding}"HorizontalAlignment="Left"VerticalAlignment="Center"Foreground="{TemplateBinding Foreground}"IsVisible="{Binding $parent[control:TreeComboBox].SelectText,Converter={x:Static StringConverters.IsNotNullOrEmpty}}"Text="{Binding $parent[control:TreeComboBox].SelectText}"></TextBox></StackPanel><Borderx:Name="DropDownOverlay"Grid.Column="1"Width="30"Margin="0,1,1,1"HorizontalAlignment="Right"Background="Transparent"IsVisible="False" /><Button Grid.Column="1" Width="12"Name="ClearButton"Tag="{TemplateBinding Name}"DockPanel.Dock="Right"Background="Transparent"Command="{Binding $parent[control:TreeComboBox].Clear}"IsVisible="{Binding $parent[control:TreeComboBox].SelectedItem,Converter={x:Static ObjectConverters.IsNotNull}}"Height="12"><Button.Template><ControlTemplate><Border><PathIcon Data="{StaticResource TextBoxClearButtonData}"Foreground="{DynamicResource ComboBoxIconDefaultForeground}"Width="12"Height="12"></PathIcon></Border></ControlTemplate></Button.Template><Button.Styles><Style Selector="Button:pointerover"><Setter Property="Background" Value="Transparent"></Setter></Style></Button.Styles></Button><PathIconx:Name="DropDownGlyph"Grid.Column="2"Width="12"Height="12"Margin="0,0,10,0"HorizontalAlignment="Right"VerticalAlignment="Center"Data="{DynamicResource ComboBoxIcon}"Foreground="{DynamicResource ComboBoxIconDefaultForeground}"IsHitTestVisible="False"UseLayoutRounding="False" /><PopupName="PART_Popup"Grid.Column="0"MinWidth="{Binding Bounds.Width, RelativeSource={RelativeSource TemplatedParent}}"MaxHeight="300"ClipToBounds="False"InheritsTransform="True"IsLightDismissEnabled="True"PlacementTarget="Background"IsOpen="{Binding $parent[control:TreeComboBox].IsDropDownOpen,Mode=TwoWay}"WindowManagerAddShadowHint="False"><Borderx:Name="PopupBorder"Margin="0,4"HorizontalAlignment="Stretch"Background="{DynamicResource ComboBoxPopupBackground}"BorderBrush="{DynamicResource ComboBoxPopupBorderBrush}"BorderThickness="{DynamicResource ComboBoxPopupBorderThickness}"BoxShadow="{DynamicResource ComboBoxPopupBoxShadow}"ClipToBounds="True"CornerRadius="6"><ScrollViewerHorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"><ItemsPresenterName="PART_ItemsPresenter"Margin="{DynamicResource ComboBoxDropdownContentMargin}" /></ScrollViewer></Border></Popup></Grid></ControlTemplate></Setter></ControlTheme>

3.运行效果

4.代码地址

https://github.com/klousCan/Avalonia.TreeComboBox.git

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ulsteruni.cn/article/34774504.html

如若内容造成侵权/违法违规/事实不符,请联系编程大学网进行投诉反馈email:xxxxxxxx@qq.com,一经查实,立即删除!

相关文章

void usart_dma_init(void)

void usart_dma_init(void) {GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;DMA_InitTypeDef DMA_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;/* 配置GPIO的模式和IO口 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_…

k8s-调度-taint

NoSchedule :表示k8s将不会将Pod调度到具有该污点的Node上 PreferNoSchedule :表示k8s将尽量避免将Pod调度到具有该污点的Node上 NoExecute :表示k8s将不会将Pod调度到具有该污点的Node上,同时会将Node上已经存在的Pod驱逐出去去除污点 kubectl taint nodes k8s-node2 chec…

Cisco Nexus 9000 Series Switches, NX-OS Standalone 10.4(3)F and ACI Mode 16.0(5h)

Cisco Nexus 9000 Series Switches, NX-OS Standalone 10.4(3)F and ACI Mode 16.0(5h)Cisco Nexus 9000 Series Switches, NX-OS Standalone 10.4(3)F and ACI Mode 16.0(5h) include Application Policy Infrastructure Controller (APIC) Release 6.0(5h) 请访问原文链接:C…

003提供器(provider)

一、介绍 提供器是 Nest 中的一个基本概念。 许多基本的 Nest 类可以被视为提供器,例如: 服务、存储库、工厂、助手等等。 提供器的主要思想是它可以作为依赖注入;这意味着对象之间可以创建各种关系,并且 "接线" 这些对象的功能很大程度上可以委托给 Nest 运行时…

SQL事前巡检插件

背景: 事故频发 •每年都会看到SQL问题引发的线上问题 不易发觉 •对于SQL性能问题测试在预发环境不易发现 •saas系统隔离字段在SQL条件中遗漏,造成越权风险 •业务初期SQL没问题,业务增长容易出现事故 •DBS慢SQL不支持实时报警,无法及时发现 •靠大家review代码总会出现遗…

.NET MAUI开源免费的UI工具包 - Uranium

前言 一直有小伙伴在微信公众号后台留言让我分享一下.NET MAUI相关的UI框架,今天大姚分享一个.NET MAUI开源、免费的UI工具包:Uranium。Uranium介绍 Uranium是一个.NET MAUI开源免费的UI工具包。它提供了一组用于构建现代应用程序的控件和实用程序,它构建在.NET MAUI基础架构…