Adjust project structure
This commit is contained in:
1 parent
d38912f5da
commit
e3c436f939
2111 files changed
+14028
-47199
No files matched your search
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Media.Animation;
|
||||
|
||||
namespace HandyControl.Tools
|
||||
{
|
||||
/// <summary>
|
||||
/// 包含一些常用的动画辅助方法
|
||||
/// </summary>
|
||||
public class AnimationHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建一个Thickness动画
|
||||
/// </summary>
|
||||
/// <param name="thickness"></param>
|
||||
/// <param name="milliseconds"></param>
|
||||
/// <returns></returns>
|
||||
public static ThicknessAnimation CreateAnimation(Thickness thickness = default(Thickness), double milliseconds = 200)
|
||||
{
|
||||
return new ThicknessAnimation(thickness, new Duration(TimeSpan.FromMilliseconds(milliseconds)))
|
||||
{
|
||||
EasingFunction = new PowerEase { EasingMode = EasingMode.EaseInOut }
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个Double动画
|
||||
/// </summary>
|
||||
/// <param name="toValue"></param>
|
||||
/// <param name="milliseconds"></param>
|
||||
/// <returns></returns>
|
||||
public static DoubleAnimation CreateAnimation(double toValue, double milliseconds = 200)
|
||||
{
|
||||
return new DoubleAnimation(toValue, new Duration(TimeSpan.FromMilliseconds(milliseconds)))
|
||||
{
|
||||
EasingFunction = new PowerEase { EasingMode = EasingMode.EaseInOut }
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Media.Media3D;
|
||||
|
||||
namespace HandyControl.Tools
|
||||
{
|
||||
/// <summary>
|
||||
/// 包含内部使用的一些简单算法
|
||||
/// </summary>
|
||||
internal class ArithmeticHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 平分一个整数到一个数组中
|
||||
/// </summary>
|
||||
/// <param name="num"></param>
|
||||
/// <param name="count"></param>
|
||||
/// <returns></returns>
|
||||
public static int[] DivideInt2Arr(int num, int count)
|
||||
{
|
||||
var arr = new int[count];
|
||||
var div = num / count;
|
||||
var rest = num % count;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
arr[i] = div;
|
||||
}
|
||||
for (int i = 0; i < rest; i++)
|
||||
{
|
||||
arr[i] += 1;
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算控件在窗口中的可见坐标
|
||||
/// </summary>
|
||||
public static Point CalSafePoint(FrameworkElement element, FrameworkElement showElement, Thickness thickness = default(Thickness))
|
||||
{
|
||||
if (element == null || showElement == null) return default(Point);
|
||||
var point = element.PointToScreen(new Point(0, 0));
|
||||
|
||||
if (point.X < 0) point.X = 0;
|
||||
if (point.Y < 0) point.Y = 0;
|
||||
|
||||
var maxLeft = SystemParameters.WorkArea.Width -
|
||||
((double.IsNaN(showElement.Width) ? showElement.ActualWidth : showElement.Width) +
|
||||
thickness.Left + thickness.Right);
|
||||
var maxTop = SystemParameters.WorkArea.Height -
|
||||
((double.IsNaN(showElement.Height) ? showElement.ActualHeight : showElement.Height) +
|
||||
thickness.Top + thickness.Bottom);
|
||||
return new Point(maxLeft > point.X ? point.X : maxLeft, maxTop > point.Y ? point.Y : maxTop);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取布局范围框
|
||||
/// </summary>
|
||||
/// <param name="element"></param>
|
||||
/// <returns></returns>
|
||||
public static Rect GetLayoutRect(FrameworkElement element)
|
||||
{
|
||||
var num1 = element.ActualWidth;
|
||||
var num2 = element.ActualHeight;
|
||||
if (element is Image || element is MediaElement)
|
||||
if (element.Parent is Canvas)
|
||||
{
|
||||
num1 = double.IsNaN(element.Width) ? num1 : element.Width;
|
||||
num2 = double.IsNaN(element.Height) ? num2 : element.Height;
|
||||
}
|
||||
else
|
||||
{
|
||||
num1 = element.RenderSize.Width;
|
||||
num2 = element.RenderSize.Height;
|
||||
}
|
||||
var width = element.Visibility == Visibility.Collapsed ? 0.0 : num1;
|
||||
var height = element.Visibility == Visibility.Collapsed ? 0.0 : num2;
|
||||
var margin = element.Margin;
|
||||
var layoutSlot = LayoutInformation.GetLayoutSlot(element);
|
||||
var x = 0.0;
|
||||
var y = 0.0;
|
||||
switch (element.HorizontalAlignment)
|
||||
{
|
||||
case HorizontalAlignment.Left:
|
||||
x = layoutSlot.Left + margin.Left;
|
||||
break;
|
||||
case HorizontalAlignment.Center:
|
||||
x = (layoutSlot.Left + margin.Left + layoutSlot.Right - margin.Right) / 2.0 - width / 2.0;
|
||||
break;
|
||||
case HorizontalAlignment.Right:
|
||||
x = layoutSlot.Right - margin.Right - width;
|
||||
break;
|
||||
case HorizontalAlignment.Stretch:
|
||||
x = Math.Max(layoutSlot.Left + margin.Left,
|
||||
(layoutSlot.Left + margin.Left + layoutSlot.Right - margin.Right) / 2.0 - width / 2.0);
|
||||
break;
|
||||
}
|
||||
switch (element.VerticalAlignment)
|
||||
{
|
||||
case VerticalAlignment.Top:
|
||||
y = layoutSlot.Top + margin.Top;
|
||||
break;
|
||||
case VerticalAlignment.Center:
|
||||
y = (layoutSlot.Top + margin.Top + layoutSlot.Bottom - margin.Bottom) / 2.0 - height / 2.0;
|
||||
break;
|
||||
case VerticalAlignment.Bottom:
|
||||
y = layoutSlot.Bottom - margin.Bottom - height;
|
||||
break;
|
||||
case VerticalAlignment.Stretch:
|
||||
y = Math.Max(layoutSlot.Top + margin.Top,
|
||||
(layoutSlot.Top + margin.Top + layoutSlot.Bottom - margin.Bottom) / 2.0 - height / 2.0);
|
||||
break;
|
||||
}
|
||||
return new Rect(x, y, width, height);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算两点的连线和x轴的夹角
|
||||
/// </summary>
|
||||
/// <param name="center"></param>
|
||||
/// <param name="p"></param>
|
||||
/// <returns></returns>
|
||||
public static double CalAngle(Point center, Point p) => Math.Atan2(p.Y - center.Y, p.X - center.X) * 180 / Math.PI;
|
||||
|
||||
/// <summary>
|
||||
/// 判断是否是有效的双精度浮点数
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsValidDoubleValue(object value)
|
||||
{
|
||||
var d = (double)value;
|
||||
if (!double.IsNaN(d))
|
||||
return !double.IsInfinity(d);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算法线
|
||||
/// </summary>
|
||||
/// <param name="p0"></param>
|
||||
/// <param name="p1"></param>
|
||||
/// <param name="p2"></param>
|
||||
/// <returns></returns>
|
||||
public static Vector3D CalNormal(Point3D p0, Point3D p1, Point3D p2)
|
||||
{
|
||||
var v0 = new Vector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
|
||||
var v1 = new Vector3D(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
|
||||
return Vector3D.CrossProduct(v0, v1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace HandyControl.Tools
|
||||
{
|
||||
public class ColorHelper
|
||||
{
|
||||
private const int Win32RedShift = 0;
|
||||
private const int Win32GreenShift = 8;
|
||||
private const int Win32BlueShift = 16;
|
||||
|
||||
public static int ToWin32(Color c) => c.R << Win32RedShift | c.G << Win32GreenShift | c.B << Win32BlueShift;
|
||||
|
||||
public static Color ToColor(uint c)
|
||||
{
|
||||
var bytes = BitConverter.GetBytes(c);
|
||||
return Color.FromArgb(bytes[3], bytes[2], bytes[1], bytes[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace HandyControl.Tools
|
||||
{
|
||||
internal class CreateParams
|
||||
{
|
||||
public string ClassName { get; set; }
|
||||
|
||||
public string Caption { get; set; }
|
||||
|
||||
public int Style { get; set; }
|
||||
|
||||
public int ExStyle{ get; set; }
|
||||
|
||||
public int ClassStyle { get; set; }
|
||||
|
||||
public int X { get; set; }
|
||||
|
||||
public int Y { get; set; }
|
||||
|
||||
public int Width { get; set; }
|
||||
|
||||
public int Height { get; set; }
|
||||
|
||||
public IntPtr Parent { get; set; }
|
||||
|
||||
public object Param { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var sb = new StringBuilder(64);
|
||||
sb.Append("CreateParams {'");
|
||||
sb.Append(ClassName);
|
||||
sb.Append("', '");
|
||||
sb.Append(Caption);
|
||||
sb.Append("', 0x");
|
||||
sb.Append(Convert.ToString(Style, 16));
|
||||
sb.Append(", 0x");
|
||||
sb.Append(Convert.ToString(ExStyle, 16));
|
||||
sb.Append(", {");
|
||||
sb.Append(X);
|
||||
sb.Append(", ");
|
||||
sb.Append(Y);
|
||||
sb.Append(", ");
|
||||
sb.Append(Width);
|
||||
sb.Append(", ");
|
||||
sb.Append(Height);
|
||||
sb.Append("}");
|
||||
sb.Append("}");
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
|
||||
namespace HandyControl.Tools
|
||||
{
|
||||
public class DesignerHelper
|
||||
{
|
||||
private static bool? _isInDesignMode;
|
||||
|
||||
public static bool IsInDesignMode
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_isInDesignMode.HasValue)
|
||||
{
|
||||
_isInDesignMode = (bool)DependencyPropertyDescriptor.FromProperty(DesignerProperties.IsInDesignModeProperty, typeof(FrameworkElement)).Metadata.DefaultValue;
|
||||
}
|
||||
return _isInDesignMode.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,362 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Security.Permissions;
|
||||
using System.Threading;
|
||||
|
||||
namespace HandyControl.Tools
|
||||
{
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
internal class ExternDllHelper
|
||||
{
|
||||
private const string Gdi32 = "gdi32.dll";
|
||||
|
||||
private const string User32 = "user32.dll";
|
||||
|
||||
public const int E_FAIL = unchecked((int) 0x80004005);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct WINCOMPATTRDATA
|
||||
{
|
||||
public WINDOWCOMPOSITIONATTRIB Attribute;
|
||||
public IntPtr Data;
|
||||
public int DataSize;
|
||||
}
|
||||
|
||||
internal enum WINDOWCOMPOSITIONATTRIB
|
||||
{
|
||||
WCA_ACCENT_POLICY = 19
|
||||
}
|
||||
|
||||
internal enum ACCENTSTATE
|
||||
{
|
||||
ACCENT_DISABLED = 0,
|
||||
ACCENT_ENABLE_GRADIENT = 1,
|
||||
ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
|
||||
ACCENT_ENABLE_BLURBEHIND = 3,
|
||||
ACCENT_ENABLE_ACRYLICBLURBEHIND = 4,
|
||||
ACCENT_INVALID_STATE = 5
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct ACCENTPOLICY
|
||||
{
|
||||
public ACCENTSTATE AccentState;
|
||||
public int AccentFlags;
|
||||
public uint GradientColor;
|
||||
public int AnimationId;
|
||||
}
|
||||
|
||||
[DllImport(User32)]
|
||||
internal static extern int SetWindowCompositionAttribute(IntPtr hwnd, ref WINCOMPATTRDATA data);
|
||||
|
||||
[ReflectionPermission(SecurityAction.Assert, Unrestricted = true), SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.UnmanagedCode)]
|
||||
public static object PtrToStructure(IntPtr lparam, Type cls) => Marshal.PtrToStructure(lparam, cls);
|
||||
|
||||
[DllImport(Gdi32, CharSet = CharSet.Auto, SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool DeleteObject(IntPtr hObject);
|
||||
|
||||
[ComImport, Guid("0000000C-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
public interface IStream
|
||||
{
|
||||
int Read(
|
||||
[In]
|
||||
IntPtr buf,
|
||||
[In]
|
||||
int len);
|
||||
|
||||
int Write(
|
||||
[In]
|
||||
IntPtr buf,
|
||||
[In]
|
||||
int len);
|
||||
|
||||
[return: MarshalAs(UnmanagedType.I8)]
|
||||
long Seek(
|
||||
[In, MarshalAs(UnmanagedType.I8)]
|
||||
long dlibMove,
|
||||
[In]
|
||||
int dwOrigin);
|
||||
|
||||
void SetSize(
|
||||
[In, MarshalAs(UnmanagedType.I8)]
|
||||
long libNewSize);
|
||||
|
||||
[return: MarshalAs(UnmanagedType.I8)]
|
||||
long CopyTo(
|
||||
[In, MarshalAs(UnmanagedType.Interface)]
|
||||
IStream pstm,
|
||||
[In, MarshalAs(UnmanagedType.I8)]
|
||||
long cb,
|
||||
[Out, MarshalAs(UnmanagedType.LPArray)]
|
||||
long[] pcbRead);
|
||||
|
||||
void Commit(
|
||||
[In]
|
||||
int grfCommitFlags);
|
||||
|
||||
void Revert();
|
||||
|
||||
void LockRegion(
|
||||
[In, MarshalAs(UnmanagedType.I8)]
|
||||
long libOffset,
|
||||
[In, MarshalAs(UnmanagedType.I8)]
|
||||
long cb,
|
||||
[In]
|
||||
int dwLockType);
|
||||
|
||||
void UnlockRegion(
|
||||
[In, MarshalAs(UnmanagedType.I8)]
|
||||
long libOffset,
|
||||
[In, MarshalAs(UnmanagedType.I8)]
|
||||
long cb,
|
||||
[In]
|
||||
int dwLockType);
|
||||
|
||||
void Stat(
|
||||
[In]
|
||||
IntPtr pStatstg,
|
||||
[In]
|
||||
int grfStatFlag);
|
||||
|
||||
[return: MarshalAs(UnmanagedType.Interface)]
|
||||
IStream Clone();
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public class StreamConsts
|
||||
{
|
||||
public const int LOCK_WRITE = 0x1;
|
||||
public const int LOCK_EXCLUSIVE = 0x2;
|
||||
public const int LOCK_ONLYONCE = 0x4;
|
||||
public const int STATFLAG_DEFAULT = 0x0;
|
||||
public const int STATFLAG_NONAME = 0x1;
|
||||
public const int STATFLAG_NOOPEN = 0x2;
|
||||
public const int STGC_DEFAULT = 0x0;
|
||||
public const int STGC_OVERWRITE = 0x1;
|
||||
public const int STGC_ONLYIFCURRENT = 0x2;
|
||||
public const int STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE = 0x4;
|
||||
public const int STREAM_SEEK_SET = 0x0;
|
||||
public const int STREAM_SEEK_CUR = 0x1;
|
||||
public const int STREAM_SEEK_END = 0x2;
|
||||
}
|
||||
|
||||
internal class Gdip
|
||||
{
|
||||
private const string Gdiplus = "gdiplus.dll";
|
||||
|
||||
private const string ThreadDataSlotName = "system.drawing.threaddata";
|
||||
|
||||
private static IntPtr InitToken;
|
||||
|
||||
private static bool Initialized => InitToken != IntPtr.Zero;
|
||||
|
||||
static Gdip()
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct StartupInput
|
||||
{
|
||||
private int GdiplusVersion;
|
||||
|
||||
private readonly IntPtr DebugEventCallback;
|
||||
|
||||
private bool SuppressBackgroundThread;
|
||||
|
||||
private bool SuppressExternalCodecs;
|
||||
|
||||
public static StartupInput GetDefault()
|
||||
{
|
||||
var result = new StartupInput
|
||||
{
|
||||
GdiplusVersion = 1,
|
||||
SuppressBackgroundThread = false,
|
||||
SuppressExternalCodecs = false
|
||||
};
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct StartupOutput
|
||||
{
|
||||
private readonly IntPtr hook;
|
||||
|
||||
private readonly IntPtr unhook;
|
||||
}
|
||||
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
[ResourceConsumption(ResourceScope.AppDomain, ResourceScope.AppDomain)]
|
||||
[SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals")]
|
||||
private static void Initialize()
|
||||
{
|
||||
var input = StartupInput.GetDefault();
|
||||
|
||||
var status = GdiplusStartup(out InitToken, ref input, out _);
|
||||
|
||||
if (status != Ok)
|
||||
{
|
||||
throw StatusException(status);
|
||||
}
|
||||
|
||||
var currentDomain = AppDomain.CurrentDomain;
|
||||
currentDomain.ProcessExit += OnProcessExit;
|
||||
|
||||
if (!currentDomain.IsDefaultAppDomain())
|
||||
{
|
||||
currentDomain.DomainUnload += OnProcessExit;
|
||||
}
|
||||
}
|
||||
|
||||
[PrePrepareMethod]
|
||||
[ResourceExposure(ResourceScope.AppDomain)]
|
||||
[ResourceConsumption(ResourceScope.AppDomain)]
|
||||
private static void OnProcessExit(object sender, EventArgs e) => Shutdown();
|
||||
|
||||
[SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods")]
|
||||
[ResourceExposure(ResourceScope.AppDomain)]
|
||||
[ResourceConsumption(ResourceScope.AppDomain)]
|
||||
private static void Shutdown()
|
||||
{
|
||||
if (Initialized)
|
||||
{
|
||||
ClearThreadData();
|
||||
// unhook our shutdown handlers as we do not need to shut down more than once
|
||||
var currentDomain = AppDomain.CurrentDomain;
|
||||
currentDomain.ProcessExit -= OnProcessExit;
|
||||
if (!currentDomain.IsDefaultAppDomain())
|
||||
{
|
||||
currentDomain.DomainUnload -= OnProcessExit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
private static void ClearThreadData()
|
||||
{
|
||||
var slot = Thread.GetNamedDataSlot(ThreadDataSlotName);
|
||||
Thread.SetData(slot, null);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
// Status codes
|
||||
//----------------------------------------------------------------------------------------
|
||||
internal const int Ok = 0;
|
||||
internal const int GenericError = 1;
|
||||
internal const int InvalidParameter = 2;
|
||||
internal const int OutOfMemory = 3;
|
||||
internal const int ObjectBusy = 4;
|
||||
internal const int InsufficientBuffer = 5;
|
||||
internal const int NotImplemented = 6;
|
||||
internal const int Win32Error = 7;
|
||||
internal const int WrongState = 8;
|
||||
internal const int Aborted = 9;
|
||||
internal const int FileNotFound = 10;
|
||||
internal const int ValueOverflow = 11;
|
||||
internal const int AccessDenied = 12;
|
||||
internal const int UnknownImageFormat = 13;
|
||||
internal const int FontFamilyNotFound = 14;
|
||||
internal const int FontStyleNotFound = 15;
|
||||
internal const int NotTrueTypeFont = 16;
|
||||
internal const int UnsupportedGdiplusVersion = 17;
|
||||
internal const int GdiplusNotInitialized = 18;
|
||||
internal const int PropertyNotFound = 19;
|
||||
internal const int PropertyNotSupported = 20;
|
||||
|
||||
[DllImport(Gdiplus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
internal static extern int GdipImageGetFrameDimensionsCount(HandleRef image, out int count);
|
||||
|
||||
internal static Exception StatusException(int status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case GenericError: return new ExternalException("GdiplusGenericError");
|
||||
case InvalidParameter: return new ArgumentException("GdiplusInvalidParameter");
|
||||
case OutOfMemory: return new OutOfMemoryException("GdiplusOutOfMemory");
|
||||
case ObjectBusy: return new InvalidOperationException("GdiplusObjectBusy");
|
||||
case InsufficientBuffer: return new OutOfMemoryException("GdiplusInsufficientBuffer");
|
||||
case NotImplemented: return new NotImplementedException("GdiplusNotImplemented");
|
||||
case Win32Error: return new ExternalException("GdiplusGenericError");
|
||||
case WrongState: return new InvalidOperationException("GdiplusWrongState");
|
||||
case Aborted: return new ExternalException("GdiplusAborted");
|
||||
case FileNotFound: return new FileNotFoundException("GdiplusFileNotFound");
|
||||
case ValueOverflow: return new OverflowException("GdiplusOverflow");
|
||||
case AccessDenied: return new ExternalException("GdiplusAccessDenied");
|
||||
case UnknownImageFormat: return new ArgumentException("GdiplusUnknownImageFormat");
|
||||
case PropertyNotFound: return new ArgumentException("GdiplusPropertyNotFoundError");
|
||||
case PropertyNotSupported: return new ArgumentException("GdiplusPropertyNotSupportedError");
|
||||
case FontFamilyNotFound: return new ArgumentException("GdiplusFontFamilyNotFound");
|
||||
case FontStyleNotFound: return new ArgumentException("GdiplusFontStyleNotFound");
|
||||
case NotTrueTypeFont: return new ArgumentException("GdiplusNotTrueTypeFont_NoName");
|
||||
case UnsupportedGdiplusVersion: return new ExternalException("GdiplusUnsupportedGdiplusVersion");
|
||||
case GdiplusNotInitialized: return new ExternalException("GdiplusNotInitialized");
|
||||
}
|
||||
|
||||
return new ExternalException("GdiplusUnknown");
|
||||
}
|
||||
|
||||
[DllImport(Gdiplus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
internal static extern int GdipImageGetFrameDimensionsList(HandleRef image, IntPtr buffer, int count);
|
||||
|
||||
[DllImport(Gdiplus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
internal static extern int GdipImageGetFrameCount(HandleRef image, ref Guid dimensionId, int[] count);
|
||||
|
||||
[DllImport(Gdiplus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
internal static extern int GdipGetPropertyItemSize(HandleRef image, int propid, out int size);
|
||||
|
||||
[DllImport(Gdiplus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
internal static extern int GdipGetPropertyItem(HandleRef image, int propid, int size, IntPtr buffer);
|
||||
|
||||
[DllImport(Gdiplus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
|
||||
[ResourceExposure(ResourceScope.Machine)]
|
||||
internal static extern int GdipCreateHBITMAPFromBitmap(HandleRef nativeBitmap, out IntPtr hbitmap, int argbBackground);
|
||||
|
||||
[DllImport(Gdiplus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
internal static extern int GdipImageSelectActiveFrame(HandleRef image, ref Guid dimensionId, int frameIndex);
|
||||
|
||||
[DllImport(Gdiplus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
|
||||
[ResourceExposure(ResourceScope.Machine)]
|
||||
internal static extern int GdipCreateBitmapFromFile(string filename, out IntPtr bitmap);
|
||||
|
||||
[DllImport(Gdiplus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
internal static extern int GdipImageForceValidation(HandleRef image);
|
||||
|
||||
[DllImport(Gdiplus, SetLastError = true, ExactSpelling = true, EntryPoint = "GdipDisposeImage", CharSet = CharSet.Unicode)]
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
private static extern int IntGdipDisposeImage(HandleRef image);
|
||||
|
||||
internal static int GdipDisposeImage(HandleRef image)
|
||||
{
|
||||
if (!Initialized) return Ok;
|
||||
var result = IntGdipDisposeImage(image);
|
||||
return result;
|
||||
}
|
||||
|
||||
[DllImport(Gdiplus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
|
||||
[ResourceExposure(ResourceScope.Process)]
|
||||
private static extern int GdiplusStartup(out IntPtr token, ref StartupInput input, out StartupOutput output);
|
||||
|
||||
[DllImport(Gdiplus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
internal static extern int GdipGetImageRawFormat(HandleRef image, ref Guid format);
|
||||
|
||||
[DllImport(Gdiplus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
|
||||
[ResourceExposure(ResourceScope.Machine)]
|
||||
internal static extern int GdipCreateBitmapFromStream(IStream stream, out IntPtr bitmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,294 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using HandyControl.Tools.Interop;
|
||||
|
||||
namespace HandyControl.Tools
|
||||
{
|
||||
internal static class IconHelper
|
||||
{
|
||||
private static Size SmallIconSize;
|
||||
|
||||
private static Size IconSize;
|
||||
|
||||
private static int SystemBitDepth;
|
||||
|
||||
[SecurityCritical, SecuritySafeCritical]
|
||||
public static void GetIconHandlesFromImageSource(ImageSource image, out IconHandle largeIconHandle, out IconHandle smallIconHandle)
|
||||
{
|
||||
EnsureSystemMetrics();
|
||||
largeIconHandle = CreateIconHandleFromImageSource(image, IconSize);
|
||||
smallIconHandle = CreateIconHandleFromImageSource(image, SmallIconSize);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public static IconHandle CreateIconHandleFromImageSource(ImageSource image, Size size)
|
||||
{
|
||||
EnsureSystemMetrics();
|
||||
|
||||
var asGoodAsItGets = false;
|
||||
|
||||
var bf = image as BitmapFrame;
|
||||
if (bf?.Decoder?.Frames != null)
|
||||
{
|
||||
bf = GetBestMatch(bf.Decoder.Frames, size);
|
||||
|
||||
asGoodAsItGets = bf.Decoder is IconBitmapDecoder || bf.PixelWidth == (int)size.Width && bf.PixelHeight == (int)size.Height;
|
||||
|
||||
image = bf;
|
||||
}
|
||||
|
||||
if (!asGoodAsItGets)
|
||||
{
|
||||
bf = BitmapFrame.Create(GenerateBitmapSource(image, size));
|
||||
}
|
||||
|
||||
return CreateIconHandleFromBitmapFrame(bf);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
private static IconHandle CreateIconHandleFromBitmapFrame(BitmapFrame sourceBitmapFrame)
|
||||
{
|
||||
BitmapSource bitmapSource = sourceBitmapFrame;
|
||||
|
||||
if (bitmapSource.Format != PixelFormats.Bgra32 && bitmapSource.Format != PixelFormats.Pbgra32)
|
||||
{
|
||||
bitmapSource = new FormatConvertedBitmap(bitmapSource, PixelFormats.Bgra32, null, 0.0);
|
||||
}
|
||||
|
||||
var w = bitmapSource.PixelWidth;
|
||||
var h = bitmapSource.PixelHeight;
|
||||
var bpp = bitmapSource.Format.BitsPerPixel;
|
||||
var stride = (bpp * w + 31) / 32 * 4;
|
||||
var sizeCopyPixels = stride * h;
|
||||
var xor = new byte[sizeCopyPixels];
|
||||
bitmapSource.CopyPixels(xor, stride, 0);
|
||||
|
||||
return CreateIconCursor(xor, w, h, 0, 0, true);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
internal static IconHandle CreateIconCursor(byte[] colorArray, int width, int height, int xHotspot, int yHotspot, bool isIcon)
|
||||
{
|
||||
BitmapHandle colorBitmap = null;
|
||||
BitmapHandle maskBitmap = null;
|
||||
|
||||
try
|
||||
{
|
||||
var bi = new BITMAPINFO(width, -height, 32)
|
||||
{
|
||||
bmiHeader_biCompression = NativeMethods.BI_RGB
|
||||
};
|
||||
|
||||
var bits = IntPtr.Zero;
|
||||
colorBitmap = UnsafeNativeMethods.CreateDIBSection(new HandleRef(null, IntPtr.Zero), ref bi, NativeMethods.DIB_RGB_COLORS, ref bits, null, 0);
|
||||
|
||||
if (colorBitmap.IsInvalid || bits == IntPtr.Zero)
|
||||
{
|
||||
return IconHandle.GetInvalidIcon();
|
||||
}
|
||||
|
||||
Marshal.Copy(colorArray, 0, bits, colorArray.Length);
|
||||
var maskArray = GenerateMaskArray(width, height, colorArray);
|
||||
|
||||
maskBitmap = UnsafeNativeMethods.CreateBitmap(width, height, 1, 1, maskArray);
|
||||
if (maskBitmap.IsInvalid)
|
||||
{
|
||||
return IconHandle.GetInvalidIcon();
|
||||
}
|
||||
|
||||
var iconInfo = new ICONINFO
|
||||
{
|
||||
fIcon = isIcon,
|
||||
xHotspot = xHotspot,
|
||||
yHotspot = yHotspot,
|
||||
hbmMask = maskBitmap,
|
||||
hbmColor = colorBitmap
|
||||
};
|
||||
|
||||
return UnsafeNativeMethods.CreateIconIndirect(iconInfo);
|
||||
}
|
||||
finally
|
||||
{
|
||||
colorBitmap?.Dispose();
|
||||
maskBitmap?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] GenerateMaskArray(int width, int height, byte[] colorArray)
|
||||
{
|
||||
var nCount = width * height;
|
||||
var bytesPerScanLine = AlignToBytes(width, 2) / 8;
|
||||
var bitsMask = new byte[bytesPerScanLine * height];
|
||||
|
||||
for (var i = 0; i < nCount; i++)
|
||||
{
|
||||
var hPos = i % width;
|
||||
var vPos = i / width;
|
||||
var byteIndex = hPos / 8;
|
||||
var offsetBit = (byte)(0x80 >> (hPos % 8));
|
||||
|
||||
if (colorArray[i * 4 + 3] == 0x00)
|
||||
{
|
||||
bitsMask[byteIndex + bytesPerScanLine * vPos] |= offsetBit;
|
||||
}
|
||||
else
|
||||
{
|
||||
bitsMask[byteIndex + bytesPerScanLine * vPos] &= (byte)~offsetBit;
|
||||
}
|
||||
|
||||
if (hPos == width - 1 && width == 8)
|
||||
{
|
||||
bitsMask[1 + bytesPerScanLine * vPos] = 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
return bitsMask;
|
||||
}
|
||||
|
||||
internal static int AlignToBytes(double original, int nBytesCount)
|
||||
{
|
||||
var nBitsCount = 8 << (nBytesCount - 1);
|
||||
return ((int)Math.Ceiling(original) + (nBitsCount - 1)) / nBitsCount * nBitsCount;
|
||||
}
|
||||
|
||||
private static BitmapSource GenerateBitmapSource(ImageSource img, Size renderSize)
|
||||
{
|
||||
var drawingDimensions = new Rect(0, 0, renderSize.Width, renderSize.Height);
|
||||
|
||||
var renderRatio = renderSize.Width / renderSize.Height;
|
||||
var aspectRatio = img.Width / img.Height;
|
||||
|
||||
if (img.Width <= renderSize.Width && img.Height <= renderSize.Height)
|
||||
{
|
||||
drawingDimensions = new Rect((renderSize.Width - img.Width) / 2, (renderSize.Height - img.Height) / 2, img.Width, img.Height);
|
||||
}
|
||||
else if (renderRatio > aspectRatio)
|
||||
{
|
||||
var scaledRenderWidth = (img.Width / img.Height) * renderSize.Width;
|
||||
drawingDimensions = new Rect((renderSize.Width - scaledRenderWidth) / 2, 0, scaledRenderWidth, renderSize.Height);
|
||||
}
|
||||
else if (renderRatio < aspectRatio)
|
||||
{
|
||||
var scaledRenderHeight = img.Height / img.Width * renderSize.Height;
|
||||
drawingDimensions = new Rect(0, (renderSize.Height - scaledRenderHeight) / 2, renderSize.Width, scaledRenderHeight);
|
||||
}
|
||||
|
||||
var dv = new DrawingVisual();
|
||||
var dc = dv.RenderOpen();
|
||||
dc.DrawImage(img, drawingDimensions);
|
||||
dc.Close();
|
||||
|
||||
var bmp = new RenderTargetBitmap((int)renderSize.Width, (int)renderSize.Height, 96, 96, PixelFormats.Pbgra32);
|
||||
bmp.Render(dv);
|
||||
|
||||
return bmp;
|
||||
}
|
||||
|
||||
private static BitmapFrame GetBestMatch(ReadOnlyCollection<BitmapFrame> frames, Size size)
|
||||
{
|
||||
var bestScore = int.MaxValue;
|
||||
var bestBpp = 0;
|
||||
var bestIndex = 0;
|
||||
|
||||
var isBitmapIconDecoder = frames[0].Decoder is IconBitmapDecoder;
|
||||
|
||||
for (int i = 0; i < frames.Count && bestScore != 0; ++i)
|
||||
{
|
||||
var currentIconBitDepth = isBitmapIconDecoder ? frames[i].Thumbnail.Format.BitsPerPixel : frames[i].Format.BitsPerPixel;
|
||||
|
||||
if (currentIconBitDepth == 0)
|
||||
{
|
||||
currentIconBitDepth = 8;
|
||||
}
|
||||
|
||||
var score = MatchImage(frames[i], size, currentIconBitDepth);
|
||||
if (score < bestScore)
|
||||
{
|
||||
bestIndex = i;
|
||||
bestBpp = currentIconBitDepth;
|
||||
bestScore = score;
|
||||
}
|
||||
else if (score == bestScore)
|
||||
{
|
||||
if (bestBpp < currentIconBitDepth)
|
||||
{
|
||||
bestIndex = i;
|
||||
bestBpp = currentIconBitDepth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return frames[bestIndex];
|
||||
}
|
||||
|
||||
private static int MatchImage(BitmapFrame frame, Size size, int bpp)
|
||||
{
|
||||
var score = 2 * MyAbs(bpp, SystemBitDepth, false) +
|
||||
MyAbs(frame.PixelWidth, (int)size.Width, true) +
|
||||
MyAbs(frame.PixelHeight, (int)size.Height, true);
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
private static int MyAbs(int valueHave, int valueWant, bool fPunish)
|
||||
{
|
||||
var diff = (valueHave - valueWant);
|
||||
|
||||
if (diff < 0)
|
||||
{
|
||||
diff = (fPunish ? -2 : -1) * diff;
|
||||
}
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
[SecurityCritical, SecuritySafeCritical]
|
||||
private static void EnsureSystemMetrics()
|
||||
{
|
||||
if (SystemBitDepth == 0)
|
||||
{
|
||||
var hdcDesktop = new HandleRef(null, UnsafeNativeMethods.GetDC(new HandleRef()));
|
||||
try
|
||||
{
|
||||
var sysBitDepth = UnsafeNativeMethods.GetDeviceCaps(hdcDesktop, NativeMethods.BITSPIXEL);
|
||||
sysBitDepth *= UnsafeNativeMethods.GetDeviceCaps(hdcDesktop, NativeMethods.PLANES);
|
||||
|
||||
if (sysBitDepth == 8)
|
||||
{
|
||||
sysBitDepth = 4;
|
||||
}
|
||||
|
||||
var cxSmallIcon = UnsafeNativeMethods.GetSystemMetrics(SM.CXSMICON);
|
||||
var cySmallIcon = UnsafeNativeMethods.GetSystemMetrics(SM.CYSMICON);
|
||||
var cxIcon = UnsafeNativeMethods.GetSystemMetrics(SM.CXICON);
|
||||
var cyIcon = UnsafeNativeMethods.GetSystemMetrics(SM.CYICON);
|
||||
|
||||
SmallIconSize = new Size(cxSmallIcon, cySmallIcon);
|
||||
IconSize = new Size(cxIcon, cyIcon);
|
||||
SystemBitDepth = sysBitDepth;
|
||||
}
|
||||
finally
|
||||
{
|
||||
UnsafeNativeMethods.ReleaseDC(new HandleRef(), hdcDesktop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SecurityCritical, SecuritySafeCritical]
|
||||
public static void GetDefaultIconHandles(out IconHandle largeIconHandle, out IconHandle smallIconHandle)
|
||||
{
|
||||
largeIconHandle = null;
|
||||
smallIconHandle = null;
|
||||
|
||||
SecurityHelper.DemandUIWindowPermission();
|
||||
|
||||
var iconModuleFile = UnsafeNativeMethods.GetModuleFileName(new HandleRef());
|
||||
UnsafeNativeMethods.ExtractIconEx(iconModuleFile, 0, out largeIconHandle, out smallIconHandle, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Windows;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Tools
|
||||
{
|
||||
/// <summary>
|
||||
/// 资源帮助类
|
||||
/// </summary>
|
||||
public class ResourceHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取字符串
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetString(string key) => Application.Current.TryFindResource(key) as string;
|
||||
|
||||
/// <summary>
|
||||
/// 获取字符串
|
||||
/// </summary>
|
||||
/// <param name="separator"></param>
|
||||
/// <param name="keyArr"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetString(string separator = ";", params string[] keyArr) =>
|
||||
string.Join(separator, keyArr.Select(key => Application.Current.TryFindResource(key) as string).ToList());
|
||||
|
||||
/// <summary>
|
||||
/// 获取字符串
|
||||
/// </summary>
|
||||
/// <param name="keyArr"></param>
|
||||
/// <returns></returns>
|
||||
public static List<string> GetStringList(params string[] keyArr) => keyArr.Select(key => Application.Current.TryFindResource(key) as string).ToList();
|
||||
|
||||
/// <summary>
|
||||
/// 获取资源
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public static T GetResource<T>(string key)
|
||||
{
|
||||
if (Application.Current.TryFindResource(key) is T resource)
|
||||
{
|
||||
return resource;
|
||||
}
|
||||
|
||||
return default(T);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取HandyControl皮肤
|
||||
/// </summary>
|
||||
/// <param name="skin"></param>
|
||||
/// <returns></returns>
|
||||
public static ResourceDictionary GetSkin(SkinType skin) => new ResourceDictionary
|
||||
{
|
||||
Source = new Uri($"pack://application:,,,/HandyControl;component/Themes/Skin{skin.ToString()}.xaml")
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 获取皮肤
|
||||
/// </summary>
|
||||
/// <param name="assembly"></param>
|
||||
/// <param name="themePath"></param>
|
||||
/// <param name="skin"></param>
|
||||
/// <returns></returns>
|
||||
public static ResourceDictionary GetSkin(Assembly assembly, string themePath, SkinType skin)
|
||||
{
|
||||
try
|
||||
{
|
||||
var uri = new Uri($"pack://application:,,,/{assembly.GetName().Name};component/{themePath}/Skin{skin.ToString()}.xaml");
|
||||
return new ResourceDictionary
|
||||
{
|
||||
Source = uri
|
||||
};
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new ResourceDictionary
|
||||
{
|
||||
Source = new Uri($"pack://application:,,,/{assembly.GetName().Name};component/{themePath}/Skin{SkinType.Default.ToString()}.xaml")
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Security;
|
||||
using System.Security.Permissions;
|
||||
|
||||
namespace HandyControl.Tools
|
||||
{
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
internal class SecurityHelper
|
||||
{
|
||||
private static UIPermission _allWindowsUIPermission;
|
||||
|
||||
[SecurityCritical]
|
||||
internal static void DemandUIWindowPermission()
|
||||
{
|
||||
if (_allWindowsUIPermission == null)
|
||||
{
|
||||
_allWindowsUIPermission = new UIPermission(UIPermissionWindow.AllWindows);
|
||||
}
|
||||
_allWindowsUIPermission.Demand();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Media;
|
||||
using HandyControl.Controls;
|
||||
|
||||
namespace HandyControl.Tools
|
||||
{
|
||||
/// <summary>
|
||||
/// 该类可以为可视化元素提供单开的功能
|
||||
/// </summary>
|
||||
public class SingleOpenHelper
|
||||
{
|
||||
private static readonly Dictionary<string, ISingleOpen> OpenDic = new Dictionary<string, ISingleOpen>();
|
||||
|
||||
/// <summary>
|
||||
/// 根据指定的类型创建实例
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static T CreateControl<T>() where T : Visual, ISingleOpen, new()
|
||||
{
|
||||
var typeStr = typeof(T).FullName;
|
||||
|
||||
if (string.IsNullOrEmpty(typeStr)) return default(T);
|
||||
|
||||
var temp = new T();
|
||||
if (!OpenDic.Keys.Contains(typeStr))
|
||||
{
|
||||
OpenDic.Add(typeStr, temp);
|
||||
return temp;
|
||||
}
|
||||
var currentCtl = OpenDic[typeStr];
|
||||
if (currentCtl.CanDispose)
|
||||
{
|
||||
currentCtl.Dispose();
|
||||
OpenDic[typeStr] = temp;
|
||||
return temp;
|
||||
}
|
||||
return default(T);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
namespace HandyControl.Tools
|
||||
{
|
||||
/// <summary>
|
||||
/// 验证帮助类
|
||||
/// </summary>
|
||||
public class ValidateHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否在浮点数范围内
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsInRangeOfDouble(object value)
|
||||
{
|
||||
var v = (double)value;
|
||||
return !(double.IsNaN(v) || double.IsInfinity(v));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否在正浮点数范围内
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="includeZero"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsInRangeOfPosDouble(object value, bool includeZero = false)
|
||||
{
|
||||
var v = (double)value;
|
||||
return !(double.IsNaN(v) || double.IsInfinity(v)) && (includeZero ? v >= 0 : v > 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否在正浮点数范围内
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="includeZero"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsInRangeOfNegDouble(object value, bool includeZero = false)
|
||||
{
|
||||
var v = (double)value;
|
||||
return !(double.IsNaN(v) || double.IsInfinity(v)) && (includeZero ? v <= 0 : v < 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace HandyControl.Tools
|
||||
{
|
||||
public class VisualHelper
|
||||
{
|
||||
internal static VisualStateGroup TryGetVisualStateGroup(DependencyObject d, string groupName)
|
||||
{
|
||||
var root = GetImplementationRoot(d);
|
||||
if (root == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return VisualStateManager
|
||||
.GetVisualStateGroups(root)?
|
||||
.OfType<VisualStateGroup>()
|
||||
.FirstOrDefault(group => string.CompareOrdinal(groupName, group.Name) == 0);
|
||||
}
|
||||
|
||||
internal static FrameworkElement GetImplementationRoot(DependencyObject d)
|
||||
{
|
||||
return 1 == VisualTreeHelper.GetChildrenCount(d)
|
||||
? VisualTreeHelper.GetChild(d, 0) as FrameworkElement
|
||||
: null;
|
||||
}
|
||||
|
||||
internal static T GetChild<T>(DependencyObject d) where T : DependencyObject
|
||||
{
|
||||
if (d is T t)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(d); i++)
|
||||
{
|
||||
var child = VisualTreeHelper.GetChild(d, i);
|
||||
|
||||
var result = GetChild<T>(child);
|
||||
if (result != null) return result;
|
||||
}
|
||||
|
||||
return default(T);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前应用中处于激活的一个窗口
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Window GetActiveWindow() => Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user