2025-02-10 20:53:40 +08:00
|
|
|
|
using System.ComponentModel;
|
2024-09-22 11:05:41 +08:00
|
|
|
|
using System.Reflection;
|
|
|
|
|
|
using System.Windows.Controls.Primitives;
|
|
|
|
|
|
using System.Windows.Markup;
|
|
|
|
|
|
|
2026-01-02 17:30:41 +08:00
|
|
|
|
namespace Melskin.Markup
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
2025-08-20 12:10:13 +08:00
|
|
|
|
/// 用于在XAML中提供枚举类型的值源扩展。此扩展允许开发者直接将枚举类型作为数据源,适用于如ComboBox等控件的ItemsSource绑定。
|
2024-09-22 11:05:41 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class EnumSourceExtension : MarkupExtension
|
|
|
|
|
|
{
|
2025-08-20 12:10:13 +08:00
|
|
|
|
private Type? enumType;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置一个值,指示是否将枚举项绑定到其 DescriptionAttribute 的描述。如果设置为 true,则返回的枚举项将包含描述信息,并且只能通过 SelectedValue 来绑定源属性。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>当此属性设置为 true 时,提供给 UI 的数据源将会是带有 Value 和 Description 属性的对象列表。其中 Value 对应于枚举值,而 Description 则是从枚举成员上的 DescriptionAttribute 中获取的描述文本。</remarks>
|
2024-09-22 11:05:41 +08:00
|
|
|
|
public bool BindToDescription { get; set; } = false;
|
2025-08-20 12:10:13 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置用作数据源的枚举类型。此属性允许开发者指定一个枚举类型,该类型将作为控件(如ComboBox)的数据源。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>当设置了此属性后,对应的控件会使用指定的枚举类型的所有成员作为其数据项。如果需要展示枚举成员上的描述信息,请同时设置 BindToDescription 属性为 true,并通过 SelectedValue 绑定源属性。</remarks>
|
|
|
|
|
|
public Type? EnumType
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
2025-08-20 12:10:13 +08:00
|
|
|
|
get => enumType;
|
2024-09-22 11:05:41 +08:00
|
|
|
|
set
|
|
|
|
|
|
{
|
2025-08-20 12:10:13 +08:00
|
|
|
|
if (value == enumType) return;
|
|
|
|
|
|
if (null != value)
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
2025-08-20 12:10:13 +08:00
|
|
|
|
var type = Nullable.GetUnderlyingType(value) ?? value;
|
|
|
|
|
|
if (!type.IsEnum)
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
2025-08-20 12:10:13 +08:00
|
|
|
|
throw new ArgumentException("类型必须是枚举类型");
|
2024-09-22 11:05:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-08-20 12:10:13 +08:00
|
|
|
|
enumType = value;
|
2024-09-22 11:05:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
2025-10-04 08:52:23 +08:00
|
|
|
|
/// 用Markup语法,绑定枚举类型
|
2024-09-22 11:05:41 +08:00
|
|
|
|
/// </summary>
|
2025-10-04 08:52:23 +08:00
|
|
|
|
/// <example><c>ItemsSource="{controls:EnumSource EnumType=controls:Sex}"</c></example>
|
2024-09-22 11:05:41 +08:00
|
|
|
|
public EnumSourceExtension()
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
2025-10-04 08:52:23 +08:00
|
|
|
|
/// 用Markup语法,绑定枚举类型
|
2024-09-22 11:05:41 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="enumType"></param>
|
|
|
|
|
|
/// <remarks>若需要绑定Description,则需设置BindToDescription为True,同时只能用SelectedValue来绑定源属性</remarks>
|
2025-10-04 08:52:23 +08:00
|
|
|
|
/// <example><c>ItemsSource="{controls:EnumSource controls:ExampleEnum}"</c></example>
|
2024-09-22 11:05:41 +08:00
|
|
|
|
public EnumSourceExtension(Type enumType) { EnumType = enumType; }
|
|
|
|
|
|
|
2025-08-20 12:10:13 +08:00
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
|
public override object? ProvideValue(IServiceProvider serviceProvider)
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
2025-10-04 08:52:23 +08:00
|
|
|
|
if (serviceProvider.GetService(typeof(IProvideValueTarget)) is not IProvideValueTarget pvt)
|
|
|
|
|
|
{
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
|
|
|
|
|
//如果为空,则返回运行时绑定的类。
|
|
|
|
|
|
if (pvt.TargetObject is not FrameworkElement) { return this; }
|
|
|
|
|
|
|
2026-01-02 16:37:37 +08:00
|
|
|
|
if (enumType == null) return null;
|
|
|
|
|
|
var enumValues = Enum.GetValues(enumType);
|
|
|
|
|
|
if (!BindToDescription) return enumValues;
|
|
|
|
|
|
var items = new List<object>();
|
|
|
|
|
|
foreach (var enumValue in enumValues)
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
2026-01-02 16:37:37 +08:00
|
|
|
|
var item = new
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
2026-01-02 16:37:37 +08:00
|
|
|
|
Value = enumValue,
|
|
|
|
|
|
Description = GetDescription(enumValue)
|
|
|
|
|
|
};
|
|
|
|
|
|
items.Add(item);
|
|
|
|
|
|
}
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
2026-01-02 16:37:37 +08:00
|
|
|
|
if (pvt.TargetObject is Selector selector)
|
|
|
|
|
|
{
|
|
|
|
|
|
selector.DisplayMemberPath = "Description";
|
|
|
|
|
|
selector.SelectedValuePath = "Value";
|
2024-09-22 11:05:41 +08:00
|
|
|
|
}
|
2025-08-20 12:10:13 +08:00
|
|
|
|
|
2026-01-02 16:37:37 +08:00
|
|
|
|
return items;
|
|
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
}
|
2026-01-02 16:37:37 +08:00
|
|
|
|
private static string? GetDescription(object? enumValue)
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
2025-10-04 08:52:23 +08:00
|
|
|
|
if (enumValue == null) return string.Empty;
|
2026-01-02 16:37:37 +08:00
|
|
|
|
var fieldInfo = enumValue.GetType().GetField(enumValue.ToString() ?? string.Empty);
|
2025-10-04 08:52:23 +08:00
|
|
|
|
var descriptionAttribute = fieldInfo?.GetCustomAttribute<DescriptionAttribute>();
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
|
|
|
|
|
return descriptionAttribute?.Description ?? enumValue.ToString();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|