views:

526

answers:

2

I am using a window with no border and drawing the Chrome myself. I want to resize the window in a typical manner and have defined a 3x3 grid with the center being the content and the outer cells constituting the respective areas requiring different treatment (TopLeft/TopMiddle/TopRight... etc.) such as cursors. Maximize, Minimize, Move etc are all straight forward but I could use some pointers to resize in various directions based on the cell the cursor is over.

+1  A: 

This seems pretty tight. Min/Max width and Height are accounted for as well as variable borderwidths. The only issue I'm aware of is when the cursor movement is rapid and the size is within 20 pix of the min it sticks somewhat because of refresh rate. Not a huge deal but I'll sort it.

alt text

I can't seem to get the Window tag to display properly...(Just take out the apostrophe and it should be fine.) Anyone have any thoughts?

XAML

<'Window x:Class="Article_1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    Title="Article_1_Resizing"
    Background="Transparent" AllowsTransparency="True"
        WindowStyle="None" WindowStartupLocation="CenterScreen"
    MinHeight="100" Height="400" MaxHeight="600"
    MinWidth="100" Width="400" MaxWidth="800">

 <Window.Resources>

  <SolidColorBrush x:Key="Brush_ChromeBackground" Color="#FFC8D1E0"/>
  <SolidColorBrush x:Key="Brush_ChromeBorder" Color="#FFA0A0A0"/>

  <sys:Double x:Key="Chrome_BorderWidth">5</sys:Double>

 </Window.Resources>

 <Border x:Name="Border_Chrome"
     BorderBrush="{StaticResource Brush_ChromeBorder}" BorderThickness="1,1,1,1"
     CornerRadius="2,2,2,2"
     Width="Auto">

  <Grid x:Name="Grid" ShowGridLines="False">

   <Grid.RowDefinitions>
    <RowDefinition x:Name="row_Top" Height="Auto"/>
    <RowDefinition x:Name="row_Middle" Height="*"/>
    <RowDefinition x:Name="row_Bottom" Height="Auto"/>
   </Grid.RowDefinitions>

   <Grid.ColumnDefinitions>
    <ColumnDefinition x:Name="col_Left" Width="Auto"/>
    <ColumnDefinition x:Name="col_Middle" Width="*"/>
    <ColumnDefinition x:Name="col_Right" Width="Auto"/>
   </Grid.ColumnDefinitions>

   <!-- Top Row -->
   <Rectangle x:Name="Rectangle_TopLeft"
         Grid.Row="0" Grid.Column="0"
         Width="{StaticResource Chrome_BorderWidth}" Height="{StaticResource Chrome_BorderWidth}"
         Fill="{StaticResource Brush_ChromeBackground}"
         Cursor="SizeNWSE"
         MouseLeftButtonDown="Resize_Begin" MouseLeftButtonUp="Resize_End"
         MouseMove="Resize"/>

   <Rectangle x:Name="Rectangle_TopMiddle"
         Grid.Row="0" Grid.Column="1"
         Height="{StaticResource Chrome_BorderWidth}"
         Fill="{StaticResource Brush_ChromeBackground}"
         Cursor="SizeNS"
         MouseLeftButtonDown="Resize_Begin" MouseLeftButtonUp="Resize_End"
         MouseMove="Resize"/>

   <Rectangle x:Name="Rectangle_TopRight"
         Grid.Row="0" Grid.Column="2"
         Width="{StaticResource Chrome_BorderWidth}" Height="{StaticResource Chrome_BorderWidth}"
         Fill="{StaticResource Brush_ChromeBackground}"
         Cursor="SizeNESW"
         MouseLeftButtonDown="Resize_Begin" MouseLeftButtonUp="Resize_End"
         MouseMove="Resize"/>


   <!-- Middle Row -->
   <Rectangle x:Name="Rectangle_MiddleLeft"
         Grid.Row="1" Grid.Column="0"
         Width="{StaticResource Chrome_BorderWidth}"
         Fill="{StaticResource Brush_ChromeBackground}"
         Cursor="SizeWE"
         MouseLeftButtonDown="Resize_Begin" MouseLeftButtonUp="Resize_End"
         MouseMove="Resize"/>

   <!-- Content -->
   <Label Content="Mouse Down to Move - Double Click to Close"
       Grid.Row="1" Grid.Column="1"
       Background="White" Foreground="Black"
       HorizontalAlignment="Stretch" HorizontalContentAlignment="Center"
       VerticalAlignment="Stretch" VerticalContentAlignment="Center"
       MouseDoubleClick="_Close"
       MouseLeftButtonDown="Move"/>

   <Rectangle x:Name="Rectangle_MiddleRight"
         Grid.Row="1" Grid.Column="2"
         Width="{StaticResource Chrome_BorderWidth}"
         Fill="{StaticResource Brush_ChromeBackground}"
         Cursor="SizeWE"
         MouseLeftButtonDown="Resize_Begin" MouseLeftButtonUp="Resize_End"
         MouseMove="Resize"/>


   <!-- Bottom Row -->
   <Rectangle x:Name="Rectangle_BottomLeft"
         Grid.Row="2" Grid.Column="0"
         Width="{StaticResource Chrome_BorderWidth}" Height="{StaticResource Chrome_BorderWidth}"
         Fill="{StaticResource Brush_ChromeBackground}"
         Cursor="SizeNESW"
         MouseLeftButtonDown="Resize_Begin" MouseLeftButtonUp="Resize_End"
         MouseMove="Resize"/>

   <Rectangle x:Name="Rectangle_BottomMiddle"
         Grid.Row="2" Grid.Column="1"
         Height="{StaticResource Chrome_BorderWidth}"
         Fill="{StaticResource Brush_ChromeBackground}"
         Cursor="SizeNS"
         MouseLeftButtonDown="Resize_Begin" MouseLeftButtonUp="Resize_End"
         MouseMove="Resize"/>

   <Rectangle x:Name="Rectangle_BottomRight"
         Grid.Row="2" Grid.Column="2"
         Width="{StaticResource Chrome_BorderWidth}" Height="{StaticResource Chrome_BorderWidth}"
         Fill="{StaticResource Brush_ChromeBackground}"
         Cursor="SizeNWSE"
         MouseLeftButtonDown="Resize_Begin" MouseLeftButtonUp="Resize_End"
         MouseMove="Resize"/>
  </Grid>

 </Border>

