WPF阴影VS2012风格国界的窗口 [英] WPF borderless window with shadow VS2012 style

查看:780
本文介绍了WPF阴影VS2012风格国界的窗口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图创建一个看起来像Visual Studio 2012年我用的 WindowChrome 去除窗口边框,并改变了我的XAML边框的颜色。

I'm trying to create an application that looks like Visual Studio 2012. I have used WindowChrome to remove the window borders, and changed the border color in my xaml.

我不知道该怎么做的是油漆窗口的阴影,在这里你可以看到我在说什么的截图:

What I don't know how to do is paint the shadow of the window, here you can see an screenshot of what I'm saying:

正如你可以看到有一个阴影,其颜色也边框颜色

As you can see there is a shadow and its color is also the border color

你知道如何使用WPF实现它?

Do you know how to implement it using WPF?

推荐答案

我一直在努力上这样的库来复制的Visual Studio 2012的用户界面。自定义的镀铬并不难,但你应该照顾的是这样亮的边框,这是很难实现的。你可以只说你的设置窗口的背景颜色为透明和主电网的填充设置为大约30像素。网格周围的边框可以着色,具有彩色阴影效果有关,但这种方法迫使你重新设置 AllowsTransparency 来真正能极大地减少应用程序的可视化性能,这是后话你绝对不希望做的!

I have been working on such a library to copy the Visual Studio 2012 user interface. A custom chrome isn't that difficult but what you should take care of is this glowing border which is hard to implement. You could just say set the background color of your window to transparent and set the padding of the main grid to about 30px. A border around the grid could be colored and associated with a colored shadow effect but this approach forces you to set AllowsTransparency to true which drastically reduces visual performance of your application and this is something you definitely do not want to do!

我目前的做法,以创建一个只对边框的彩色阴影效果,是透明的,但没有任何内容在所有这样的窗口。 Evertime我的主窗口的位置改变我刚刚更新持有边界窗口的位置。所以,最后我处理两个窗口有消息假,边界将是主窗口的一部分。这是必要的,因为DWM库不提供一种方法来对窗户的彩色阴影效果,我想的Visual Studio 2012这是否similiar像我试过了。

My current approach to create such a window which just has a colored shadow effect on a border and is transparent but has no content at all. Evertime the position of my main window changes I just update the position of the window which holds the border. So in the end I am handling two windows with messages to fake that the border would be part of the main window. This was necessary because the DWM library doesn't provide a way to have a colored drop shadow effect for windows and I think Visual Studio 2012 does that similiar like I tried.

并延长这个帖子与信息局2013确实是不同的。围绕一个窗口边框只是1px的厚,色,但阴影是由DWM像代码这个这里绘制。如果你能活着,而无需蓝色/紫色/绿色的边框,只是平常的人,这是我会选择的办法!只是不要设置 AllowsTransparency 为true,否则你已经失去了。

And to extend this post with more information: Office 2013 does that differently. The border around a window is just 1px thick and colored, yet the shadow is drawn by DWM with a code like this one here. If you can live without having blue/purple/green borders and just usual ones this is the approach I would choose! Just don't set AllowsTransparency to true, otherwise you have lost.

这是我的窗口的屏幕截图奇怪的颜色突出显示是什么样子:

And here is a screenshot of my window with strange color to highlight what it looks like:

下面是关于如何启动

请记住,我的代码是很长,这样我只能告诉你基本的事情要做,你应该能够至少在某种程度上开始。首先我要假设我们以某种方式设计我们的主窗口(手动或使用 MahApps.Metro 包我昨天尝试了的 - 有一些修改源代码,这是真正的好(1)),我们目前正在努力实现发光的阴影边框,我称之为 GlowWindow 从现在开始。最简单的方法是创建一个窗口下面的XAML代码

Please keep in mind that my code is quite long, such that I will only be able to show you the basic things to do and you should be able to at least start somehow. First of all I'm going to assume that we have designed our main window somehow (either manually or with the MahApps.Metro package I tried out yesterday - with some modifications to the sourcecode this is really good(1)) and we are currently working to implement the glowing shadow border, which I will call GlowWindow from now on. The easiest approach is to create a window with the following XAML code

