行为库

ChangeAttachedPropertyAction

行为库的 ChangePropertyAction 只支持依赖属性,不支持附加属性。所以如果想要改变附加属性的值,就需要自定义一个 ChangeAttachedPropertyAction

using Microsoft.Xaml.Behaviors;
using System.ComponentModel;
using System.Reflection;
using System.Windows;

public class ChangeAttachedPropertyAction : TargetedTriggerAction<UIElement>
{
    public Type? ClassType
    {
        get { return (Type)GetValue(ClassTypeProperty); }
        set { SetValue(ClassTypeProperty, value); }
    }

    public static readonly DependencyProperty ClassTypeProperty = DependencyProperty.Register(
        nameof(ClassType),
        typeof(Type),
        typeof(ChangeAttachedPropertyAction),
        new PropertyMetadata(null)
    );

    public string? PropertyName
    {
        get => (string)GetValue(PropertyNameProperty);
        set => SetValue(PropertyNameProperty, value);
    }

    public static readonly DependencyProperty PropertyNameProperty = DependencyProperty.Register(
        nameof(PropertyName),
        typeof(string),
        typeof(ChangeAttachedPropertyAction),
        new PropertyMetadata("")
    );

    public object? Value
    {
        get => GetValue(ValueProperty);
        set => SetValue(ValueProperty, value);
    }

    public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
        nameof(Value),
        typeof(object),
        typeof(ChangeAttachedPropertyAction),
        new PropertyMetadata(null)
    );

    protected override void Invoke(object parameter)
    {
        ArgumentNullException.ThrowIfNull(ClassType, nameof(ClassType));
        ArgumentException.ThrowIfNullOrEmpty(PropertyName, nameof(PropertyName));
        MethodInfo setter =
            ClassType.GetMethod($"Set{PropertyName}", BindingFlags.Static | BindingFlags.Public)
            ?? throw new ArgumentException($"Method {PropertyName} not found in {ClassType}");
        Type parameterType = setter.GetParameters()[1].ParameterType;
        if (parameterType.IsAssignableFrom(Value.GetType()))
        {
            setter.Invoke(null, [ Target, Value ]);
            return;
        }
        var tc = TypeDescriptor.GetConverter(parameterType);
        if (Value != null && tc.CanConvertFrom(Value.GetType()))
        {
            setter.Invoke(null, [ Target, tc.ConvertFrom(Value) ]);
            return;
        }
        throw new ArgumentException($"Cannot convert {Value?.GetType()} to {parameterType}");
    }
}