97

If you set ResizeMode="CanResizeWithGrip" on a WPF Window then a resize grip is shown in the lower right corner, as below:

If you set WindowStyle="None" as well the title bar disappears but the grey bevelled edge remains until you set ResizeMode="NoResize". Unfortunately, with this combination of properties set, the resize grip also disappears.

I have overridden the Window's ControlTemplate via a custom Style. I want to specify the border of the window myself, and I don't need users to be able to resize the window from all four sides, but I do need a resize grip.

Can someone detail a simple way to meet all of these criteria?

  1. Do not have a border on the Window apart from the one I specify myself in a ControlTemplate.
  2. Do have a working resize grip in the lower right corner.
  3. Do not have a title bar.
Laurel
  • 5,522
  • 11
  • 26
  • 49
Drew Noakes
  • 266,361
  • 143
  • 616
  • 705
  • 3
    Please note that Allowtransperency creates memory leak. So avoid using it. Please refer to http://social.msdn.microsoft.com/Forums/en/wpf/thread/fc76b788-c4a6-45f4-896e-5646dffd2155 – Dipesh Bhatt Feb 24 '12 at 07:12
  • 1
    @DipeshBhatt I couldn't find any explanation to that claim in the link you provided. maybe you meant to post link https://social.msdn.microsoft.com/Forums/vstudio/en-US/69bae823-dbe9-4a38-b964-e87b71195bb6/window-on-seperate-thread-memory-leak-when-allowtransparencytrue-progress-window?forum=wpf – itsho Feb 12 '17 at 14:10
  • I was facing the gray edge at the top although I had set the window style to None. ResizeMode="NoResize" solved my problem. – Surendra Shrestha May 11 '18 at 13:48

5 Answers5

187

If you set the AllowsTransparency property on the Window (even without setting any transparency values) the border disappears and you can only resize via the grip.

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="640" Height="480" 
    WindowStyle="None"
    AllowsTransparency="True"
    ResizeMode="CanResizeWithGrip">

    <!-- Content -->

</Window>

Result looks like:

Laurel
  • 5,522
  • 11
  • 26
  • 49
ZombieSheep
  • 28,629
  • 10
  • 64
  • 112
  • Pure fluke I knew this - I was playing with the same control set myself this afternoon. :) – ZombieSheep Mar 04 '09 at 16:26
  • 2
    Wow, I wouldn't expect this, but it is totally handy for make-your-own-post-it-notes-in-5-minutes, thanks :) – Tomáš Kafka Jan 05 '10 at 21:40
  • 4
    AllowTransparency has several downfalls though, Windows can no longer host sub window controls such was WebBrowser, Usually forces software rendering, has reported memory leaks. See my workaround below. – Wobbles Aug 02 '14 at 12:30
  • You only need WindowStyle="None" to get rid of the borders; AllowsTransparency only happens to require it, but doesn't affect the borders.. – Grault May 01 '15 at 18:15
  • 2
    @Grault thats gets rid of the window header, but there is still a solid border around the form. AllowsTransparency gets rid of the borders. – Wobbles Oct 17 '15 at 14:17
  • Les choses simples sont plus efficaces / The simple things are more efficient –  Feb 23 '16 at 15:29
90

I was trying to create a borderless window with WindowStyle="None" but when I tested it, seems that appears a white bar in the top, after some research it appears to be a "Resize border", here is an image (I remarked in yellow):

The Challenge

After some research over the internet, and lots of difficult non xaml solutions, all the solutions that I found were code behind in C# and lots of code lines, I found indirectly the solution here: Maximum custom window loses drop shadow effect

<WindowChrome.WindowChrome>
    <WindowChrome 
        CaptionHeight="0"
        ResizeBorderThickness="5" />
</WindowChrome.WindowChrome>

Note : You need to use .NET 4.5 framework, or if you are using an older version use WPFShell, just reference the shell and use Shell:WindowChrome.WindowChrome instead.

I used the WindowChrome property of Window, if you use this that white "resize border" disappears, but you need to define some properties to work correctly.

CaptionHeight: This is the height of the caption area (headerbar) that allows for the Aero snap, double clicking behaviour as a normal title bar does. Set this to 0 (zero) to make the buttons work.

ResizeBorderThickness: This is thickness at the edge of the window which is where you can resize the window. I put to 5 because i like that number, and because if you put zero its difficult to resize the window.

After using this short code the result is this:

The Solution

And now, the white border disappeared without using ResizeMode="NoResize" and AllowsTransparency="True", also it shows a shadow in the window.

