5

Got a custom wpf window (WindowStyle=None, AllowTransparancy=true) and wondering how to get Windows edge resize features to work.. you know when draging window and mouse touches left, right or top edge of screen (even corners in W10).

Tried looking into WM notification but none of them seems to be what im looking for..

To clearify, not ordinary window resizeing.. but draging to screen edge and letting Windows resize it to half/full/quarter (think its called Aero Snap). And I can do it with ordinary resize calls but that doesnt show the transparent preview window or drop animation on mouse when touches edge.

Thanks

Joel R
  • 51
  • 1
  • 3

3 Answers3

13

Step 1

Create a Style (in <Window1.Resources>) for rectangles as the Grip area around the window:

<Style x:Key="RectBorderStyle" TargetType="Rectangle">
    <Setter Property="Focusable" Value="False" />
    <Setter Property="Fill" Value="Transparent" />
    <Setter Property="Tag" Value="{Binding RelativeSource={RelativeSource AncestorType=Window}}" />
    <EventSetter Event="MouseLeftButtonDown" Handler="Resize_Init"/>
    <EventSetter Event="MouseLeftButtonUp" Handler="Resize_End"/>
    <EventSetter Event="MouseMove" Handler="Resizeing_Form"/>
</Style>

Step 2

Add these styled rectangles to your window. (You can add them inside a simple grid within your window)

<Rectangle x:Name="leftSizeGrip"
    Width="7"
    HorizontalAlignment="Left"
    Cursor="SizeWE"
    Style="{StaticResource RectBorderStyle}" />
<Rectangle x:Name="rightSizeGrip"
    Width="7"
    HorizontalAlignment="Right"
    Cursor="SizeWE"
    Style="{StaticResource RectBorderStyle}" />
<Rectangle x:Name="topSizeGrip"
    Height="7"
    VerticalAlignment="Top"
    Cursor="SizeNS"
    Style="{StaticResource RectBorderStyle}" />
<Rectangle x:Name="bottomSizeGrip"
    Height="7"
    VerticalAlignment="Bottom"
    Cursor="SizeNS"
    Style="{StaticResource RectBorderStyle}" />
<!--  Corners  -->
<Rectangle Name="topLeftSizeGrip"
    Width="7"
    Height="7"
    HorizontalAlignment="Left"
    VerticalAlignment="Top"
    Cursor="SizeNWSE"
    Style="{StaticResource RectBorderStyle}" />
<Rectangle Name="bottomRightSizeGrip"
    Width="7"
    Height="7"
    HorizontalAlignment="Right"
    VerticalAlignment="Bottom"
    Cursor="SizeNWSE"
    Style="{StaticResource RectBorderStyle}" />
<Rectangle Name="topRightSizeGrip"
    Width="7"
    Height="7"
    HorizontalAlignment="Right"
    VerticalAlignment="Top"
    Cursor="SizeNESW"
    Style="{StaticResource RectBorderStyle}" />
<Rectangle Name="bottomLeftSizeGrip"
    Width="7"
    Height="7"
    HorizontalAlignment="Left"
    VerticalAlignment="Bottom"
    Cursor="SizeNESW"
    Style="{StaticResource RectBorderStyle}" />

Step 3

Add these codes to the code behind of your window (window1.xaml.cs) (or to MyStyle.xaml.cs if you are using a template for window and you have added the 8 rectangles inside the template)

#region ResizeWindows
bool ResizeInProcess = false;
private void Resize_Init(object sender, MouseButtonEventArgs e)
{
    Rectangle senderRect = sender as Rectangle;
    if (senderRect != null)
    {
        ResizeInProcess = true;
        senderRect.CaptureMouse();
    }
}

private void Resize_End(object sender, MouseButtonEventArgs e)
{
    Rectangle senderRect = sender as Rectangle;
    if (senderRect != null)
    {
        ResizeInProcess = false; ;
        senderRect.ReleaseMouseCapture();
    }
}

