简体   繁体   English

如何在装饰器下为控件提供玻璃外观?

[英]How to give a glass appearance to the control under an adorner?

I am attempting to "blurr" a windows 10 user control when an adorner is placed over it.当装饰器放置在 Windows 10 用户控件上时,我试图“模糊”它。

More exactly, I have a datagrid control in a wpf user window.更确切地说,我在 wpf 用户窗口中有一个 datagrid 控件。 When a cell in the datagrid is selected, an editing adorner is created over the datagrid control.选择DataGrid中的单元格时,在DataGrid控件上创建编辑ADORNER。

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 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".在 WinForms(我认为是 C++)中,每个控件都是它自己的“迷你窗口”。 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. WPF 不同,窗口中“单独控件”的错觉是由 WPF 框架创建的。 As far as the OS knows, there is only one entity: the Window and all further logic is handled internally by WPF.就操作系统而言,只有一个实体: Window和所有进一步的逻辑都由 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).我提出这一点的原因是因为您的代码行PresentationSource.FromVisual(dataGrid)将为您提供托管DataGridWindow的句柄,而不是DataGrid本身独有的句柄(因为DataGrid没有手柄)。 And so everything else you do using that handle is actually being targeted to the entire WPF Window as a whole.因此,您使用该句柄执行的所有其他操作实际上都针对整个 WPF Window

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 . WPF Window内的所有渲染都由 WPF 框架(加上您的代码)在内部处理,而不是由操作系统直接处理(如在 WinForms 和 C++ 中),因此使用本机方法告诉操作系统如何渲染某些内容将不起作用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.您可以尝试在 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.你可以尝试把那些有自己处理其他WPF元素的优势。

    • The two main WPF elements I know of that have their own handles are Window and Popup .我知道的两个主要的 WPF 元素有自己的句柄是WindowPopup 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.不过这会变得很棘手,因为这些元素实际上产生它们的Window之外并且并没有真正链接到它。 So when you move the main Window across the desktop, the Popup or sub- Window won't move with it.因此,当您在桌面上移动主WindowPopup Window或子Window不会随之移动。 You might also be able to drag other windows between your WPF window and the popup you create (not sure about that, though).您也可以在 WPF 窗口和您创建的弹出窗口之间拖动其他窗口(不过不确定)。

    • There is maybe one other possibility under this heading, and that is the WindowsFormsHost control.在这个标题下可能还有另一种可能性,那就是WindowsFormsHost控件。 This is a WPF control that hosts a WinForms control in a WPF window .这是在 WPF 窗口承载 WinForms 控件的 WPF 控件 The WinForms controls hosted inside presumably are given their own handle by the OS (since that's how WinForms operates).托管在内部的 WinForms 控件可能由操作系统赋予它们自己的句柄(因为这就是 WinForms 的操作方式)。 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.这可能是您最好的选择,除非我从未尝试过,而且我不知道WindowsFormsHost将如何与它周围或下方的其他元素进行交互。 So it also might not work at all for what you need.因此,它也可能根本无法满足您的需求。

Good luck.祝你好运。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM