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

发布于 2024-07-16 04:21:19 字数 629 浏览 3 评论 0 原文

单击 Vista 中的通知图标(例如网络或声音图标)时,您会看到一个带边框但无标题的对话框 (http://i.msdn.microsoft.com/Aa511448.NotificationArea22(en-us,MSDN.10).png):

< a href="http://i.msdn.microsoft.com/Aa511448.NotificationArea22(en-us,MSDN.10).png" rel="nofollow noreferrer">http://i.msdn.microsoft.com/ Aa511448.NotificationArea22(en-us,MSDN.10).png

如何在 WPF 中模拟这些? 创建一个新窗口并将 WindowStyle 设置为“None”并将 ResizeMode 设置为“CanResize”会产生接近的结果,只是框架稍微太薄并且对话框可调整大小,这是不希望的。 将 ResizeMode 设置为“NoResize”会导致窗口没有 Aero 边框(只有 2 像素的细实线边框。)

When single-clicking a notification icon in Vista (such as the network or sound icons) you are presented with a bordered yet captionless dialog (http://i.msdn.microsoft.com/Aa511448.NotificationArea22(en-us,MSDN.10).png):

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

How can I emulate these in WPF? Creating a new window and setting WindowStyle to "None" and ResizeMode to "CanResize" produces a close result except that the frame is slightly too thin and the dialog is resizable, which is undesirable. Setting ResizeMode to "NoResize" results in a window with no Aero border (just a thin 2px solid line border.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

日久见人心 2024-07-23 04:21:19

诀窍是自己添加边框。 我通过将主要内容元素设置为 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>

The trick is to add the border your self. I did so by making the main content element a DockPanel and adding a Border. You can use the border to customize the look to match the Vista Style windows. I'm not good with colors so I can't name that particular one but used Gray as an example.

Try the following

<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>
夜声 2024-07-23 04:21:19

我终于弄清楚了:如果将 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 知道光标位于边框上,我们将永远不会看到调整大小的光标。

I finally figured it out: If you set WindowStyle to "None" and ResizeMode to "CanResize" then you'll get the correct thick border without a caption, the only hitch is that you can still resize the window.

Fortunately this problem is easily rectified by handling WM_NCHITTEST for your Window instance:

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

By never letting Windows know that the cursor is on a border, we will never be presented with a resize cursor.

一紙繁鸢 2024-07-23 04:21:19

您需要的是指定窗口样式的正确组合,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);
}

What you need is to specify the right combination of window styles, WPF does not expose all the options available in Windows but you can set them yourself using pinvoke.

I'm not at a Vista machine right now so I can't test style combination to see what gives the correct look but the list of styles (in C#) is here http://pinvoke.net/default.aspx/user32/GetWindowLong.html

in you're Window class:

[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);
}
℡Ms空城旧梦 2024-07-23 04:21:19

我想我应该发布我到目前为止所想到的。 这非常接近:

<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 有黑色覆盖。 外边框的右侧和底部边缘也有强调色。 如果我真的这样做,我将创建一个从 Border 派生的 UserControl 来处理所有类似的小细节(并允许我根据需要调整大小)并将 Window 的样式放入资源字典中。

I figured I'd post what I've come up with so far. This gets pretty close:

<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>

Clearly they are using more than just a transparency on the ActiveWindowBorderColor to draw the middle of the border. It seems that the top 1/4 has a white overlay while the bottom 3/4 has a black overlay. Also the outer border has an accent color on the right and bottom edges. If I were to do this for real I would create a UserControl that derives from Border to handle all of the little details like that (and allow me to resize if I want) and throw the Window's style into a resource dictionary.

迷爱 2024-07-23 04:21:19

发布的代码中有一个解决方案 this 可以更好地解释论坛帖子的作用。

There is a solution in code posted here. I'm going to look into doing it in straight XAML though, there should be a way to style your window border so it looks close. You should also take a look at this for a better explanation of what the forum post is doing.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文