Эмуляция диалоговых окон значков уведомлений Vista с WPF - PullRequest
3 голосов
/ 22 марта 2009

При однократном щелчке на значке уведомлений в Vista (например, на значках сети или звука) вы получаете окаймленное диалоговое окно без заголовков (http://i.msdn.microsoft.com/Aa511448.NotificationArea22(en-us,MSDN.10).png):

)

http://i.msdn.microsoft.com/Aa511448.NotificationArea22(en-us,MSDN.10).png

Как я могу эмулировать их в WPF? Создание нового окна и установка WindowStyle на «None» и ResizeMode на «CanResize» приводит к близкому результату, за исключением того, что рамка немного слишком тонкая, а размер диалогового окна изменяется, что нежелательно. Установка ResizeMode в «NoResize» приводит к появлению окна без границы Aero (только тонкая граница в 2 пикселя сплошной линии).

Ответы [ 5 ]

2 голосов
/ 26 марта 2009

Я наконец понял: если вы установите WindowStyle на «None» и ResizeMode на «CanResize», тогда вы получите правильную толстую границу без заголовка, единственная загвоздка в том, что вы все равно можете изменить размер окна. *

К счастью, эту проблему легко устранить, обработав WM_NCHITTEST для вашего Window экземпляра:

private IntPtr _hwnd;

protected override void OnSourceInitialized(EventArgs e) {
    _hwnd = new System.Windows.Interop.WindowInteropHelper(this).Handle;
    System.Windows.Interop.HwndSource.FromHwnd(_hwnd).AddHook(_WndProc);
    base.OnSourceInitialized(e);
}

private const int WM_NCHITTEST = 132;
private const int HTCLIENT = 1;

private IntPtr _WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) {
    // We should only receive messages for our own window handle.
    System.Diagnostics.Debug.Assert(hwnd == _hwnd);

    if (msg == WM_NCHITTEST) {
        handled = true;
        return (IntPtr)HTCLIENT;
    }
    return IntPtr.Zero;
}

Никогда не сообщая Windows, что курсор находится на границе, мы никогда не увидим курсор изменения размера.

2 голосов
/ 22 марта 2009

Хитрость в том, чтобы добавить границы себе. Я сделал это, сделав основной элемент содержимого DockPanel и добавив Border. Вы можете использовать границу, чтобы настроить внешний вид в соответствии с окнами в стиле Vista. Я не очень хорошо разбираюсь в цветах, поэтому не могу назвать этот конкретный, но в качестве примера использовал серый.

Попробуйте следующее

<Window x:Class="WpfApplication10.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" 
    Height="300" 
    Width="300"
    WindowStyle="None"
    ResizeMode="NoResize">
    <DockPanel>
        <Border
            BorderBrush="Gray"
            BorderThickness="5">

            <TextBlock>Here we go</TextBlock>

        </Border>
    </DockPanel>
</Window>
1 голос
/ 23 марта 2009

Вам нужно указать правильную комбинацию стилей окна, WPF не отображает все параметры, доступные в Windows, но вы можете установить их самостоятельно, используя pinvoke.

Я сейчас не на машине с Vista, поэтому не могу проверить комбинацию стилей, чтобы увидеть, что дает правильный вид, но список стилей (в C #) здесь http://pinvoke.net/default.aspx/user32/GetWindowLong.html

в вашем классе окон:

[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, uint dwNewLong);

[DllImport("user32.dll")]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);

private const int GWL_STYLE = -16;
private const int GWL_EXSTYLE = -20;
private const UInt32 SWP_NOSIZE = 0x0001;
private const UInt32 SWP_NOMOVE = 0x0002;
private const UInt32 SWP_NOZORDER = 0x0004;
private const UInt32 SWP_NOREDRAW = 0x0008;
private const UInt32 SWP_NOACTIVATE = 0x0010;
private const UInt32 SWP_FRAMECHANGED = 0x0020;

public override void OnSourceInitialized(EventArgs e)
{
    IntPtr hwnd = new System.Windows.Interop.WindowInteropHelper(this).Handle;

    // set styles to a combination of WS_ flags and exstyles to a combination of WS_EX_ flags

    SetWindowLong(hwnd, GWL_STYLE, styles);
    SetWindowLong(hwnd, GWL_EXSTYLE, exstyles);

    // and to activate changes:
    SetWindowPos(hwnd,IntPtr.Zero,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_FRAMECHANGED);
}
0 голосов
/ 23 марта 2009

Я решил опубликовать то, что придумал. Это довольно близко:

<Window.Style>
    <Style TargetType="{x:Type Window}">
        <Setter Property="AllowsTransparency"       Value="True"            />
        <Setter Property="Background"           Value="{x:Null}"        />
        <Setter Property="BorderBrush"          Value="{x:Null}"        />
        <Setter Property="BorderThickness"      Value="0"           />
        <Setter Property="OverridesDefaultStyle"    Value="True"            />
        <Setter Property="ResizeMode"           Value="NoResize"        />
        <Setter Property="SizeToContent"        Value="WidthAndHeight"      />
        <Setter Property="WindowStyle"          Value="None"            />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Window}">
                    <Border BorderThickness="1" CornerRadius="4" Background="{x:Null}">
                        <Border.BorderBrush>
                            <SolidColorBrush Color="{x:Static SystemColors.WindowFrameColor}" Opacity="0.75" />
                        </Border.BorderBrush>
                        <Border BorderThickness="5" Background="{x:Null}">
                            <Border.BorderBrush>
                                <SolidColorBrush Color="{x:Static SystemColors.ActiveBorderColor}" Opacity="0.5" />
                            </Border.BorderBrush>
                            <Border BorderThickness="1" Background="White">
                                <Border.BorderBrush>
                                    <SolidColorBrush Color="{x:Static SystemColors.WindowFrameColor}" Opacity="0.75" />
                                </Border.BorderBrush>

                                <ContentPresenter />
                            </Border>
                        </Border>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Style>

Очевидно, что они используют больше, чем просто прозрачность на ActiveWindowBorderColor, чтобы нарисовать середину границы. Кажется, что верхняя 1/4 имеет белое наложение, а нижняя 3/4 имеет черное наложение. Также внешняя граница имеет акцентный цвет на правом и нижнем краях. Если бы я делал это по-настоящему, я бы создал UserControl, производный от Border, чтобы обрабатывать все такие мелкие детали (и позволял бы мне изменять размер, если я хочу) и бросать стиль Window в словарь ресурсов.

0 голосов
/ 23 марта 2009

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

...