</Window>

Code Behind

Partial Public Class Article_1

  Public Sub New()

    InitializeComponent()

    Initialize_Sizes

  End Sub

  Private isResizing as Boolean = False

  Private Const CURSOR_OFFSET_SMALL As Double = 3
  Private Const CURSOR_OFFSET_LARGE As Double = 5

  Private _x As Double = 0
  Private _Y As Double = 0

  Private Sub Initialize_Sizes

    Dim _MinWidth As Double = Rectangle_MiddleLeft.Width + _
                              Rectangle_BottomRight.Width + _
                              border_Chrome.BorderThickness.Left + _
                              border_Chrome.BorderThickness.Right + 1

    If MinWidth < _MinWidth then _
       MinWidth = _MinWidth

    Dim _MinHeight As Double = Rectangle_TopMiddle.Height + _
                               Rectangle_BottomMiddle.Height + _
                               border_Chrome.BorderThickness.top + _
                               border_Chrome.BorderThickness.Bottom + 1

    If MinHeight < _MinHeight then _
       MinHeight = _MinHeight

  End Sub

  Private sub Resize_Begin(sender as object, _
                           e As MouseEventArgs) 

    isResizing = True

    DirectCast(sender, Rectangle).CaptureMouse

  End Sub

  Private sub Resize_End(sender as object, _
                         e As MouseEventArgs)

    isResizing = False

    DirectCast(sender, Rectangle).ReleaseMouseCapture

  End Sub

  Private Sub Resize(sender As Object, _
                     e As MouseEventArgs)

    If isResizing = False then Exit Sub

      _x = e.GetPosition(me).x
      _y = e.GetPosition(me).Y 

      Select Case DirectCast(sender, Rectangle).Name

        Case "Rectangle_TopLeft" :      Resize_Width_Left
                                        Resize_Height_Top
        Case "Rectangle_TopMiddle" :    Resize_Height_Top
        Case "Rectangle_TopRight" :     Resize_Width_Right
                                        Resize_Height_Top

        Case "Rectangle_MiddleLeft" :   Resize_Width_Left
        Case "Rectangle_MiddleRight" :  Resize_Width_Right


        Case "Rectangle_BottomLeft" :   Resize_Width_Left
                                        Resize_Height_Bottom
        Case "Rectangle_BottomMiddle" : Resize_Height_Bottom
        Case "Rectangle_BottomRight" :  Resize_Width_Right
                                        Resize_Height_Bottom

        Case else : MessageBox.Show("Error in Resize")

      End Select

  End Sub

  Private Sub Resize_Width_Left

    _x -= CURSOR_OFFSET_SMALL

    If Width - _x >= MinWidth Then        
      If Width - _x <= MaxWidth then

        Width -= _x
        Left += _x

      End If
    End If

  End Sub

  Private Sub Resize_Width_Right

    _x += CURSOR_OFFSET_LARGE

    Select Case _x

      Case Is < MinWidth : width = MinWidth
      Case Is > MaxWidth : Width = MaxWidth

      Case Else : Width = _x

    End Select

  End Sub

  Private Sub Resize_Height_Top

    _y -= CURSOR_OFFSET_SMALL

    If Height - _y >= MinHeight Then        
      If Height - _y <= MaxHeight then

        Height -= _y
        Top += _y

      End If
    End If

  End Sub

  Private Sub Resize_Height_Bottom

    _y += CURSOR_OFFSET_SMALL

    Select Case _y

      Case Is < MinHeight : Height = MinHeight
      Case Is > MaxHeight : Height = MaxHeight

      Case Else : Height = _y

    End Select

  End Sub

  Private Sub Move(ByVal sender As Object, _
                    ByVal e As System.Windows.Input.MouseButtonEventArgs)

    Dim curs As Cursor = Cursor

    Cursor = Cursors.SizeAll

    DragMove()

    Cursor = Curs

  End Sub

  Private Sub _Close()

    Close

  End Sub

