使用WPF模拟Vista通知图标对话框

时间:2009-03-22 13:26:00

标签: wpf dialog icons notifications

单击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边框(只有一个2px的实线边框。)

5 个答案:

答案 0 :(得分:2)

诀窍是添加自己的边框。我这样做是通过使主要内容元素成为DockPanel并添加边框。您可以使用边框自定义外观以匹配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 :(得分:2)

我终于想通了:如果你将WindowStyle设置为“None”并将ResizeMode设置为“CanResize”,那么你将获得没有标题的正确粗边框,唯一的障碍是你仍然可以调整窗口大小。

幸运的是,通过处理Window实例的WM_NCHITTEST可以轻松解决此问题:

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 :(得分:1)

您需要指定窗口样式的正确组合,WPF不公开Windows中可用的所有选项,但您可以使用pinvoke自行设置它们。

我现在不在Vista机器上,所以我无法测试样式组合,看看是什么给出了正确的外观,但样式列表(在C#中)是http://pinvoke.net/default.aspx/user32/GetWindowLong.html

在你的Window类中:

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

答案 3 :(得分:0)

发布的代码here中有一个解决方案。我会考虑直接在XAML中进行操作,应该有一种方法来设置窗口边框的样式,使其看起来很接近。您还应该查看this以更好地解释论坛帖子正在做什么。

答案 4 :(得分:0)

我想我到目前为止发布了我想出的内容。这非常接近:

<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的样式抛出到资源字典中。