mirror of
https://gitee.com/chinware/atomui.git
synced 2024-11-30 02:47:45 +08:00
增加一些反射帮助类
This commit is contained in:
parent
1c3bb2c837
commit
dd9b6a046c
259
src/AtomUI.Base/Reflection/ObjectExtension.cs
Normal file
259
src/AtomUI.Base/Reflection/ObjectExtension.cs
Normal file
@ -0,0 +1,259 @@
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace AtomUI.Reflection;
|
||||
|
||||
public static class ObjectExtension
|
||||
{
|
||||
public static bool TryGetProperty<T>(
|
||||
this object source,
|
||||
string name,
|
||||
out T? result,
|
||||
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic)
|
||||
{
|
||||
PropertyInfo? property = source.GetType().GetProperty(name, flags);
|
||||
if (property is not null && property.GetValue(source) is T obj) {
|
||||
result = obj;
|
||||
return true;
|
||||
}
|
||||
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryGetProperty<T>(
|
||||
this object source,
|
||||
Type declareType,
|
||||
string name,
|
||||
out T? result,
|
||||
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic)
|
||||
{
|
||||
PropertyInfo? property = declareType.GetProperty(name, flags);
|
||||
if (property is not null && property.GetValue(source) is T obj) {
|
||||
result = obj;
|
||||
return true;
|
||||
}
|
||||
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryGetProperty<T>(this object source, PropertyInfo info, out T? result)
|
||||
{
|
||||
if (info.GetValue(source) is T obj) {
|
||||
result = obj;
|
||||
return true;
|
||||
}
|
||||
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static T? GetPropertyOrThrow<T>(this object source, string name,
|
||||
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic)
|
||||
{
|
||||
object? obj = source.GetType().GetPropertyInfoOrThrow(name, flags).GetValue(source);
|
||||
if (obj is T propertyOrThrow) {
|
||||
return propertyOrThrow;
|
||||
}
|
||||
if (obj == null) {
|
||||
if (typeof(T).IsValueType) {
|
||||
throw new Exception(name + " is a value type but the value is null.");
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
var stringBuilder = new StringBuilder(30, 3);
|
||||
stringBuilder.Append(name);
|
||||
stringBuilder.Append("'s type is ");
|
||||
stringBuilder.Append(source.GetType().Name);
|
||||
stringBuilder.Append(" but the value is ");
|
||||
stringBuilder.Append(obj.GetType().Name);
|
||||
stringBuilder.Append(".");
|
||||
throw new Exception(stringBuilder.ToString());
|
||||
}
|
||||
|
||||
public static T? GetPropertyOrThrow<T>(
|
||||
this object source,
|
||||
Type declareType,
|
||||
string name,
|
||||
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic)
|
||||
{
|
||||
object? obj = declareType.GetPropertyInfoOrThrow(name, flags).GetValue(source);
|
||||
if (obj is T propertyOrThrow) {
|
||||
return propertyOrThrow;
|
||||
}
|
||||
|
||||
if (obj == null) {
|
||||
if (typeof(T).IsValueType) {
|
||||
throw new Exception(name + " is a value type but the value is null.");
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
var stringHandler = new StringBuilder(30, 3);
|
||||
stringHandler.Append(name);
|
||||
stringHandler.Append("'s type is ");
|
||||
stringHandler.Append(declareType.Name);
|
||||
stringHandler.Append(" but the value is ");
|
||||
stringHandler.Append(obj.GetType().Name);
|
||||
stringHandler.Append(".");
|
||||
throw new Exception(stringHandler.ToString());
|
||||
}
|
||||
|
||||
public static bool TrySetProperty<T>(
|
||||
this object source,
|
||||
Type declareType,
|
||||
string name,
|
||||
T? value,
|
||||
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic)
|
||||
{
|
||||
PropertyInfo? property = declareType.GetProperty(name, flags);
|
||||
if (property is null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
property.SetValue(source, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool TryGetField<T>(
|
||||
this object source,
|
||||
string name,
|
||||
out T? result,
|
||||
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic)
|
||||
{
|
||||
FieldInfo? field = source.GetType().GetField(name, flags);
|
||||
if (field is not null && field.GetValue(source) is T obj) {
|
||||
result = obj;
|
||||
return true;
|
||||
}
|
||||
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryGetField<T>(
|
||||
this object source,
|
||||
Type declareType,
|
||||
string name,
|
||||
out T? result,
|
||||
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic)
|
||||
{
|
||||
FieldInfo? field = declareType.GetField(name, flags);
|
||||
if (field is not null && field.GetValue(source) is T obj) {
|
||||
result = obj;
|
||||
return true;
|
||||
}
|
||||
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryGetField<T>(this object source, FieldInfo info, out T? result)
|
||||
{
|
||||
if (info.GetValue(source) is T obj) {
|
||||
result = obj;
|
||||
return true;
|
||||
}
|
||||
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static T? GetFieldOrThrow<T>(this object source, string name,
|
||||
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic)
|
||||
{
|
||||
object? obj = source.GetType().GetFieldInfoOrThrow(name, flags).GetValue(source);
|
||||
if (obj is T fieldOrThrow) {
|
||||
return fieldOrThrow;
|
||||
}
|
||||
|
||||
if (obj == null) {
|
||||
if (typeof(T).IsValueType) {
|
||||
throw new Exception(name + " is a value type but the value is null.");
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
var stringBuilder = new StringBuilder(30, 3);
|
||||
stringBuilder.Append(name);
|
||||
stringBuilder.Append("'s type is ");
|
||||
stringBuilder.Append(source.GetType().Name);
|
||||
stringBuilder.Append(" but the value is ");
|
||||
stringBuilder.Append(obj.GetType().Name);
|
||||
stringBuilder.Append(".");
|
||||
throw new Exception(stringBuilder.ToString());
|
||||
}
|
||||
|
||||
public static T? GetFieldOrThrow<T>(
|
||||
this object source,
|
||||
Type declareType,
|
||||
string name,
|
||||
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic)
|
||||
{
|
||||
object? obj = declareType.GetFieldInfoOrThrow(name, flags).GetValue(source);
|
||||
if (obj is T fieldOrThrow) return fieldOrThrow;
|
||||
if (obj == null) {
|
||||
if (typeof(T).IsValueType) {
|
||||
throw new Exception(name + " is a value type but the value is null.");
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
var stringBuilder = new StringBuilder(30, 3);
|
||||
stringBuilder.Append(name);
|
||||
stringBuilder.Append("'s type is ");
|
||||
stringBuilder.Append(declareType);
|
||||
stringBuilder.Append(" but the value is ");
|
||||
stringBuilder.Append(obj.GetType().Name);
|
||||
stringBuilder.Append(".");
|
||||
throw new Exception(stringBuilder.ToString());
|
||||
}
|
||||
|
||||
public static bool TrySetField<T>(
|
||||
this object source,
|
||||
Type declareType,
|
||||
string name,
|
||||
T? value,
|
||||
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic)
|
||||
{
|
||||
FieldInfo? field = declareType.GetField(name, flags);
|
||||
if (field is null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
field.SetValue(source, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool TryInvokeMethod(
|
||||
this object source,
|
||||
Type declareType,
|
||||
string name,
|
||||
out object? result,
|
||||
params object[] parameters)
|
||||
{
|
||||
MethodInfo? method = declareType.GetMethod(name, BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
if (method is null) {
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
result = method.Invoke(source, parameters);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static object? InvokeMethodOrThrow(
|
||||
this object source,
|
||||
Type declareType,
|
||||
string name,
|
||||
params object[] parameters)
|
||||
{
|
||||
return declareType.GetMethodInfoOrThrow(name).Invoke(source, parameters);
|
||||
}
|
||||
}
|
73
src/AtomUI.Base/Reflection/TypeExtension.cs
Normal file
73
src/AtomUI.Base/Reflection/TypeExtension.cs
Normal file
@ -0,0 +1,73 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Reflection;
|
||||
|
||||
namespace AtomUI.Reflection;
|
||||
|
||||
public static class TypeExtension
|
||||
{
|
||||
public static bool TryGetPropertyInfo(
|
||||
this Type type,
|
||||
string name,
|
||||
[NotNullWhen(true)] out PropertyInfo? info,
|
||||
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic)
|
||||
{
|
||||
info = type.GetProperty(name, flags);
|
||||
return info is not null;
|
||||
}
|
||||
|
||||
public static bool TryGetFieldInfo(
|
||||
this Type type,
|
||||
string name,
|
||||
[NotNullWhen(true)] out FieldInfo? info,
|
||||
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic)
|
||||
{
|
||||
info = type.GetField(name, flags);
|
||||
return info is not null;
|
||||
}
|
||||
|
||||
public static bool TryGetMethodInfo(
|
||||
this Type type,
|
||||
string name,
|
||||
[NotNullWhen(true)] out MethodInfo? info,
|
||||
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic)
|
||||
{
|
||||
info = type.GetMethod(name, flags);
|
||||
return info is not null;
|
||||
}
|
||||
|
||||
public static PropertyInfo GetPropertyInfoOrThrow(
|
||||
this Type type,
|
||||
string name,
|
||||
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic)
|
||||
{
|
||||
PropertyInfo? info;
|
||||
if (!type.TryGetPropertyInfo(name, out info, flags)) {
|
||||
throw new NotSupportedException($"Can not find the '{name}' from type '{type}'. We can not reflect it.");
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
public static FieldInfo GetFieldInfoOrThrow(this Type type, string name,
|
||||
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic)
|
||||
{
|
||||
FieldInfo? info;
|
||||
if (!type.TryGetFieldInfo(name, out info, flags)) {
|
||||
throw new NotSupportedException($"Can not find the '{name}' from type '{type}'. We can not reflect it.");
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
public static MethodInfo GetMethodInfoOrThrow(this Type type, string name,
|
||||
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic)
|
||||
{
|
||||
MethodInfo? info;
|
||||
if (!type.TryGetMethodInfo(name, out info, flags)) {
|
||||
throw new NotSupportedException($"Can not find the '{name}' from type '{type}'. We can not reflect it.");
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
}
|
@ -168,7 +168,7 @@
|
||||
public const string TagBorderlessBg = "TagBorderlessBg";
|
||||
}
|
||||
|
||||
public static class TooltipResourceKey
|
||||
public static class ToolTipResourceKey
|
||||
{
|
||||
public const string TooltipMaxWidth = "TooltipMaxWidth";
|
||||
public const string TooltipColor = "TooltipColor";
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
using AvaloniaTooltip = Avalonia.Controls.ToolTip;
|
||||
|
||||
public partial class Tooltip : AvaloniaTooltip
|
||||
public partial class ToolTip : AvaloniaTooltip
|
||||
{
|
||||
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
namespace AtomUI.Controls.Tooltip;
|
||||
|
||||
public partial class Tooltip
|
||||
public partial class ToolTip
|
||||
{
|
||||
|
||||
}
|
8
src/AtomUI.Controls/Tooltip/ToolTipService.cs
Normal file
8
src/AtomUI.Controls/Tooltip/ToolTipService.cs
Normal file
@ -0,0 +1,8 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace AtomUI.Controls.Tooltip;
|
||||
|
||||
public class ToolTipService
|
||||
{
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
namespace AtomUI.Controls.Tooltip;
|
||||
|
||||
public class TooltipService
|
||||
public partial class ToolTip
|
||||
{
|
||||
|
||||
}
|
@ -4,11 +4,11 @@ using Avalonia.Media;
|
||||
namespace AtomUI.Controls.Tooltip;
|
||||
|
||||
[ControlDesignToken]
|
||||
internal class TooltipToken : AbstractControlDesignToken
|
||||
internal class ToolTipToken : AbstractControlDesignToken
|
||||
{
|
||||
public const string ID = "Tooltip";
|
||||
|
||||
public TooltipToken()
|
||||
public ToolTipToken()
|
||||
: base(ID)
|
||||
{
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
namespace AtomUI.Controls.Tooltip;
|
||||
|
||||
public partial class Tooltip
|
||||
{
|
||||
|
||||
}
|
14
src/AtomUI.Controls/Utils/IShadowLayer.cs
Normal file
14
src/AtomUI.Controls/Utils/IShadowLayer.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Media;
|
||||
|
||||
namespace AtomUI.Controls.Utils;
|
||||
|
||||
public interface IShadowLayer
|
||||
{
|
||||
public void AttachToTarget(Control control);
|
||||
public void SetShadowMaskGeometry(Geometry geometry);
|
||||
public void SetShadows(BoxShadows shadows);
|
||||
|
||||
public void ShowShadows();
|
||||
public void HideShadows();
|
||||
}
|
38
src/AtomUI.Controls/Utils/ShadowLayer.cs
Normal file
38
src/AtomUI.Controls/Utils/ShadowLayer.cs
Normal file
@ -0,0 +1,38 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Media;
|
||||
|
||||
namespace AtomUI.Controls.Utils;
|
||||
|
||||
public sealed class ShadowLayer : AvaloniaObject, IShadowLayer
|
||||
{
|
||||
public void AttachToTarget(Control control)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void SetShadowMaskGeometry(Geometry geometry)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void SetShadows(BoxShadows shadows)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void ShowShadows()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void HideShadows()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void CreateShadowRenderControl()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
114
src/AtomUI/Input/InputManagerEx.cs
Normal file
114
src/AtomUI/Input/InputManagerEx.cs
Normal file
@ -0,0 +1,114 @@
|
||||
using System.Reactive.Linq;
|
||||
using System.Reflection;
|
||||
using AtomUI.Reflection;
|
||||
using Avalonia;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Input.Raw;
|
||||
|
||||
namespace AtomUI.Input;
|
||||
|
||||
/// <summary>
|
||||
/// See <see cref="InputManager"/>.
|
||||
/// </summary>
|
||||
internal static class InputManagerEx
|
||||
{
|
||||
private static readonly PropertyInfo RootInfo;
|
||||
private static readonly PropertyInfo KeyInfo;
|
||||
private static readonly PropertyInfo ModifiersInfo;
|
||||
private static readonly PropertyInfo PositionInfo;
|
||||
private static readonly PropertyInfo TypeInfo;
|
||||
|
||||
static InputManagerEx()
|
||||
{
|
||||
// Input
|
||||
RootInfo = typeof(RawInputEventArgs).GetPropertyInfoOrThrow("Root", BindingFlags.Public | BindingFlags.Instance);
|
||||
|
||||
// Key
|
||||
KeyInfo = typeof(RawKeyEventArgs).GetPropertyInfoOrThrow("Key", BindingFlags.Public | BindingFlags.Instance);
|
||||
ModifiersInfo = typeof(RawKeyEventArgs).GetPropertyInfoOrThrow("Modifiers", BindingFlags.Public | BindingFlags.Instance);
|
||||
TypeInfo = typeof(RawKeyEventArgs).GetPropertyInfoOrThrow("Type", BindingFlags.Public | BindingFlags.Instance);
|
||||
|
||||
// Pointer
|
||||
PositionInfo = typeof(RawPointerEventArgs).GetPropertyInfoOrThrow("Position", BindingFlags.Public | BindingFlags.Instance);
|
||||
}
|
||||
|
||||
public static IInputRoot? Root(this RawInputEventArgs e) => RootInfo.GetValue(e) as IInputRoot;
|
||||
|
||||
public static Key Key(this RawKeyEventArgs e) => (Key)KeyInfo.GetValue(e)!;
|
||||
|
||||
public static RawInputModifiers Modifiers(this RawKeyEventArgs e) => (RawInputModifiers)ModifiersInfo.GetValue(e)!;
|
||||
|
||||
public static Point Position(this RawPointerEventArgs e) => (Point)PositionInfo.GetValue(e)!;
|
||||
|
||||
public static RawKeyEventType Type(this RawKeyEventArgs e) => (RawKeyEventType)TypeInfo.GetValue(e)!;
|
||||
|
||||
private static IObservable<TInputArgs> GetRawInputEventObservable<TInputArgs>(string processName)
|
||||
where TInputArgs : RawInputEventArgs
|
||||
{
|
||||
// Avalonia.Base
|
||||
var assembly = Assembly.GetAssembly(typeof(RawInputEventArgs));
|
||||
|
||||
// InputManager Type
|
||||
var type = assembly?.GetType("Avalonia.Input.InputManager")
|
||||
?? throw new NotSupportedException($"Can not find the type InputManager in assembly {assembly}.");
|
||||
|
||||
// InputManager.Instance
|
||||
var manager = type.GetPropertyOrThrow<IInputManager>(type, "Instance", BindingFlags.Public | BindingFlags.Static)
|
||||
?? throw new NotSupportedException($"Can not find the 'Instance' in type of InputManager.");
|
||||
|
||||
// InputManager.PreProcess | InputManager.Process | InputManager.PostProcess
|
||||
var process = manager.GetPropertyOrThrow<IObservable<RawInputEventArgs>>(type, processName, BindingFlags.Public | BindingFlags.Instance)
|
||||
?? throw new NotSupportedException($"Can not find the '{processName}' in InputManager.");
|
||||
|
||||
return process.OfType<TInputArgs>();
|
||||
}
|
||||
|
||||
private static IDisposable SubscribeRawInputEventCore<TInputArgs, TEnumType>(string processName, Func<TEnumType, bool>? filter,
|
||||
Action<TInputArgs> next)
|
||||
where TInputArgs : RawInputEventArgs
|
||||
where TEnumType : Enum
|
||||
{
|
||||
var observable = GetRawInputEventObservable<TInputArgs>(processName);
|
||||
|
||||
return observable
|
||||
.Where(x => filter == null || filter(x.GetPropertyOrThrow<TEnumType>(typeof(TInputArgs), "Type", BindingFlags.Public | BindingFlags.Instance)!))
|
||||
.Subscribe(next);
|
||||
}
|
||||
|
||||
public static IDisposable SubscribeRawKeyEvent(Func<RawKeyEventType, bool>? filter,
|
||||
Action<RawKeyEventArgs> next)
|
||||
{
|
||||
return SubscribeRawInputEventCore("Process", filter, next);
|
||||
}
|
||||
|
||||
public static IDisposable SubscribePreRawKeyEvent(Func<RawKeyEventType, bool>? filter,
|
||||
Action<RawKeyEventArgs> next)
|
||||
{
|
||||
return SubscribeRawInputEventCore("PreProcess", filter, next);
|
||||
}
|
||||
|
||||
public static IDisposable SubscribePostRawKeyEvent(Func<RawKeyEventType, bool>? filter,
|
||||
Action<RawKeyEventArgs> next)
|
||||
{
|
||||
return SubscribeRawInputEventCore("PostProcess", filter, next);
|
||||
}
|
||||
|
||||
public static IDisposable SubscribeRawPointerEvent(Func<RawPointerEventType, bool>? filter,
|
||||
Action<RawPointerEventArgs> next)
|
||||
{
|
||||
return SubscribeRawInputEventCore("Process", filter, next);
|
||||
}
|
||||
|
||||
public static IDisposable SubscribePreRawPointerEvent(Func<RawPointerEventType, bool>? filter,
|
||||
Action<RawPointerEventArgs> next)
|
||||
{
|
||||
return SubscribeRawInputEventCore("PreProcess", filter, next);
|
||||
}
|
||||
|
||||
public static IDisposable SubscribePostRawPointerEvent(Func<RawPointerEventType, bool>? filter,
|
||||
Action<RawPointerEventArgs> next)
|
||||
{
|
||||
return SubscribeRawInputEventCore("PostProcess", filter, next);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user