C# avalonia沒有內(nèi)置判斷屬性是否綁定的代碼,所以我們自己擴展實現(xiàn)一個。這個擴展可以用于動態(tài)解綁和綁定屬性。基于我寫的自定義擴展。
http://www.rzrgm.cn/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;
}
}
}
浙公網(wǎng)安備 33010602011771號