Включить эффект стекла Vista в окне WPF без полей - PullRequest
3 голосов
/ 24 августа 2009

Я написал прикрепленное свойство, которое я могу установить в окне, чтобы расширить стеклянную рамку в клиентскую область (используя DwmExtendFrameIntoClientArea API). Работает нормально в большинстве случаев. Теперь я хочу, чтобы мое окно было без полей, поэтому я установил в своем окне следующие атрибуты:

    WindowStyle="None"
    ResizeMode="NoResize"
    Background="Transparent"
    u:WinUtil.EnableGlass="True"
    ShowInTaskbar="False"

Но с этими атрибутами стекло не появляется вообще: у моего окна просто прозрачный фон. Если я установлю ResizeMode на CanResize, стекло будет показано, но я не хочу, чтобы размер окна можно было изменять.

Я подозреваю, что это происходит из-за того, что эффект стекла получается путем расширения фрейма, не являющегося клиентом, в клиентскую область: при WindowStyle = None и ResizeMode = NoResize фрейм, не являющийся клиентом, отсутствует расширить. Когда я включаю изменение размера, оно создает рамку вокруг окна, поэтому рамка может быть расширена.

Я полагаю, что можно создать окно с тонкой рамкой, без заголовка и нельзя изменить его размер, установив соответствующие биты WS_ *, но я не знаю, какие именно

Итак, мои вопросы:

  1. Какие биты стиля должны быть установлены или не установлены, чтобы иметь желаемый вид и поведение?
  2. Как я могу инициализировать биты стиля окна? Класс Window, похоже, не имеет ничего подобного свойству Windows Forms CreateParams ... Можно ли устанавливать эти биты после создания дескриптора?
  3. Я нашел класс HwndSource, который мог бы стать ответом на вопрос 2, но его было бы немного сложно использовать, если вы не являетесь экспертом по Win32 ... Было бы разумным решением моей проблемы?

Любой совет приветствуется

Ответы [ 2 ]

5 голосов
/ 25 августа 2009

Вы пытались использовать DwmEnableBlurBehindWindow ? Это позволяет вам сделать прозрачной определенную часть клиентской области окна.

4 голосов
/ 04 августа 2010

У меня было окно, которое я хотел дать только стеклянную границу (без заголовка и без изменения размера), и столкнулся с той же проблемой, что и вы. Вы не можете сделать это, просто установив стиль окна. Мое решение состояло в том, чтобы установить ResizeMode = "CanResize" и WindowStyle = "None", а затем обработать событие WM_NCHITTEST для преобразования изменяемых размеров границ в неизменяемые границы. Также необходимо было изменить стиль окна, чтобы отключить максимизацию и минимизацию (с помощью ярлыков Windows) и системное меню:

private void Window_SourceInitialized(object sender, EventArgs e)
{
    System.Windows.Interop.HwndSource source = (System.Windows.Interop.HwndSource)PresentationSource.FromVisual(this);
    source.AddHook(new System.Windows.Interop.HwndSourceHook(HwndSourceHook));

    IntPtr hWnd = new System.Windows.Interop.WindowInteropHelper(this).Handle;
    IntPtr flags = GetWindowLongPtr(hWnd, -16 /*GWL_STYLE*/);
    SetWindowLongPtr(hWnd, -16 /*GWL_STYLE*/, new IntPtr(flags.ToInt64() & ~(0x00010000L /*WS_MAXIMIZEBOX*/ | 0x00020000L /*WS_MINIMIZEBOX*/ | 0x00080000L /*WS_SYSMENU*/)));
}

private static IntPtr HwndSourceHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
    switch (msg)
    {
        case 0x0084 /*WM_NCHITTEST*/:
            IntPtr result = DefWindowProc(hwnd, msg, wParam, lParam);
            if (result.ToInt32() >= 10 /*HTLEFT*/ && result.ToInt32() <= 17 /*HTBOTTOMRIGHT*/ )
            {
                handled = true;
                return new IntPtr(18 /*HTBORDER*/);
            }
            break;
    }
    return IntPtr.Zero;
}

[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern IntPtr DefWindowProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);

Это дает вам окно в Windows 7, подходящее для всплывающих подсказок в области уведомлений (например, всплывающих окон с часами или громкостью). Кстати, вы можете воспроизвести затенение в нижней части всплывающей подсказки, создав элемент управления высотой 44 и установив его фон:

<Control.Background>
    <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
        <GradientStop Color="{x:Static SystemColors.GradientActiveCaptionColor}" Offset="0"/>
        <GradientStop Color="{x:Static SystemColors.InactiveBorderColor}" Offset="0.1"/>
    </LinearGradientBrush>
</Control.Background>
...