Перерисовка заголовка окна при использовании пользовательских Chrome и DWM - PullRequest
3 голосов
/ 26 августа 2011

Я использую библиотеку интеграции оболочки WPF (http://archive.msdn.microsoft.com/WPFShell), однако при использовании пользовательского Chrome с Aero строка заголовка удаляется.

Я понимаю, что мне нужно использовать функцию DrawThemeTextEx, чтобы перерисовать заголовок окна, однако я не могу найти примеры C #, которые делают это. Я нашел руководство по Пользовательской оконной рамке с использованием DWM (Windows) , в котором подробно описан рисунок заголовка заголовка.

Я не совсем уверен (у меня мало опыта работы с pinvoke), как это сделать в C #, чтобы использовать правильные системные шрифты и т. Д. Кто-то может предоставить пример C #, который я мог бы интегрировать в библиотеку интеграции оболочки WPF

Обновление № 1: Я пробовал этот код в проекте Windows Form, и он работает нормально. Я заметил, что форма Windows потеряет текст заголовка, если переместить форму с экрана. Поэтому я считаю, что проблема может быть связана с этим. Я попытался нарисовать текст заголовка в событии OnRender, однако это не решает проблему.

Я добавил следующий код в WindowChromeWorker.cs:

    private void _DrawCustomTitle(IntPtr hwnd)
    {
        if (NativeMethods.DwmIsCompositionEnabled())
        {

            Standard.RECT rcClient = new Standard.RECT();
            NativeMethods.GetClientRect(hwnd, ref rcClient);

            Standard.RECT rcPaint = rcClient;
            rcPaint.Top += 8;
            rcPaint.Right -= 125;
            rcPaint.Left += 8;
            rcPaint.Bottom = 50;

            IntPtr destdc = NativeMethods.GetDC(hwnd);
            IntPtr Memdc = NativeMethods.CreateCompatibleDC(destdc); // Set up a memory DC where we'll draw the text.
            IntPtr bitmap;
            IntPtr bitmapOld = IntPtr.Zero;
            IntPtr logFont;

            uint uFormat = NativeMethods.DT_SINGLELINE | NativeMethods.DT_TOP | NativeMethods.DT_LEFT | NativeMethods.DT_WORD_ELLIPSIS;

            BITMAPINFO dib = new BITMAPINFO();
            dib.bmiHeader.biHeight = -(rcClient.Bottom - rcClient.Top); // negative because DrawThemeTextEx() uses a top-down DIB
            dib.bmiHeader.biWidth = rcClient.Right - rcClient.Left;
            dib.bmiHeader.biPlanes = 1;
            dib.bmiHeader.biSize = Marshal.SizeOf(typeof(BITMAPINFOHEADER));
            dib.bmiHeader.biBitCount = 32;
            dib.bmiHeader.biCompression = NativeMethods.BI_RGB;

            if (!(NativeMethods.SaveDC(Memdc) == 0))
            {
                bitmap = NativeMethods.CreateDIBSection(Memdc, ref dib, NativeMethods.DIB_RGB_COLORS, 0, IntPtr.Zero, 0);   // Create a 32-bit bmp for use in offscreen drawing when glass is on
                if (!(bitmap == IntPtr.Zero))
                {
                    bitmapOld = NativeMethods.SelectObject(Memdc, bitmap);

                    System.Drawing.Font font = new System.Drawing.Font("Segoe UI", 9f);
                    IntPtr hFont = font.ToHfont();
                    logFont = NativeMethods.SelectObject(Memdc, hFont);
                    try
                    {

                        System.Windows.Forms.VisualStyles.VisualStyleRenderer renderer = new System.Windows.Forms.VisualStyles.VisualStyleRenderer(System.Windows.Forms.VisualStyles.VisualStyleElement.Window.Caption.Active);

                        NativeMethods.DTTOPTS dttOpts = new NativeMethods.DTTOPTS();
                        dttOpts.dwSize = (int)Marshal.SizeOf(typeof(NativeMethods.DTTOPTS));
                        dttOpts.dwFlags = NativeMethods.DTT_COMPOSITED | NativeMethods.DTT_GLOWSIZE;
                        dttOpts.iGlowSize = 15;

                        string title = "Windows Title";
                        NativeMethods.DrawThemeTextEx(renderer.Handle, Memdc, 0, 0, title, -1, uFormat, ref rcPaint, ref dttOpts);

                        NativeMethods.BitBlt(destdc, rcClient.Left, rcClient.Top, rcClient.Right - rcClient.Left, rcClient.Bottom - rcClient.Top, Memdc, 0, 0, NativeMethods.SRCCOPY);

                    }
                    catch (Exception e)
                    {
                        System.Diagnostics.Debug.WriteLine(e.Message);
                    }

                    // Clean Up
                    NativeMethods.SelectObject(Memdc, bitmapOld);
                    NativeMethods.SelectObject(Memdc, logFont);
                    NativeMethods.DeleteObject(bitmap);
                    NativeMethods.DeleteObject(hFont);

                    NativeMethods.ReleaseDC(Memdc, -1);
                    NativeMethods.DeleteDC(Memdc);
                }

            }
        }

    }

Затем я вызываю DrawCustomTitle в следующей функции после расширения стекла DWM. Любая идея, почему это не будет работать.

    private void _ExtendGlassFrame()
    {
        Assert.IsNotNull(_window);

        // Expect that this might be called on OSes other than Vista.
        if (!Utility.IsOSVistaOrNewer)
        {
            // Not an error.  Just not on Vista so we're not going to get glass.
            return;
        }

        if (IntPtr.Zero == _hwnd)
        {
            // Can't do anything with this call until the Window has been shown.
            return;
        }

        // Ensure standard HWND background painting when DWM isn't enabled.
        if (!NativeMethods.DwmIsCompositionEnabled())
        {
            _hwndSource.CompositionTarget.BackgroundColor = SystemColors.WindowColor;
        }
        else
        {
            // This makes the glass visible at a Win32 level so long as nothing else is covering it.
            // The Window's Background needs to be changed independent of this.

            // Apply the transparent background to the HWND
            _hwndSource.CompositionTarget.BackgroundColor = Colors.Transparent;

            // Thickness is going to be DIPs, need to convert to system coordinates.
            Point deviceTopLeft = DpiHelper.LogicalPixelsToDevice(new Point(_chromeInfo.GlassFrameThickness.Left, _chromeInfo.GlassFrameThickness.Top));
            Point deviceBottomRight = DpiHelper.LogicalPixelsToDevice(new Point(_chromeInfo.GlassFrameThickness.Right, _chromeInfo.GlassFrameThickness.Bottom));

            var dwmMargin = new MARGINS
            {
                // err on the side of pushing in glass an extra pixel.
                cxLeftWidth = (int)Math.Ceiling(deviceTopLeft.X),
                cxRightWidth = (int)Math.Ceiling(deviceBottomRight.X),
                cyTopHeight = (int)Math.Ceiling(deviceTopLeft.Y),
                cyBottomHeight = (int)Math.Ceiling(deviceBottomRight.Y),
            };

            NativeMethods.DwmExtendFrameIntoClientArea(_hwnd, ref dwmMargin);

            this._DrawCustomTitle(_hwnd);
        }
    }

Ответы [ 2 ]

0 голосов
/ 26 сентября 2011

Вероятно, причина, по которой он не работает, это то, что обычно называют проблемами "воздушного пространства".По сути, используемый вами код представляет собой рендеринг пикселей с помощью GDI, а WPF реализован с использованием DirectX, и две технологии рендеринга не знают, как делиться пикселями.Может также случиться что-то более тонкое, но на первый взгляд, я подозреваю, что это так.

Способ, которым вы хотели бы сделать это в WPF, аналогичен тому, что предлагал Мранц ранее.Есть несколько простых способов получить эффект размытия с помощью WPF:

  1. Создание двух текстовых блоков непосредственно друг над другом (например, в сетке, занимающей одну и ту же ячейку), с одинаковымишрифт и текст и т. д., но сделайте нижний цвет, который вы хотите для свечения, а затем примените к нему эффект размытия.Вы должны быть осторожны, так как без эффекта они будут отображаться одинаково, иначе размытие будет отключено.

  2. Создайте эллипс или прямоугольник с эллипсами по краям и выполнитетот же трюк, заключающийся в том, чтобы поместить его за текстовым блоком с заголовком и наложить на него эффект размытия.

Это немного сложнее, потому что Windows изменила некоторые из этих режимов поведения между Vista и 7 (иЯ понятия не имею, как в конечном итоге будет выглядеть 8).Если я правильно помню, в Vista, когда вы развернули окно до максимума, эффект размытия исчезнет, ​​а цвет шрифта станет белым.В 7 этого больше не происходит.По крайней мере в предварительном просмотре для 8 (и Office 2010) текст заголовка теперь центрирован.Также, когда вы делаете это самостоятельно, вы должны быть осторожны, чтобы не затенять кнопки заголовка, потому что он, вероятно, не начнет обрезать текст в том месте, где вы ожидаете.

Если у вас есть проблемы с одним изэти подходы не стесняйтесь пинговать меняЯ, вероятно, могу собрать пример кода, но у меня нет удобных стилей.Кроме того, если вы решите это, пожалуйста, опубликуйте свое решение, чтобы другие могли извлечь пользу:)

