Files
Shrlalgo.RvKits/Melskin/Markup/EnumSourceExtension.cs
2026-02-17 22:17:13 +08:00

103 lines
4.2 KiB
C#
Raw Permalink 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 Melskin.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>
/// 用Markup语法绑定枚举类型
/// </summary>
/// <example><c>ItemsSource="{controls:EnumSource EnumType=controls:Sex}"</c></example>
public EnumSourceExtension()
{
}
/// <summary>
/// 用Markup语法绑定枚举类型
/// </summary>
/// <param name="enumType"></param>
/// <remarks>若需要绑定Description则需设置BindToDescription为True同时只能用SelectedValue来绑定源属性</remarks>
/// <example><c>ItemsSource="{controls:EnumSource controls:ExampleEnum}"</c></example>
public EnumSourceExtension(Type enumType) { EnumType = enumType; }
/// <inheritdoc />
public override object? ProvideValue(IServiceProvider serviceProvider)
{
if (serviceProvider.GetService(typeof(IProvideValueTarget)) is not IProvideValueTarget pvt)
{
return null;
}
//如果为空,则返回运行时绑定的类。
if (pvt.TargetObject is not FrameworkElement) { return this; }
if (enumType == null) return 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;
}
private static string? GetDescription(object? enumValue)
{
if (enumValue == null) return string.Empty;
var fieldInfo = enumValue.GetType().GetField(enumValue.ToString() ?? string.Empty);
var descriptionAttribute = fieldInfo?.GetCustomAttribute<DescriptionAttribute>();
return descriptionAttribute?.Description ?? enumValue.ToString();
}
}
}