End Class
Brad
+1  A: 

For a minimalist approach,

  1. Set the Brush_ChromeBackground color to "Transparent". This makes the drag rectangles invisible.
  2. Set the Window's ResizeMode to "NoResize". This hides the grey bevelled edge around the window, leaving the 1px Border_Chrome only.

Also, I translated the code-behind to C#:

public partial class Article_1 : Window
{
    private bool _isResizing = false;
    private const double CURSOR_OFFSET_SMALL = 3;
    private const double CURSOR_OFFSET_LARGE = 5;

    public Article_1()
    {
        InitializeComponent();
        MinWidth = Math.Max(MinWidth, Rectangle_MiddleLeft.Width + Rectangle_MiddleRight.Width + 10);
        MinHeight = Math.Max(MinHeight, Rectangle_TopMiddle.Height + Rectangle_BottomMiddle.Height + 10);
    }

    private void Resize_Begin(object sender, MouseButtonEventArgs e)
    {
        if (sender is Rectangle)
        {
            _isResizing = true;
            ((Rectangle)sender).CaptureMouse();
        }
    }

    private void Resize_End(object sender, MouseButtonEventArgs e)
    {
        if (sender is Rectangle)
        {
            _isResizing = false;
            ((Rectangle)sender).ReleaseMouseCapture();
        }
    }

    private void Resize(object sender, MouseEventArgs e)
    {
        if (_isResizing && (sender is Rectangle))
        {
            double x = e.GetPosition(this).X;
            double y = e.GetPosition(this).Y;

            string mode = ((Rectangle)sender).Name.ToLower();
            if (mode.Contains("left"))
            {
                x -= CURSOR_OFFSET_SMALL;
                if ((Width - x >= MinWidth) && (Width - x <= MaxWidth))
                {
                    Width -= x;
                    Left += x;
                }
            }
            if (mode.Contains("right"))
            {
                Width = Math.Max(MinWidth, Math.Min(MaxWidth, x + CURSOR_OFFSET_LARGE));
            }
            if (mode.Contains("top"))
            {
                y -= CURSOR_OFFSET_SMALL;
                if ((Height - y >= MinHeight) && (Height - y <= MaxHeight))
                {
                    Height -= y;
                    Top += y;
                }
            }
            if (mode.Contains("bottom"))
            {
                Height = Math.Max(MinHeight, Math.Min(MaxHeight, y + CURSOR_OFFSET_SMALL));
            }
        }
    }

    private void Move(object sender, MouseButtonEventArgs e)
    {
        Cursor old = Cursor;
        Cursor = Cursors.SizeAll;
        DragMove();
        Cursor = old;
    }

    private void Close(object sender, MouseButtonEventArgs e)
    {
        Close();
    }
}
Thanks ehartwell!
Brad