Files
ShrlAlgoToolkit/NeuWPF/NeoUI/Markup/EnumSourceExtension.cs
ShrlAlgo 955a01f564 整理
2025-08-20 12:10:35 +08:00

105 lines
4.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.ComponentModel;
using System.Reflection;
using System.Windows.Controls.Primitives;
using System.Windows.Markup;
namespace NeoUI.Markup
{
/// <summary>
/// 用于在XAML中提供枚举类型的值源扩展。此扩展允许开发者直接将枚举类型作为数据源适用于如ComboBox等控件的ItemsSource绑定。
/// </summary>
public class EnumSourceExtension : MarkupExtension
{
private Type? enumType;
/// <summary>
/// 获取或设置一个值,指示是否将枚举项绑定到其 DescriptionAttribute 的描述。如果设置为 true则返回的枚举项将包含描述信息并且只能通过 SelectedValue 来绑定源属性。
/// </summary>
/// <remarks>当此属性设置为 true 时,提供给 UI 的数据源将会是带有 Value 和 Description 属性的对象列表。其中 Value 对应于枚举值,而 Description 则是从枚举成员上的 DescriptionAttribute 中获取的描述文本。</remarks>
public bool BindToDescription { get; set; } = false;
/// <summary>
/// 获取或设置用作数据源的枚举类型。此属性允许开发者指定一个枚举类型该类型将作为控件如ComboBox的数据源。
/// </summary>
/// <remarks>当设置了此属性后,对应的控件会使用指定的枚举类型的所有成员作为其数据项。如果需要展示枚举成员上的描述信息,请同时设置 BindToDescription 属性为 true并通过 SelectedValue 绑定源属性。</remarks>
public Type? EnumType
{
get => enumType;
set
{
if (value == enumType) return;
if (null != value)
{
var type = Nullable.GetUnderlyingType(value) ?? value;
if (!type.IsEnum)
{
throw new ArgumentException("类型必须是枚举类型");
}
}
enumType = value;
}
}
/// <summary>
/// 在ResourceDictionary中声明
/// </summary>
/// <example><c>local:EnumSourceExtension x:Key="EnumBindingSource" EnumType="{x:AppearanceType local:Sex}"</c></example>
/// <example><c>ItemsSource="{local:EnumSource EnumType=local:ExampleEnum}" SelectedItem="{Binding ExampleEnum}"</c></example>
public EnumSourceExtension()
{
}
/// <summary>
/// 用Markup语法
/// </summary>
/// <param name="enumType"></param>
/// <remarks>若需要绑定Description则需设置BindToDescription为True同时只能用SelectedValue来绑定源属性</remarks>
/// <example><c>ItemsSource="{Binding Source={local:EnumTypeBindingSource {x:AppearanceType local:ExampleEnum}}}"</c></example>
public EnumSourceExtension(Type enumType) { EnumType = enumType; }
/// <inheritdoc />
public override object? ProvideValue(IServiceProvider serviceProvider)
{
var pvt = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
if (pvt == null) { return null; }
//如果为空,则返回运行时绑定的类。
if (pvt.TargetObject is not FrameworkElement) { return this; }
if (enumType != null)
{
var enumValues = Enum.GetValues(enumType);
if (!BindToDescription) return enumValues;
var items = new List<object>();
foreach (var enumValue in enumValues)
{
var item = new
{
Value = enumValue,
Description = GetDescription(enumValue)
};
items.Add(item);
}
if (pvt.TargetObject is Selector selector)
{
selector.DisplayMemberPath = "Description";
selector.SelectedValuePath = "Value";
}
return items;
}
return null;
}
private static string GetDescription(object enumValue)
{
var fieldInfo = enumValue.GetType().GetField(enumValue.ToString());
var descriptionAttribute = fieldInfo.GetCustomAttribute<DescriptionAttribute>();
return descriptionAttribute?.Description ?? enumValue.ToString();
}
}
}