C# avalonia没有内置判断属性是否绑定的代码,所以我们自己扩展实现一个。这个扩展可以用于动态解绑和绑定属性。基于我写的自定义扩展。

https://www.cnblogs.com/dalgleish/p/18972924

AvaloniaObjectExtensions代码

using Avalonia;
using Avalonia.Data;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Shares.Avalonia
{
    public static class AvaloniaObjectExtensions
    {
        private static readonly MethodInfo? getExpressionMethod;
        private static readonly FieldInfo? valuesField;
        private static readonly FieldInfo? framesField;
        private static readonly FieldInfo? localValueBindingsField;
        private static readonly Type? valueEntryType;

        static AvaloniaObjectExtensions()
        {
            var baseAssembly = typeof(AvaloniaObject).Assembly;
            var valueStoreType = baseAssembly.GetType("Avalonia.PropertyStore.ValueStore");
            valueEntryType = baseAssembly.GetType("Avalonia.PropertyStore.IValueEntry");

            getExpressionMethod = valueStoreType?.GetMethod("GetExpression",
                BindingFlags.Instance | BindingFlags.Public,
                null, new[] { typeof(AvaloniaProperty) }, null);

            valuesField = typeof(AvaloniaObject).GetField("_values", BindingFlags.Instance | BindingFlags.NonPublic);
            framesField = valueStoreType?.GetField("_frames", BindingFlags.Instance | BindingFlags.NonPublic);
            localValueBindingsField = valueStoreType?.GetField("_localValueBindings", BindingFlags.Instance | BindingFlags.NonPublic);
        }

        public static bool IsBinding(this AvaloniaObject avaloniaObject, AvaloniaProperty property)
        {
            try
            {
                if (avaloniaObject == null || property == null) return false;
                var valueStore = GetValueStore(avaloniaObject);
                return valueStore != null &&
                       (TryGetExpression(valueStore, property, out var expr) && expr != null
                        || IsLocallyBound(valueStore, property)
                        || IsBingdingInFrames(valueStore, property));
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[AvaloniaObjectExtensions] IsBinding错误 : {ex.Message}");
                return false;
            }
        }

        public static bool RemoveBinding(this AvaloniaObject avaloniaObject, AvaloniaProperty property)
        {
            try
            {
                if (avaloniaObject == null || property == null) return false;
                var valueStore = GetValueStore(avaloniaObject);
                if (valueStore == null) return false;

                var currentValue = avaloniaObject.GetValue(property);
                bool removed = RemoveLocalBinding(valueStore, property)
                            || RemoveFrameBindings(valueStore, property)
                            || RemoveBindingExpression(valueStore, property);

                if (removed) avaloniaObject.SetValue(property, currentValue);
                return removed;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[AvaloniaObjectExtensions] RemoveBinding错误 : {ex.Message}");
                return false;
            }
        }

        private static object? GetValueStore(AvaloniaObject obj) =>
            valuesField?.GetValue(obj) ?? obj.GetFieldValue<object>("_values");

        private static bool TryGetExpression(object valueStore, AvaloniaProperty property, out object? expression)
        {
            expression = null;
            try
            {
                expression = getExpressionMethod?.Invoke(valueStore, new object[] { property });
                return expression != null;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[AvaloniaObjectExtensions] TryGetExpression错误 : {ex.Message}");
                return false;
            }
        }

        private static bool IsLocallyBound(object valueStore, AvaloniaProperty property)
        {
            try
            {
                var localBindings = localValueBindingsField?.GetValue(valueStore) as IDictionary
                                    ?? valueStore.GetFieldValue<IDictionary>("_localValueBindings");
                return localBindings?.Contains(property.GetPropertyValue<int>("Id")) == true;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[AvaloniaObjectExtensions] IsLocallyBound错误 : {ex.Message}");
                return false;
            }
        }

        private static bool IsBingdingInFrames(object valueStore, AvaloniaProperty property)
        {
            try
            {
                var frames = framesField?.GetValue(valueStore) as IList
                             ?? valueStore.GetFieldValue<IList>("_frames");
                if (frames == null) return false;

                foreach (var frame in frames)
                {
                    int entryCount = frame.GetPropertyValue<int>("EntryCount");
                    for (int i = 0; i < entryCount; i++)
                    {
                        try
                        {
                            var entry = frame.InvokeMethod("GetEntry", new object[] { i });
                            if (entry != null && valueEntryType?.IsInstanceOfType(entry) == true && IsBindingEntry(entry, property))
                                return true;
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine($"[AvaloniaObjectExtensions] IsBoundInFrames (loop)错误 : {ex.Message}");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[AvaloniaObjectExtensions] IsBoundInFrames错误 : {ex.Message}");
            }
            return false;
        }

        private static bool IsBindingEntry(object entry, AvaloniaProperty property)
        {
            try
            {
                if (!property.Equals(entry.GetPropertyValue<AvaloniaProperty>("Property")))
                    return false;

                string typeName = entry.GetType().Name;
                return typeName.Contains("Binding", StringComparison.OrdinalIgnoreCase) ||
                       typeName.Contains("Observer", StringComparison.OrdinalIgnoreCase);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[AvaloniaObjectExtensions] IsBindingEntry错误 : {ex.Message}");
                return false;
            }
        }

        private static bool RemoveLocalBinding(object valueStore, AvaloniaProperty property)
        {
            try
            {
                var localBindings = localValueBindingsField?.GetValue(valueStore) as IDictionary
                                    ?? valueStore.GetFieldValue<IDictionary>("_localValueBindings");
                var propertyId = property.GetPropertyValue<int>("Id");

                if (localBindings?.Contains(propertyId) == true)
                {
                    if (localBindings[propertyId] is IDisposable disposable)
                        disposable.Dispose();

                    localBindings.Remove(propertyId);
                    return true;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[AvaloniaObjectExtensions] RemoveLocalBinding错误 : {ex.Message}");
            }
            return false;
        }

        private static bool RemoveFrameBindings(object valueStore, AvaloniaProperty property)
        {
            bool removed = false;
            try
            {
                var frames = framesField?.GetValue(valueStore) as IList
                             ?? valueStore.GetFieldValue<IList>("_frames");
                if (frames == null) return false;

                foreach (var frame in frames)
                {
                    if (frame == null) continue;

                    var removeMethod = frame.GetType().GetMethod("Remove",
                        BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
                        null, new[] { typeof(AvaloniaProperty) }, null);

                    if (removeMethod != null)
                    {
                        try
                        {
                            removeMethod.Invoke(frame, new object[] { property });
                            removed = true;
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine($"[AvaloniaObjectExtensions] RemoveFrameBindings (invoke)错误 : {ex.Message}");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[AvaloniaObjectExtensions] RemoveFrameBindings错误 : {ex.Message}");
            }
            return removed;
        }

        private static bool RemoveBindingExpression(object valueStore, AvaloniaProperty property)
        {
            try
            {
                if (TryGetExpression(valueStore, property, out var expression) &&
                   expression is IDisposable disposable)
                {
                    disposable.Dispose();
                    return true;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[AvaloniaObjectExtensions] RemoveBindingExpression错误 : {ex.Message}");
            }
            return false;
        }
    }
} 
posted on 2025-08-05 07:04  dalgleish  阅读(21)  评论(0)    收藏  举报