Later I will explain how to make to work the buttons (I didn't used images for the buttons) easily with simple and short code, Im new and i think that I can post to codeproject, because here I didn't find the place to post the tutorial.

Maybe there is another solution (I know that there are hard and difficult solutions for noobs like me) but this works for my personal projects.

Here is the complete code

<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:Concursos"
    mc:Ignorable="d"
    Title="Concuros" Height="350" Width="525"
    WindowStyle="None"
    WindowState="Normal" 
    ResizeMode="CanResize"
    >
<WindowChrome.WindowChrome>
    <WindowChrome 
        CaptionHeight="0"
        ResizeBorderThickness="5" />
</WindowChrome.WindowChrome>

    <Grid>

    <Rectangle Fill="#D53736" HorizontalAlignment="Stretch" Height="35" VerticalAlignment="Top" PreviewMouseDown="Rectangle_PreviewMouseDown" />
    <Button x:Name="Btnclose" Content="r" HorizontalAlignment="Right" VerticalAlignment="Top" Width="35" Height="35" Style="{StaticResource TempBTNclose}"/>
    <Button x:Name="Btnmax" Content="2" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,0,35,0" Width="35" Height="35" Style="{StaticResource TempBTNclose}"/>
    <Button x:Name="Btnmin" Content="0" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,0,70,0" Width="35" Height="35" Style="{StaticResource TempBTNclose}"/>

</Grid>

Thank you!

Community
  • 1
  • 1
Fernando Aguirre
  • 1,099
  • 8
  • 7
  • 5
    Well, Kudos for this one! This is by far the simplest/no trades off answer of this thread! Should be getting far more 'up' vote. I have to admit that I was kind of septic about it, especially about what was happening under the hood. I even checked the WFP tree and it sure looks like the transparency is not added back. Even tricky controls like the 'WebBrowser' display just fine. I had a rendering freezing issue using transparency when the app was under a lot of stress... Well, this is not happening with this solution. I think it might be time to retire @Wobbles solution! – VeV May 21 '16 at 08:38
  • 1
    Looks like this may still need interop for window dragging if I interpret the use of the `Rectangle_PreviewMouseDown` event properly. – Wobbles May 21 '16 at 10:31
  • This may not work in <= Win 8.1, saw some odd results in my VM. Windows 7 & 8 are the primary concerns as they do the stupid Aero border thing. – Wobbles May 21 '16 at 11:19
  • Thank you for your reply's – Fernando Aguirre Jun 21 '16 at 03:20
  • Hi @FernandoAguirre, I posted [this related question](http://stackoverflow.com/q/39182413/1461424), and would be grateful if you have an answer. – sampathsris Aug 27 '16 at 14:51
  • By far the best answer! Exactly what needs to be done. No tradeoffs, no hacks with interop. Thank you. – Jonathan Alfaro Oct 13 '16 at 02:25
  • This is excellent. Fixed the issue for me. I'm amazed it took me as long as it did to find this, but thanks a bunch! http://i2.kym-cdn.com/photos/images/newsfeed/000/117/814/are-you-wizard.jpg – Callan Feb 02 '17 at 18:22
  • I get a weird blue rectangle flicker for a split second where the window's shadow should be on Windows 10 (Fall Creators Update) with this. Might be my graphics card. – 1adam12 Oct 25 '17 at 16:19
  • Might also want to add `GlassFrameThickness="0"` to remove any visual border. – James Coyle Oct 26 '18 at 15:33
  • Could you provide the static resource StaticResource TempBTNclose? i want to to the same look and feel for my window borderless buttons. – Ralph Jan 19 '19 at 18:11
  • If you need to set WindowChrome in code, here's how to do it: ```w.SetValue(System.Windows.Shell.WindowChrome.WindowChromeProperty, new System.Windows.Shell.WindowChrome() { CaptionHeight = 0, ResizeBorderThickness = new Thickness(5) });``` where ```w``` is a variable of type ```Window```. – Daap Nov 17 '19 at 04:42
  • I definately suggest to set `CaptionHeight="35"` for a better user expirience, that moving the window and maximise with doubleclick is possible at the top area. At the buttons set `WindowChrome.IsHitTestVisibleInChrome="True"` that they are clickable. – Apfelkuacha Dec 01 '19 at 15:35
  • Is this solution still valid? Tried it with .NET Core 3.1 and Windows 10. I still get the white bar at the top of the window. Adding the `WindowChrome` markup has no effect. – Mike Ward Mar 09 '20 at 14:12
  • Figured out why it did not work in my case. Posted answer below. – Mike Ward Mar 09 '20 at 15:43
  • This results in flickering for me while resizing, but not using this has no flickering at all. Is this by chance defaulting to software rendering or something? If so, it's completely useless, as you're losing everything powerful about WPF. – Krythic Oct 07 '20 at 23:26
40

While the accepted answer is very true, just want to point out that AllowTransparency has some downfalls. It does not allow child window controls to show up, ie WebBrowser, and it usually forces software rendering which can have negative performance effects.

There is a better work around though.

When you want to create a window with no border that is resizeable and is able to host a WebBrowser control or a Frame control pointed to a URL you simply couldn't, the contents of said control would show empty.

I found a workaround though; in the Window, if you set the WindowStyle to None, ResizeMode to NoResize (bear with me, you will still be able to resize once done) then make sure you have UNCHECKED AllowsTransparency you will have a static sized window with no border and will show the browser control.

Now, you probably still want to be able to resize right? Well we can to that with a interop call:

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

    [DllImportAttribute("user32.dll")]
    public static extern bool ReleaseCapture();

    //Attach this to the MouseDown event of your drag control to move the window in place of the title bar
    private void WindowDrag(object sender, MouseButtonEventArgs e) // MouseDown
    {
        ReleaseCapture();
        SendMessage(new WindowInteropHelper(this).Handle,
            0xA1, (IntPtr)0x2, (IntPtr)0);
    }

    //Attach this to the PreviewMousLeftButtonDown event of the grip control in the lower right corner of the form to resize the window
    private void WindowResize(object sender, MouseButtonEventArgs e) //PreviewMousLeftButtonDown
    {
        HwndSource hwndSource = PresentationSource.FromVisual((Visual)sender) as HwndSource;
        SendMessage(hwndSource.Handle, 0x112, (IntPtr)61448, IntPtr.Zero);
    }

And voila, A WPF window with no border and still movable and resizable without losing compatibility with with controls like WebBrowser

Wobbles
  • 2,789
  • 1
  • 19
  • 44
  • How should we go about if we want to resize from all sides, not just bottom right, but still want no border visible? – Daniel Dec 10 '14 at 22:17
  • 6
    Here are the other wParam values, just assign new events to new UI Objects using these as needed `private enum ResizeDirection { Left = 61441, Right = 61442, Top = 61443, TopLeft = 61444, TopRight = 61445, Bottom = 61446, BottomLeft = 61447, BottomRight = 61448, }` – Wobbles Mar 24 '15 at 12:50
  • This works great for me, with one exception though once you have NoResize you can't snap the window by dragging it to the top anymore. – CJK May 11 '15 at 16:30
  • 2
    @CJK True, but no doubt you can hook the windows messages for that as-well and handle it. – Wobbles May 11 '15 at 22:33
  • I cannot drag the window. any idea why? (resize works like a charm) – Li3ro Nov 12 '15 at 12:02
  • Only thing I discovered here: I placed borders around my Window to catch the events. Works fine. I set the Cursor of the given Borders to show the resize-Cursors on mouse over. However, while dragging/resizing the cursor may reset... But that's just a minor finding – dba Nov 17 '16 at 08:39
5

Sample here:

<Style TargetType="Window" x:Key="DialogWindow">
        <Setter Property="AllowsTransparency" Value="True"/>
        <Setter Property="WindowStyle" Value="None"/>
        <Setter Property="ResizeMode" Value="CanResizeWithGrip"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Window}">
                    <Border BorderBrush="Black" BorderThickness="3" CornerRadius="10" Height="{TemplateBinding Height}"
                            Width="{TemplateBinding Width}" Background="Gray">
                        <DockPanel>
                            <Grid DockPanel.Dock="Top">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition></ColumnDefinition>
                                    <ColumnDefinition Width="50"/>
                                </Grid.ColumnDefinitions>
                                <Label Height="35" Grid.ColumnSpan="2"
                                       x:Name="PART_WindowHeader"                                            
                                       HorizontalAlignment="Stretch" 
                                       VerticalAlignment="Stretch"/>
                                <Button Width="15" Height="15" Content="x" Grid.Column="1" x:Name="PART_CloseButton"/>
                            </Grid>
                            <Border HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
                                        Background="LightBlue" CornerRadius="0,0,10,10" 
                                        Grid.ColumnSpan="2"
                                        Grid.RowSpan="2">
                                <Grid>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition/>
                                        <ColumnDefinition Width="20"/>
                                    </Grid.ColumnDefinitions>
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="*"/>
                                        <RowDefinition Height="20"></RowDefinition>
                                    </Grid.RowDefinitions>
                                    <ResizeGrip Width="10" Height="10" Grid.Column="1" VerticalAlignment="Bottom" Grid.Row="1"/>
                                </Grid>
                            </Border>
                        </DockPanel>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
Kebes
  • 85
  • 1
  • 2
0

I was having difficulty getting the answer by @fernando-aguirre using WindowChrome to work. It was not working in my case because I was overriding OnSourceInitialized in the MainWindow and not calling the base class method.

protected override void OnSourceInitialized(EventArgs e)
{
    ViewModel.Initialize(this);
    base.OnSourceInitialized(e); // <== Need to call this!
}

This stumped me for a very long time.

Mike Ward
  • 2,723
  • 1
  • 24
  • 38