Надеюсь, что это поможет,

0 голосов
/ 26 августа 2011

Тебе не нужно проходить через все эти неприятности. Посмотрите мой пример кода ниже. Ярлык с Text={TemplateBinding Title} делает то, что вы хотите.

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:shell="clr-namespace:Microsoft.Windows.Shell;assembly=Microsoft.Windows.Shell"
    Title="MainWindow" Height="350" Width="525">
<Window.Style>
    <Style TargetType="Window">
        <Setter Property="shell:WindowChrome.WindowChrome">
            <Setter.Value>
                <shell:WindowChrome GlassFrameThickness="4,40,4,4" ResizeBorderThickness="5" CaptionHeight="30"/>
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Window">
                    <Grid x:Name="PART_ComponentRoot">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="40"/>
                            <RowDefinition/>
                            <RowDefinition Height="4"/>
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="4"/>
                            <ColumnDefinition/>
                            <ColumnDefinition Width="4"/>
                        </Grid.ColumnDefinitions>

                        <TextBlock Grid.Column="1" Text="{TemplateBinding Title}"
                                   HorizontalAlignment="Center" VerticalAlignment="Center"/>

                        <ContentPresenter Grid.Row="1" Grid.Column="1" Content="{TemplateBinding Content}"/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Style>

<Grid Background="White">

</Grid>

...