<Window x:Class="MetroUI.Views.GlowWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Name="GlowWindow"
    Title="" Width="300" Height="100" WindowStartupLocation="Manual"
    AllowsTransparency="True" Background="Transparent" WindowStyle="None"
    ShowInTaskbar="False" Foreground="#007acc" MaxWidth="5000" MaxHeight="5000">
    <Border x:Name="OuterGlow" Margin="10" Background="Transparent"
            BorderBrush="{Binding Foreground, ElementName=GlowWindow}"
            BorderThickness="5">
        <Border.Effect>
            <BlurEffect KernelType="Gaussian" Radius="15" RenderingBias="Quality" />
        </Border.Effect>
    </Border>
</Window>



由此产生的窗口应该如下图。

The resulting window should look like the following picture.

接下来的步骤是相当困难 - 当我们的主窗口中派生我们要使GlowWindow可见,但背后的主要窗口,我们必须更新GlowWindow的位置被移动或调整主窗口的时候。我的建议,以防止能够而且将会出现视觉毛刺或者是位置或窗口大小的每一个变化过程中隐藏GlowWindow。一旦这样的动作完成只是再次显示。

The next steps are quite difficult - when our main window spawns we want to make the GlowWindow visible but behind the main window and we have to update the position of the GlowWindow when the main window is being moved or resized. What I suggest to prevent visual glitches that can AND will occur is to hide the GlowWindow during every change of either location or size of the window. Once finished with such action just show it again.

我有一些方法,这就是所谓的在不同情况下(这可能是很多,但只是为了得到确认)

I have some method which is called in different situations (it might be a lot but just to get sure)

private void UpdateGlowWindow(bool isActivated = false) {
    if(this.DisableComposite || this.IsMaximized) {
        this.glowWindow.Visibility = System.Windows.Visibility.Collapsed;
        return;
    }
    try {
        this.glowWindow.Left = this.Left - 10;
        this.glowWindow.Top = this.Top - 10;
        this.glowWindow.Width = this.Width + 20;
        this.glowWindow.Height = this.Height + 20;
        this.glowWindow.Visibility = System.Windows.Visibility.Visible;
        if(!isActivated)
            this.glowWindow.Activate();
    } catch(Exception) {
    }
}

这方法主要是叫我的自定义的WndProc 我已经连接到主窗口:

This method is mainly called in my custom WndProc I have attached to the main window:

/// <summary>
/// An application-defined function that processes messages sent to a window. The WNDPROC type
/// defines a pointer to this callback function.
/// </summary>
/// <param name="hwnd">A handle to the window.</param>
/// <param name="uMsg">The message.</param>
/// <param name="wParam">Additional message information. The contents of this parameter depend on
/// the value of the uMsg parameter.</param>
/// <param name="lParam">Additional message information. The contents of this parameter depend on
/// the value of the uMsg parameter.</param>
/// <param name="handled">Reference to boolean value which indicates whether a message was handled.
/// </param>
/// <returns>The return value is the result of the message processing and depends on the message sent.
/// </returns>
private IntPtr WindowProc(IntPtr hwnd, int uMsg, IntPtr wParam, IntPtr lParam, ref bool handled) {
    // BEGIN UNMANAGED WIN32
    switch((WinRT.Message)uMsg) {
        case WinRT.Message.WM_SIZE:
            switch((WinRT.Size)wParam) {
                case WinRT.Size.SIZE_MAXIMIZED:
                    this.Left = this.Top = 0;
                    if(!this.IsMaximized)
                        this.IsMaximized = true;
                    this.UpdateChrome();
                    break;
                case WinRT.Size.SIZE_RESTORED:
                    if(this.IsMaximized)
                        this.IsMaximized = false;
                    this.UpdateChrome();
                    break;
            }
            break;

        case WinRT.Message.WM_WINDOWPOSCHANGING:
            WinRT.WINDOWPOS windowPosition = (WinRT.WINDOWPOS)Marshal.PtrToStructure(lParam, typeof(WinRT.WINDOWPOS));
            Window handledWindow = (Window)HwndSource.FromHwnd(hwnd).RootVisual;
            if(handledWindow == null)
                return IntPtr.Zero;
            bool hasChangedPosition = false;
            if(this.IsMaximized == true && (this.Left != 0 || this.Top != 0)) {
                windowPosition.x = windowPosition.y = 0;
                windowPosition.cx = (int)SystemParameters.WorkArea.Width;
                windowPosition.cy = (int)SystemParameters.WorkArea.Height;
                hasChangedPosition = true;
                this.UpdateChrome();
                this.UpdateGlowWindow();
            }
            if(!hasChangedPosition)
                return IntPtr.Zero;
            Marshal.StructureToPtr(windowPosition, lParam, true);
            handled = true;
            break;
    }
    return IntPtr.Zero;
    // END UNMANAGED WIN32
}



