如何为装饰器下的控件提供玻璃外观?
How to give a glass appearance to the control under an adorner?
我正在尝试 "blurr" 一个 windows 10 用户控件,当一个装饰器放在它上面时。
更确切地说,我在 wpf 用户中有一个数据网格控件 window。选择数据网格中的单元格后,将在数据网格控件上创建一个编辑装饰器。
public DataGridAnnotationAdorner(DataGrid adornedDataGrid, IVisit visit, DateTime TableDate)
: base(adornedDataGrid)
{
Control = new DataGridAnnotationControl(visit, TableDate);
AddLogicalChild(Control);
AddVisualChild(Control);
Loaded += DataGridAnnotationAdorner_Loaded;
}
private void DataGridAnnotationAdorner_Loaded(object sender, RoutedEventArgs e)
{
EnableBlur(AdornedElement);
}
加载的事件然后调用(相当标准)Blurr/glass效果方法:
internal void EnableBlur(UIElement dataGrid)
{
HwndSource source = (HwndSource)PresentationSource.FromVisual(dataGrid);
IntPtr hwnd = source.Handle;
var accent = new AccentPolicy();
accent.AccentState = AccentState.ACCENT_ENABLE_BLURBEHIND;
var accentStructSize = Marshal.SizeOf(accent);
var accentPtr = Marshal.AllocHGlobal(accentStructSize);
Marshal.StructureToPtr(accent, accentPtr, false);
var data = new WindowCompositionAttributeData();
data.Attribute = WindowCompositionAttribute.WCA_ACCENT_POLICY;
data.SizeOfData = accentStructSize;
data.Data = accentPtr;
SetWindowCompositionAttribute(hwnd, ref data);
Marshal.FreeHGlobal(accentPtr);
}
没有报告错误....但是不起作用。
那么,如何才能使装饰器下的控件具有 "glass" 外观?
TIA
我不确定我能否为您提供完整的解决方案,但我至少可以解释为什么您的尝试不起作用,并可能为您指明正确的方向。
在 WinForms(我认为是 C++)中,每个控件都是自己的 "mini-window"。我的意思是每个控件都由 OS 赋予其自己的 "handle",并且 OS 将它们视为屏幕上的单独实体。 WPF 则不同,window 中的 "separate controls" 的错觉是由 WPF 框架创建的。据 OS 所知,只有一个实体:Window
并且所有进一步的逻辑都由 WPF 内部处理。不过,这只是大部分是正确的,我稍后会提到。
我之所以提出这个问题是因为您的代码行 PresentationSource.FromVisual(dataGrid)
将为您提供 Window
的句柄,其中DataGrid
正在托管,而不是 DataGrid
本身独有的句柄(因为 DataGrid
没有 句柄)。因此,您使用该句柄所做的所有其他事情实际上都是针对整个 WPF Window
。
WPF Window
内的所有呈现都由 WPF 框架(加上您的代码)在内部处理,而不是直接由 OS(如在 WinForms 和 C++ 中)处理,因此使用告诉 OS 如何呈现某些内容的本机方法不适用于 Window
.
中的特定元素
据我所知,您可以通过两条途径来尝试创建此效果:
您可以尝试在 WPF 中重新创建 "glassy" 效果。这个会
涉及重新创建或掌握用于
在视觉上扭曲一个区域以产生那种效果,然后以某种方式
将其实施到控件中。我真的不知道去哪里
从 Google.
开始
您可以尝试利用其他 具有自己句柄的 WPF 元素。
我知道的两个主要的 WPF 元素有自己的句柄是 Window
和 Popup
。您也许可以创建其中一个并将其放置在您需要的位置,就像您目前对您的崇拜者所做的那样。不过这会变得棘手,因为这些元素实际上 在 生成它们的 Window
之外,并没有真正链接到它。因此,当您在桌面上移动主 Window
时,Popup
或子 Window
不会随之移动。您也许还可以在 WPF window 和您创建的弹出窗口之间拖动其他 windows(虽然不确定)。
这个标题下也许还有另一种可能性,那就是WindowsFormsHost
control. This is a WPF control that hosts a WinForms control in a WPF window。托管在内部的 WinForms 控件可能由 OS 赋予它们自己的句柄(因为这就是 WinForms 的操作方式)。这可能是您最好的选择,但我从未尝试过,而且我不知道 WindowsFormsHost
将如何与它周围或下方的其他元素交互。所以它也可能根本无法满足您的需要。
祝你好运。
我正在尝试 "blurr" 一个 windows 10 用户控件,当一个装饰器放在它上面时。
更确切地说,我在 wpf 用户中有一个数据网格控件 window。选择数据网格中的单元格后,将在数据网格控件上创建一个编辑装饰器。
public DataGridAnnotationAdorner(DataGrid adornedDataGrid, IVisit visit, DateTime TableDate)
: base(adornedDataGrid)
{
Control = new DataGridAnnotationControl(visit, TableDate);
AddLogicalChild(Control);
AddVisualChild(Control);
Loaded += DataGridAnnotationAdorner_Loaded;
}
private void DataGridAnnotationAdorner_Loaded(object sender, RoutedEventArgs e)
{
EnableBlur(AdornedElement);
}
加载的事件然后调用(相当标准)Blurr/glass效果方法:
internal void EnableBlur(UIElement dataGrid)
{
HwndSource source = (HwndSource)PresentationSource.FromVisual(dataGrid);
IntPtr hwnd = source.Handle;
var accent = new AccentPolicy();
accent.AccentState = AccentState.ACCENT_ENABLE_BLURBEHIND;
var accentStructSize = Marshal.SizeOf(accent);
var accentPtr = Marshal.AllocHGlobal(accentStructSize);
Marshal.StructureToPtr(accent, accentPtr, false);
var data = new WindowCompositionAttributeData();
data.Attribute = WindowCompositionAttribute.WCA_ACCENT_POLICY;
data.SizeOfData = accentStructSize;
data.Data = accentPtr;
SetWindowCompositionAttribute(hwnd, ref data);
Marshal.FreeHGlobal(accentPtr);
}
没有报告错误....但是不起作用。
那么,如何才能使装饰器下的控件具有 "glass" 外观?
TIA
我不确定我能否为您提供完整的解决方案,但我至少可以解释为什么您的尝试不起作用,并可能为您指明正确的方向。
在 WinForms(我认为是 C++)中,每个控件都是自己的 "mini-window"。我的意思是每个控件都由 OS 赋予其自己的 "handle",并且 OS 将它们视为屏幕上的单独实体。 WPF 则不同,window 中的 "separate controls" 的错觉是由 WPF 框架创建的。据 OS 所知,只有一个实体:Window
并且所有进一步的逻辑都由 WPF 内部处理。不过,这只是大部分是正确的,我稍后会提到。
我之所以提出这个问题是因为您的代码行 PresentationSource.FromVisual(dataGrid)
将为您提供 Window
的句柄,其中DataGrid
正在托管,而不是 DataGrid
本身独有的句柄(因为 DataGrid
没有 句柄)。因此,您使用该句柄所做的所有其他事情实际上都是针对整个 WPF Window
。
WPF Window
内的所有呈现都由 WPF 框架(加上您的代码)在内部处理,而不是直接由 OS(如在 WinForms 和 C++ 中)处理,因此使用告诉 OS 如何呈现某些内容的本机方法不适用于 Window
.
据我所知,您可以通过两条途径来尝试创建此效果:
您可以尝试在 WPF 中重新创建 "glassy" 效果。这个会 涉及重新创建或掌握用于 在视觉上扭曲一个区域以产生那种效果,然后以某种方式 将其实施到控件中。我真的不知道去哪里 从 Google.
开始
您可以尝试利用其他 具有自己句柄的 WPF 元素。
我知道的两个主要的 WPF 元素有自己的句柄是
Window
和Popup
。您也许可以创建其中一个并将其放置在您需要的位置,就像您目前对您的崇拜者所做的那样。不过这会变得棘手,因为这些元素实际上 在 生成它们的Window
之外,并没有真正链接到它。因此,当您在桌面上移动主Window
时,Popup
或子Window
不会随之移动。您也许还可以在 WPF window 和您创建的弹出窗口之间拖动其他 windows(虽然不确定)。这个标题下也许还有另一种可能性,那就是
WindowsFormsHost
control. This is a WPF control that hosts a WinForms control in a WPF window。托管在内部的 WinForms 控件可能由 OS 赋予它们自己的句柄(因为这就是 WinForms 的操作方式)。这可能是您最好的选择,但我从未尝试过,而且我不知道WindowsFormsHost
将如何与它周围或下方的其他元素交互。所以它也可能根本无法满足您的需要。
祝你好运。