alpha
This commit is contained in:
@@ -0,0 +1,211 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static System.Windows.Forms.VisualStyles.VisualStyleElement.TrayNotify;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Shell;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Ink_Canvas.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// 高性能透明桌面窗口
|
||||
/// </summary>
|
||||
public partial class PerformanceTransparentWin : Window
|
||||
{
|
||||
|
||||
static class BrushCreator
|
||||
{
|
||||
/// <summary>
|
||||
/// 尝试从缓存获取或创建颜色笔刷
|
||||
/// </summary>
|
||||
/// <param name="color">对应的字符串颜色</param>
|
||||
/// <returns>已经被 Freeze 的颜色笔刷</returns>
|
||||
public static SolidColorBrush GetOrCreate(string color)
|
||||
{
|
||||
if (!color.StartsWith("#"))
|
||||
{
|
||||
throw new ArgumentException($"输入的{nameof(color)}不是有效颜色,需要使用 # 开始");
|
||||
// 如果不使用 # 开始将会在 ConvertFromString 出现异常
|
||||
}
|
||||
|
||||
if (TryGetBrush(color, out var brushValue))
|
||||
{
|
||||
return (SolidColorBrush)brushValue;
|
||||
}
|
||||
|
||||
object convertColor;
|
||||
|
||||
try
|
||||
{
|
||||
convertColor = ColorConverter.ConvertFromString(color);
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
// 因为在 ConvertFromString 会抛出的是 令牌无效 难以知道是为什么传入的不对
|
||||
throw new ArgumentException($"输入的{nameof(color)}不是有效颜色");
|
||||
}
|
||||
|
||||
if (convertColor == null)
|
||||
{
|
||||
throw new ArgumentException($"输入的{nameof(color)}不是有效颜色");
|
||||
}
|
||||
|
||||
var brush = new SolidColorBrush((Color)convertColor);
|
||||
if (TryFreeze(brush))
|
||||
{
|
||||
BrushCacheList.Add(color, new WeakReference<Brush>(brush));
|
||||
}
|
||||
|
||||
return brush;
|
||||
}
|
||||
|
||||
private static Dictionary<string, WeakReference<Brush>> BrushCacheList { get; } =
|
||||
new Dictionary<string, WeakReference<Brush>>();
|
||||
|
||||
private static bool TryGetBrush(string key, out Brush brush)
|
||||
{
|
||||
if (BrushCacheList.TryGetValue(key, out var brushValue))
|
||||
{
|
||||
if (brushValue.TryGetTarget(out brush))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 被回收的资源
|
||||
BrushCacheList.Remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
brush = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool TryFreeze(Freezable freezable)
|
||||
{
|
||||
if (freezable.CanFreeze)
|
||||
{
|
||||
freezable.Freeze();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建高性能透明桌面窗口
|
||||
/// </summary>
|
||||
public PerformanceTransparentWin()
|
||||
{
|
||||
WindowStyle = WindowStyle.None;
|
||||
ResizeMode = ResizeMode.NoResize;
|
||||
|
||||
Stylus.SetIsFlicksEnabled(this, false);
|
||||
Stylus.SetIsPressAndHoldEnabled(this, false);
|
||||
Stylus.SetIsTapFeedbackEnabled(this, false);
|
||||
Stylus.SetIsTouchFeedbackEnabled(this, false);
|
||||
|
||||
WindowChrome.SetWindowChrome(this,
|
||||
new WindowChrome { GlassFrameThickness = WindowChrome.GlassFrameCompleteThickness, CaptionHeight = 0, CornerRadius = new CornerRadius(0), ResizeBorderThickness = new Thickness(0)});
|
||||
|
||||
var visualTree = new FrameworkElementFactory(typeof(Border));
|
||||
visualTree.SetValue(Border.BackgroundProperty, new TemplateBindingExtension(Window.BackgroundProperty));
|
||||
var childVisualTree = new FrameworkElementFactory(typeof(ContentPresenter));
|
||||
childVisualTree.SetValue(UIElement.ClipToBoundsProperty, true);
|
||||
visualTree.AppendChild(childVisualTree);
|
||||
|
||||
Template = new ControlTemplate
|
||||
{
|
||||
TargetType = typeof(Window),
|
||||
VisualTree = visualTree,
|
||||
};
|
||||
|
||||
_dwmEnabled = DwmCompositionHelper.DwmIsCompositionEnabled();
|
||||
if (_dwmEnabled)
|
||||
{
|
||||
_hwnd = new WindowInteropHelper(this).EnsureHandle();
|
||||
Loaded += PerformanceDesktopTransparentWindow_Loaded;
|
||||
Background = Brushes.Transparent;
|
||||
}
|
||||
else
|
||||
{
|
||||
AllowsTransparency = true;
|
||||
Background = BrushCreator.GetOrCreate("#0100000");
|
||||
_hwnd = new WindowInteropHelper(this).EnsureHandle();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置点击穿透到后面透明的窗口
|
||||
/// </summary>
|
||||
public void SetTransparentHitThrough()
|
||||
{
|
||||
if (_dwmEnabled)
|
||||
{
|
||||
Win32.User32.SetWindowLongPtr(_hwnd, Win32.GetWindowLongFields.GWL_EXSTYLE,
|
||||
(IntPtr)(int)((long)Win32.User32.GetWindowLongPtr(_hwnd, Win32.GetWindowLongFields.GWL_EXSTYLE) | (long)Win32.ExtendedWindowStyles.WS_EX_TRANSPARENT));
|
||||
}
|
||||
else
|
||||
{
|
||||
Background = Brushes.Transparent;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置点击命中,不会穿透到后面的窗口
|
||||
/// </summary>
|
||||
public void SetTransparentNotHitThrough()
|
||||
{
|
||||
if (_dwmEnabled)
|
||||
{
|
||||
Win32.User32.SetWindowLongPtr(_hwnd, Win32.GetWindowLongFields.GWL_EXSTYLE,
|
||||
(IntPtr)(int)((long)Win32.User32.GetWindowLongPtr(_hwnd, Win32.GetWindowLongFields.GWL_EXSTYLE) & ~(long)Win32.ExtendedWindowStyles.WS_EX_TRANSPARENT));
|
||||
}
|
||||
else
|
||||
{
|
||||
Background = BrushCreator.GetOrCreate("#0100000");
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct STYLESTRUCT
|
||||
{
|
||||
public int styleOld;
|
||||
public int styleNew;
|
||||
}
|
||||
|
||||
private void PerformanceDesktopTransparentWindow_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
((HwndSource)PresentationSource.FromVisual(this)).AddHook((IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) =>
|
||||
{
|
||||
//想要让窗口透明穿透鼠标和触摸等,需要同时设置 WS_EX_LAYERED 和 WS_EX_TRANSPARENT 样式,
|
||||
//确保窗口始终有 WS_EX_LAYERED 这个样式,并在开启穿透时设置 WS_EX_TRANSPARENT 样式
|
||||
//但是WPF窗口在未设置 AllowsTransparency = true 时,会自动去掉 WS_EX_LAYERED 样式(在 HwndTarget 类中),
|
||||
//如果设置了 AllowsTransparency = true 将使用WPF内置的低性能的透明实现,
|
||||
//所以这里通过 Hook 的方式,在不使用WPF内置的透明实现的情况下,强行保证这个样式存在。
|
||||
if (msg == (int)Win32.WM.STYLECHANGING && (long)wParam == (long)Win32.GetWindowLongFields.GWL_EXSTYLE)
|
||||
{
|
||||
var styleStruct = (STYLESTRUCT)Marshal.PtrToStructure(lParam, typeof(STYLESTRUCT));
|
||||
styleStruct.styleNew |= (int)Win32.ExtendedWindowStyles.WS_EX_LAYERED;
|
||||
Marshal.StructureToPtr(styleStruct, lParam, false);
|
||||
handled = true;
|
||||
}
|
||||
return IntPtr.Zero;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否开启 DWM 了,如果开启了,那么才可以使用高性能的桌面透明窗口
|
||||
/// </summary>
|
||||
private readonly bool _dwmEnabled;
|
||||
private readonly IntPtr _hwnd;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user