不过还是有留下一个问题 - 一旦你调整你的主窗口中的GlowWindow将无法掩盖其大小整个窗口。也就是说,如果你调整你的主窗口中你的屏幕maxWidth,则该GlowWindow的WIDT是因为我已经加了10余量它的值相同+ 20。因此,右边缘将其长相丑陋的主窗口的右侧边缘权之前被中断。为了防止这一点,我用一个钩子,使GlowWindow一个工具窗口:

However there is still an issue left - once you resize your main window the GlowWindow will not be able to cover the whole window with its size. That is if you resize your main window to about MaxWidth of your screen, then the widt of the GlowWindow would be the same value + 20 as I have added a margin of 10 to it. Therefore the right edge would be interrupted right before the right edge of the main window which looks ugly. To prevent this I used a hook to make the GlowWindow a toolwindow:

this.Loaded += delegate {
    WindowInteropHelper wndHelper = new WindowInteropHelper(this);
    int exStyle = (int)WinRT.GetWindowLong(wndHelper.Handle, (int)WinRT.GetWindowLongFields.GWL_EXSTYLE);
    exStyle |= (int)WinRT.ExtendedWindowStyles.WS_EX_TOOLWINDOW;
    WinRT.SetWindowLong(wndHelper.Handle, (int)WinRT.GetWindowLongFields.GWL_EXSTYLE, (IntPtr)exStyle);
};

和我们仍然会有一些问题 - 当你用鼠标在GlowWindow和左点击将被激活,并得到这意味着它将重叠,看起来像这样的主窗口中的重点:

And still we will have some issues - when you go with the mouse over the GlowWindow and left click it will be activated and get the focus which means it will overlap the main window which looks like this:

要防止正好赶上的激活事件边框并把主窗口前台。

To prevent that just catch the Activated event of the border and bring the main window to the foreground.

您应该怎么做呢?

我建议不要尝试了这一点 - 我花了大约一个月的时间实现我想要的东西,仍然有一些问题,比如,我会去的,如Office 2013的方法做 - 彩色的边框和往常一样阴影与DWM API调用 - 没有别的,仍然看起来不错

I suggest NOT to try this out - it took me about a month to achieve what I wanted and still it has some issues, such that I would go for an approach like Office 2013 does - colored border and usual shadow with the DWM API calls - nothing else and still it looks good.

(1)我刚才编辑的一些文件,以使在窗口边框这是对窗口8禁用我。此外,我还操纵了填充标题栏,使得它看起来并不认为sqeezed就地,最后我不得不改变全部大写的属性来模仿渲染的Visual Studio的方式标题。到目前为止, MahApps.Metro 是绘制主窗口,它甚至支持AeroSnap我无法与常规P执行/ Invoke调用一个更好的方式。

(1) I have just edited some files to enable the border around the window which is disabled on Window 8 for me. Furthermore I have manipulated the Padding of the title bar such that it doesn't look that sqeezed inplace and lastly I have change the All-Caps property to mimic Visual Studio's way of rendering the title. So far the MahApps.Metro is a better way of drawing the main window as it even supports AeroSnap I couldn't implement with usual P/Invoke calls.

这篇关于WPF阴影VS2012风格国界的窗口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