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

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 元素有自己的句柄是 WindowPopup。您也许可以创建其中一个并将其放置在您需要的位置,就像您目前对您的崇拜者所做的那样。不过这会变得棘手,因为这些元素实际上 生成它们的 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 将如何与它周围或下方的其他元素交互。所以它也可能根本无法满足您的需要。

祝你好运。