I am attempting to "blurr" a windows 10 user control when an adorner is placed over it.
More exactly, I have a datagrid control in a wpf user window. When a cell in the datagrid is selected, an editing adorner is created over the datagrid control.
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);
}
The loaded event then calls (a pretty standard) Blurr/glass effect method:
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);
}
No error is reported....But is does not work.
So, how can I give a "glass" appearance to the control under the adorner?
TIA
I'm not sure I can give you a whole solution, but I can at least explain why your attempt doesn't work and maybe point you in the right direction.
In WinForms (and C++ I think), each control is sort of its own "mini-window". By which I mean each control is given its own "handle" by the OS, and the OS treats them as individual entities on the screen. WPF is different, the illusion of "separate controls" in a window is one created by the WPF framework. As far as the OS knows, there is only one entity: the Window
and all further logic is handled internally by WPF. This is only mostly true, though, as I'll bring up later.
The reason I bring this up at all is because your line of code PresentationSource.FromVisual(dataGrid)
is going to give you the handle of the Window
in which the DataGrid
is being hosted, not a handle unique to the DataGrid
itself (since the DataGrid
has no handle). And so everything else you do using that handle is actually being targeted to the entire WPF Window
as a whole.
All of the rendering inside a WPF Window
is handled internally by the WPF framework (plus your code), not directly by the OS (as in WinForms and C++), so using a native method that tells the OS how to render something wont work on a specific element inside the Window
.
As I see it there are two routes you can take in trying to create this effect:
You could try to recreate the "glassy" effect inside WPF. This would involve recreating or getting ahold of whatever algorithm is used to visually distort an area to produce that effect, and then somehow implementing that into a control. I wouldn't really know where to start with that other than just Google.
You could try to take advantage of other WPF elements that do have their own handles.
The two main WPF elements I know of that have their own handles are Window
and Popup
. You might be able to create one of those and position it where you need it, just like you're currently doing with your adorer. This will get tricky though because these elements are actually outside the Window
that spawned them and aren't really linked to it. So when you move the main Window
across the desktop, the Popup
or sub-Window
won't move with it. You might also be able to drag other windows between your WPF window and the popup you create (not sure about that, though).
There is maybe one other possibility under this heading, and that is the WindowsFormsHost
control. This is a WPF control that hosts a WinForms control in a WPF window. The WinForms controls hosted inside presumably are given their own handle by the OS (since that's how WinForms operates). This one might be your best bet, except I've never tried it and I have no idea how the WindowsFormsHost
will interact with other elements that are around or underneath it. So it also might not work at all for what you need.
Good luck.