【问题标题】:How to give a glass appearance to the control under an adorner?如何为装饰器下的控件赋予玻璃外观?
【发布时间】:2020-03-24 01:20:06
【问题描述】:

当装饰器放置在 Windows 10 用户控件上时,我试图“模糊”它。

更准确地说,我在 wpf 用户窗口中有一个 datagrid 控件。 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);
        }

加载的事件然后调用(一个非常标准的)模糊/玻璃效果方法:

   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);
    }

没有错误报告....但是不起作用。

那么,如何给装饰器下的控件赋予“玻璃”外观?

TIA

【问题讨论】:

  • 希望您不介意我发布您刚刚删除的问题,但我正要对此发表评论以防万一:可能重复Delete parent if it's not referenced by any other child PS我不知道锁定解决方案是否是基于有保证的行为,或者回答者只是不合理地假设实现。

标签: c# wpf aero-glass


【解决方案1】:

我不确定我能否给你一个完整的解决方案,但我至少可以解释为什么你的尝试没有奏效,也许可以为你指明正确的方向。

在 WinForms(我认为是 C++)中,每个控件都有其自己的“迷你窗口”。我的意思是每个控件都由操作系统赋予其自己的“句柄”,并且操作系统将它们视为屏幕上的单独实体。 WPF 不同,窗口中“单独的控件”的错觉是由 WPF 框架创建的。据操作系统所知,只有一个实体:Window,所有进一步的逻辑都由 WPF 在内部处理。不过,这只是大部分正确,我稍后会提到。

我之所以提出这个问题,是因为您的代码行 PresentationSource.FromVisual(dataGrid) 将为您提供 Window 的句柄,DataGrid 在其中托管,而不是DataGrid 本身独有的句柄(因为DataGrid 没有 句柄)。因此,您使用该句柄所做的所有其他事情实际上都针对整个 WPF Window

WPF Window 内的所有渲染都由 WPF 框架(加上您的代码)在内部处理,而不是由操作系统直接处理(如在 WinForms 和 C++ 中),因此使用告诉操作系统如何执行的本机方法在 Window 中的特定元素上渲染某些东西不起作用。

在我看来,您可以通过两条途径来尝试创建这种效果:

  • 您可以尝试在 WPF 中重新创建“玻璃状”效果。这个会 涉及重新创建或获取任何算法用于 在视觉上扭曲一个区域以产生这种效果,然后以某种方式 将其实施到控件中。我真的不知道去哪里 从谷歌以外的地方开始。

  • 您可以尝试利用确实拥有自己句柄的其他 WPF 元素。

    • 我知道的两个主要的 WPF 元素有自己的句柄是 WindowPopup。您也许可以创建其中一个并将其放置在您需要的位置,就像您目前对您的崇拜者所做的那样。不过这会变得很棘手,因为这些元素实际上产生它们的Window 之外,并没有真正链接到它。因此,当您在桌面上移动主要的Window 时,Popup 或子Window 不会随之移动。您可能还可以在 WPF 窗口和您创建的弹出窗口之间拖动其他窗口(但不确定)。

    • 在这个标题下可能还有另一种可能性,那就是WindowsFormsHost 控件。这是hosts a WinForms control in a WPF window 的 WPF 控件。托管在内部的 WinForms 控件可能由操作系统赋予它们自己的句柄(因为这就是 WinForms 的操作方式)。这可能是您最好的选择,除非我从未尝试过,而且我不知道WindowsFormsHost 将如何与它周围或下方的其他元素交互。因此,它也可能根本无法满足您的需求。

祝你好运。

【讨论】:

  • 谢谢。我不知道操作系统负责模糊效果。我希望我仍然可以模糊窗户,但我不明白为什么装饰器没有被模糊——因为它是窗户的一部分。我猜 WPF 自己渲染,不尊重模糊效果。太糟糕了 :( 或者,因为我在渲染装饰器之前进行模糊处理,也许装饰器正在撤消模糊处理?哦,好吧,值得一试。
  • 是的,Adorner 实际上只是Window 的另一部分,只是放在其他所有内容之上。它仍然在内部呈现。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-18
相关资源
最近更新 更多