private void Resizeing_Form(object sender, MouseEventArgs e)
{
    if (ResizeInProcess)
    {
        Rectangle senderRect = sender as Rectangle;
        Window mainWindow = senderRect.Tag as Window;
        if (senderRect != null)
        {
            double width = e.GetPosition(mainWindow).X;
            double height = e.GetPosition(mainWindow).Y;
            senderRect.CaptureMouse();
            if (senderRect.Name.ToLower().Contains("right"))
            {
                width += 5;
                if (width > 0)
                    mainWindow.Width = width;
            }
            if (senderRect.Name.ToLower().Contains("left"))
            {
                width -= 5;
                mainWindow.Left += width;
                width = mainWindow.Width - width;
                if (width > 0)
                {
                    mainWindow.Width = width;
                }
            }
            if (senderRect.Name.ToLower().Contains("bottom"))
            {
                height += 5;
                if (height > 0)
                    mainWindow.Height = height;
            }
            if (senderRect.Name.ToLower().Contains("top"))
            {
                height -= 5;
                mainWindow.Top += height;
                height = mainWindow.Height - height;
                if (height > 0)
                {
                    mainWindow.Height = height;
                }
            }
        }
    }
}
#endregion

Step 4

Press F5 and enjoy!

note:

these 8 rectangles are transparent. if you can't make it properly work, just change the Fill value of the style to Red to see where are they positioned.

Another note:

When maximized you might want to disable all these rectangles. well the easiest way is to handle the WindowStateChanged event and disable the grid containing them.

Bizhan
  • 16,157
  • 9
  • 63
  • 101
  • Thanks for the truly great post.. but im not after resizeing by draging window edges but rather letting Windows resize it when draging it to screen edge (think its called Aero Snap). – Joel R Nov 26 '14 at 20:23
  • I don't know how to do Aero Snap but as far as I know the WindowStyle is responsible for all these sorts of behaviors and when set to None, it will typically lose them. so my advice is to find out more about Aero Snap and then look for some sort of hack. – Bizhan Nov 26 '14 at 20:42
  • 2
    Great answer. The only small change I'd maybe say is to have a `Margin` on the left, top, right and bottom `Rectangles` so that they do not interfere with the corner `Rectangles`. – Stephen Ross Apr 22 '16 at 14:11
2

Answer of Bizhan is great! But he made a small mistake. It's solution does not take into account the maximum and minimum window sizes. Because of this, instead of changing the window, it shifts. It work:

    private void Resizeing_Form(object sender, MouseEventArgs e)
    {
        if (ResizeInProcess)
        {
            double temp = 0;
            Rectangle senderRect = sender as Rectangle;
            Window mainWindow = senderRect.Tag as Window;
            if (senderRect != null)
            {
                double width = e.GetPosition(mainWindow).X;
                double height = e.GetPosition(mainWindow).Y;
                senderRect.CaptureMouse();
                if (senderRect.Name.Contains("right", StringComparison.OrdinalIgnoreCase))
                {
                    width += 5;
                    if (width > 0)
                        mainWindow.Width = width;
                }
                if (senderRect.Name.Contains("left", StringComparison.OrdinalIgnoreCase))
                {
                    width -= 5;
                    temp = mainWindow.Width - width;
                    if ((temp > mainWindow.MinWidth) && (temp < mainWindow.MaxWidth))
                    {
                        mainWindow.Width = temp;
                        mainWindow.Left += width;
                    }
                }
                if (senderRect.Name.Contains("bottom", StringComparison.OrdinalIgnoreCase))
                {
                    height += 5;
                    if (height > 0)
                        mainWindow.Height = height;
                }
                if (senderRect.Name.ToLower().Contains("top", StringComparison.OrdinalIgnoreCase))
                {
                    height -= 5;
                    temp = mainWindow.Height - height;
                    if ((temp > mainWindow.MinHeight) && (temp < mainWindow.MaxHeight))
                    {
                        mainWindow.Height = temp;
                        mainWindow.Top += height;
                    }
                }
            }
        }
    }
GMIKE
  • 21
  • 2
1

And for @GMIKE answer to work you need this String extension method (taken from here) :

public static class StringExtensions
{
    public static bool Contains(this string source, string toCheck, StringComparison comp)
    {
        return source?.IndexOf(toCheck, comp) >= 0;
    }
}
TRex
  • 127
  • 1
  • 8