WPF利用CommunityToolkit.Mvvm實(shí)現(xiàn)級(jí)聯(lián)選擇器
WPF 使用 CommunityToolkit.Mvvm 實(shí)現(xiàn)級(jí)聯(lián)選擇器
框架使用.NET5
;
Visual Studio 2022
;
示例代碼
1)CascadePicker.cs
代碼如下:
Text
獲取或設(shè)置級(jí)聯(lián)選擇器的文本值。IsDropDownOpen
級(jí)聯(lián)選擇器的下拉菜單是否打開(kāi)。MaxDropDownHeight
級(jí)聯(lián)選擇器下拉菜單的最大高度。OnApplyTemplate
重寫了基類的模板應(yīng)用方法。MenuItem_Click
菜單項(xiàng)點(diǎn)擊事件,根據(jù)用戶選擇的菜單項(xiàng)更新級(jí)聯(lián)選擇器的文本值,并關(guān)閉下拉菜單。GetHierarchicalPath
菜單項(xiàng)的層次結(jié)構(gòu)獲取完整的路徑字符串。GetParentHierarchy
菜單項(xiàng)的父級(jí)層次結(jié)構(gòu)。
using System; using System.Collections.Generic; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Media; namespace WpfCascadePicker.Controls { public class CascadePicker : MenuBase { private static readonly Type _typeofSelf = typeof(CascadePicker); static CascadePicker() { DefaultStyleKeyProperty.OverrideMetadata(_typeofSelf, new FrameworkPropertyMetadata(_typeofSelf)); } public string Text { get { return (string)GetValue(TextProperty); } set { SetValue(TextProperty, value); } } public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(CascadePicker), new PropertyMetadata(string.Empty)); public static readonly DependencyProperty IsDropDownOpenProperty = DependencyProperty.Register( "IsDropDownOpen", typeof(bool), typeof(CascadePicker), new PropertyMetadata(false)); public bool IsDropDownOpen { get { return (bool)GetValue(IsDropDownOpenProperty); } set { SetValue(IsDropDownOpenProperty, value); } } public static readonly DependencyProperty MaxDropDownHeightProperty = DependencyProperty.Register( "MaxDropDownHeight", typeof(double), typeof(CascadePicker), new PropertyMetadata(SystemParameters.PrimaryScreenHeight / 3.0)); public double MaxDropDownHeight { get { return (double)GetValue(MaxDropDownHeightProperty); } set { SetValue(MaxDropDownHeightProperty, value); } } public override void OnApplyTemplate() { base.OnApplyTemplate(); } public CascadePicker() { AddHandler(MenuItem.ClickEvent, new RoutedEventHandler(MenuItem_Click)); } private void MenuItem_Click(object sender, RoutedEventArgs e) { var clickedMenuItem = e.OriginalSource as MenuItem; if (clickedMenuItem != null) { List<string> hierarchy = GetParentHierarchy(clickedMenuItem); Text = GetHierarchicalPath(hierarchy); } IsDropDownOpen = false; } private string GetHierarchicalPath(List<string> hierarchy) { hierarchy.Reverse(); return string.Join(" / ", hierarchy); } private List<string> GetParentHierarchy(MenuItem item) { var hierarchy = new List<string>(); var headerObject = item.Header; var propertyInfo = headerObject.GetType().GetProperty(DisplayMemberPath); if (propertyInfo != null) { var displayValue = propertyInfo.GetValue(headerObject, null) as string; if (!string.IsNullOrEmpty(displayValue)) hierarchy.Add(displayValue); } var parent = VisualTreeHelper.GetParent(item); if (parent != null) { var stackPanel = parent as StackPanel; if (stackPanel != null) { var menuItemParent = stackPanel.TemplatedParent as MenuItem; if (menuItemParent != null) { var parentHierarchy = GetParentHierarchy(menuItemParent); hierarchy.AddRange(parentHierarchy); } } } return hierarchy; } } }
2)CascadePicker.xaml
代碼如下:
- 子菜單項(xiàng)的樣式使用了
WD.DefaultMenuItem
樣式,并綁定了ItemsSource
屬性。 - 定義了控件的外觀和行為,包括邊框、文本框、下拉箭頭、下拉彈出窗口等元素。
- 觸發(fā)器定義了控件的交互行為,例如鼠標(biāo)懸停、下拉彈出窗口的打開(kāi)和關(guān)閉等。
<Application x:Class="WpfCascade.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="clr-namespace:WpfCascadePicker.Controls" xmlns:local="clr-namespace:WpfCascade" xmlns:wd="https://github.com/WPFDevelopersOrg/WPFDevelopers" StartupUri="MainWindow.xaml"> <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="pack://application:,,,/WPFDevelopers;component/Themes/Light.Blue.xaml" /> <!-- 需要注意 wd:Resources 必須在配色主題后,Theme="Dark" 為黑色皮膚 --> <wd:Resources Theme="Light" /> <ResourceDictionary Source="pack://application:,,,/WPFDevelopers;component/Themes/Theme.xaml" /> </ResourceDictionary.MergedDictionaries> <Style BasedOn="{StaticResource WD.ControlBasicStyle}" TargetType="{x:Type controls:CascadePicker}"> <Setter Property="HorizontalContentAlignment" Value="Left" /> <Setter Property="VerticalContentAlignment" Value="Center" /> <Setter Property="BorderBrush" Value="{DynamicResource WD.BaseSolidColorBrush}" /> <Setter Property="BorderThickness" Value="1" /> <Setter Property="Background" Value="{DynamicResource WD.BackgroundSolidColorBrush}" /> <Setter Property="Padding" Value="{StaticResource WD.DefaultPadding}" /> <Setter Property="ItemContainerStyle"> <Setter.Value> <Style BasedOn="{StaticResource WD.DefaultMenuItem}" TargetType="MenuItem"> <Setter Property="ItemsSource" Value="{Binding ItemsSource}" /> <Setter Property="ItemContainerStyle"> <Setter.Value> <Style BasedOn="{StaticResource WD.DefaultMenuItem}" TargetType="MenuItem"> <Setter Property="ItemsSource" Value="{Binding ItemsSource}" /> </Style> </Setter.Value> </Setter> </Style> </Setter.Value> </Setter> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type controls:CascadePicker}"> <ControlTemplate.Resources> <Storyboard x:Key="OpenStoryboard"> <DoubleAnimation EasingFunction="{StaticResource WD.ExponentialEaseOut}" Storyboard.TargetName="PART_DropDown" Storyboard.TargetProperty="(Grid.RenderTransform).(ScaleTransform.ScaleY)" To="1" Duration="00:00:.2" /> </Storyboard> <Storyboard x:Key="CloseStoryboard"> <DoubleAnimation EasingFunction="{StaticResource WD.ExponentialEaseOut}" Storyboard.TargetName="PART_DropDown" Storyboard.TargetProperty="(Grid.RenderTransform).(ScaleTransform.ScaleY)" To="0" Duration="00:00:.2" /> </Storyboard> </ControlTemplate.Resources> <wd:SmallPanel SnapsToDevicePixels="True"> <Border Name="PART_Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="{Binding Path=(wd:ElementHelper.CornerRadius), RelativeSource={RelativeSource TemplatedParent}}" SnapsToDevicePixels="True" /> <TextBox Name="PART_EditableTextBox" Margin="{TemplateBinding Padding}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Background="{TemplateBinding Background}" Focusable="True" Foreground="{DynamicResource WD.PrimaryTextSolidColorBrush}" IsReadOnly="True" SelectionBrush="{DynamicResource WD.WindowBorderBrushSolidColorBrush}" Style="{x:Null}" Template="{StaticResource WD.ComboBoxTextBox}" Text="{Binding Text, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}" /> <TextBlock Name="PART_Watermark" Margin="{TemplateBinding Padding}" Padding="1,0" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Background="Transparent" Foreground="{DynamicResource WD.RegularTextSolidColorBrush}" IsHitTestVisible="False" Text="{Binding Path=(wd:ElementHelper.Watermark), RelativeSource={RelativeSource TemplatedParent}}" TextBlock.FontSize="{StaticResource WD.NormalFontSize}" TextTrimming="CharacterEllipsis" Visibility="Collapsed" /> <ToggleButton Name="PART_ToggleButton" Background="{TemplateBinding Background}" ClickMode="Release" Focusable="False" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Style="{x:Null}" Template="{StaticResource WD.ComboBoxToggleButton}" /> <Popup Name="PART_Popup" AllowsTransparency="True" IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}" Placement="Bottom" PlacementTarget="{Binding ElementName=PART_ToggleButton}" StaysOpen="False"> <wd:SmallPanel Name="PART_DropDown" MinWidth="{TemplateBinding FrameworkElement.ActualWidth}" MaxHeight="{TemplateBinding MaxDropDownHeight}" Margin="24,2,24,24" RenderTransformOrigin=".5,0" SnapsToDevicePixels="True"> <wd:SmallPanel.RenderTransform> <ScaleTransform ScaleY="0" /> </wd:SmallPanel.RenderTransform> <Border Name="PART_DropDownBorder" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="{Binding Path=(wd:ElementHelper.CornerRadius), RelativeSource={RelativeSource TemplatedParent}}" Effect="{StaticResource WD.PopupShadowDepth}" SnapsToDevicePixels="True" UseLayoutRounding="True"> <ItemsPresenter /> </Border> </wd:SmallPanel> </Popup> </wd:SmallPanel> <ControlTemplate.Triggers> <Trigger SourceName="PART_ToggleButton" Property="IsChecked" Value="True"> <Trigger.EnterActions> <BeginStoryboard x:Name="BeginStoryboardOpenStoryboard" Storyboard="{StaticResource OpenStoryboard}" /> </Trigger.EnterActions> <Trigger.ExitActions> <StopStoryboard BeginStoryboardName="BeginStoryboardOpenStoryboard" /> </Trigger.ExitActions> </Trigger> <Trigger SourceName="PART_ToggleButton" Property="IsChecked" Value="False"> <Trigger.EnterActions> <BeginStoryboard x:Name="BeginStoryboardCloseStoryboard" Storyboard="{StaticResource CloseStoryboard}" /> </Trigger.EnterActions> <Trigger.ExitActions> <StopStoryboard BeginStoryboardName="BeginStoryboardCloseStoryboard" /> </Trigger.ExitActions> </Trigger> <Trigger Property="UIElement.IsMouseOver" Value="True"> <Setter TargetName="PART_Border" Property="BorderBrush" Value="{DynamicResource WD.PrimaryNormalSolidColorBrush}" /> </Trigger> <Trigger SourceName="PART_EditableTextBox" Property="Text" Value=""> <Setter TargetName="PART_Watermark" Property="Visibility" Value="Visible" /> </Trigger> <Trigger SourceName="PART_EditableTextBox" Property="Text" Value="{x:Null}"> <Setter TargetName="PART_Watermark" Property="Visibility" Value="Visible" /> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> </ResourceDictionary> </Application.Resources> </Application>
3)CascadePickerExample.xaml
示例代碼如下:
<controls:CascadePicker Width="240" Height="40" wd:ElementHelper.Watermark="請(qǐng)選擇內(nèi)容" DisplayMemberPath="Name" Text="{Binding City, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ItemsSource="{Binding CityInfos}" />
效果圖
以上就是WPF利用CommunityToolkit.Mvvm實(shí)現(xiàn)級(jí)聯(lián)選擇器的詳細(xì)內(nèi)容,更多關(guān)于WPF級(jí)聯(lián)選擇器的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C#難點(diǎn)逐個(gè)擊破(5):類的訪問(wèn)類型
類的訪問(wèn)類型有時(shí)也叫訪問(wèn)級(jí)別,使用以下訪問(wèn)修改符:Public、Protected、Private、internal、protected internal。2010-02-02DataGridView清除顯示的數(shù)據(jù)、設(shè)定右鍵菜單
這篇文章介紹了DataGridView清除顯示的數(shù)據(jù)、設(shè)定右鍵菜單的方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-02-02unity實(shí)現(xiàn)鼠標(biāo)跟隨(ITween)
這篇文章主要為大家詳細(xì)介紹了unity實(shí)現(xiàn)鼠標(biāo)跟隨,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-04-04利用thrift實(shí)現(xiàn)js與C#通訊的實(shí)例代碼
利用thrift實(shí)現(xiàn)js與C#通訊的實(shí)例代碼,需要的朋友可以參考一下2013-04-04總結(jié)C#動(dòng)態(tài)調(diào)用WCF接口的兩種方法
這篇文章給大家總結(jié)了C#動(dòng)態(tài)調(diào)用WCF接口的兩種方法,大家可以根據(jù)自己的需求選擇對(duì)應(yīng)的方式,下面來(lái)一起看看。2016-09-09對(duì)WPF中的TreeView實(shí)現(xiàn)右鍵選定
這篇文章介紹了WPF實(shí)現(xiàn)右鍵選定TreeView的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06