WPF利用CommunityToolkit.Mvvm實現(xiàn)級聯(lián)選擇器
更新時間:2023年12月25日 10:16:59 作者:WPF開發(fā)者
這篇文章主要介紹了WPF如何利用CommunityToolkit.Mvvm實現(xiàn)級聯(lián)選擇器,文中的示例代碼講解詳細,對我們的學習或工作有一定幫助,需要的小伙伴可以參考一下
WPF 使用 CommunityToolkit.Mvvm 實現(xiàn)級聯(lián)選擇器
框架使用.NET5;
Visual Studio 2022;

示例代碼
1)CascadePicker.cs 代碼如下:
Text獲取或設置級聯(lián)選擇器的文本值。IsDropDownOpen級聯(lián)選擇器的下拉菜單是否打開。MaxDropDownHeight級聯(lián)選擇器下拉菜單的最大高度。OnApplyTemplate重寫了基類的模板應用方法。MenuItem_Click菜單項點擊事件,根據(jù)用戶選擇的菜單項更新級聯(lián)選擇器的文本值,并關(guān)閉下拉菜單。GetHierarchicalPath菜單項的層次結(jié)構(gòu)獲取完整的路徑字符串。GetParentHierarchy菜單項的父級層次結(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 代碼如下:
- 子菜單項的樣式使用了
WD.DefaultMenuItem樣式,并綁定了ItemsSource屬性。 - 定義了控件的外觀和行為,包括邊框、文本框、下拉箭頭、下拉彈出窗口等元素。
- 觸發(fā)器定義了控件的交互行為,例如鼠標懸停、下拉彈出窗口的打開和關(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="請選擇內(nèi)容"
DisplayMemberPath="Name"
Text="{Binding City, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ItemsSource="{Binding CityInfos}" />
效果圖

以上就是WPF利用CommunityToolkit.Mvvm實現(xiàn)級聯(lián)選擇器的詳細內(nèi)容,更多關(guān)于WPF級聯(lián)選擇器的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
DataGridView清除顯示的數(shù)據(jù)、設定右鍵菜單
這篇文章介紹了DataGridView清除顯示的數(shù)據(jù)、設定右鍵菜單的方法,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-02-02
總結(jié)C#動態(tài)調(diào)用WCF接口的兩種方法
這篇文章給大家總結(jié)了C#動態(tài)調(diào)用WCF接口的兩種方法,大家可以根據(jù)自己的需求選擇對應的方式,下面來一起看看。2016-09-09

