Guillermo Mestre
Guillermo Mestre

Reputation: 490

Grid Splitter working on diagonal?

I'm trying to do a Window with a transparent square inside it, and I want to allow the user to re-size it in whatever way s/he wants. This code is working for vertical and horizontal re-size

<Window x:Class="TransparentWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="PloofTAS" Height="355" Width="539" Topmost="True"
        ResizeMode="NoResize" 
        AllowsTransparency="True" 
        Background="Transparent"
        WindowStyle="None" MouseLeftButtonDown="Window_MouseLeftButtonDown">

    <Grid Name="GlobalGrid">
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="8" />
            <RowDefinition Height="*" />
            <RowDefinition Height="8" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="8" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="8" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Rectangle Fill="Gray" Grid.Column="0" Grid.RowSpan="5" />
        <Rectangle Fill="Gray" Grid.Column="4" Grid.RowSpan="5" />
        <Rectangle Fill="Gray" Grid.Column="1" Grid.Row="0" Grid.ColumnSpan="3" />
        <Rectangle Fill="Gray" Grid.Column="1" Grid.Row="4" Grid.ColumnSpan="3" />
        <GridSplitter Grid.Column="2" Grid.Row="1" Height="Auto" HorizontalAlignment="Stretch" />
        <GridSplitter Grid.Column="1" Grid.Row="2" Height="Auto" HorizontalAlignment="Stretch" />
        <GridSplitter Grid.Column="3" Grid.Row="2" Height="Auto" HorizontalAlignment="Stretch" />
        <GridSplitter Grid.Column="2" Grid.Row="3" Height="Auto" HorizontalAlignment="Stretch" />
        <Rectangle Fill="Orange" Grid.Row="1" Grid.Column="1" />
        <Rectangle Fill="Orange" Grid.Row="1" Grid.Column="3" />
        <Rectangle Fill="Orange" Grid.Row="3" Grid.Column="1" />
        <Rectangle Fill="Orange" Grid.Row="3" Grid.Column="3" />
        <Rectangle Fill="Transparent" Stroke="Red" Grid.Column="2" Grid.Row="2"/>
    </Grid>
</Window>

Here is the resulting window

There is no need to compile the code ^_^

I'd like for the orange squares (the corners of the red/transparent square) to be able to work diagonally, or both vertical and horizontal. Is it possible?

Upvotes: 2

Views: 589

Answers (1)

karolL
karolL

Reputation: 66

I don't know elegant solution for this problem as GridSplitter is not possible to set up programmatically.

My solution is just dirty mouse capture and set Column and Row measures according to mouse movement.

Set style and events. Tag property store index of a row and column we gonna to change in code behind.

<Window.Resources>
    <Style x:Key="DiagonalSplitterRectangle" TargetType="{x:Type Rectangle}">
        <Setter Property="Fill" Value="Orange"/>
        <EventSetter Event="MouseDown" Handler="UIElement_OnMouseDown"/>
        <EventSetter Event="MouseMove" Handler="UIElement_OnMouseMove"/>
        <EventSetter Event="MouseUp" Handler="UIElement_OnMouseUp"/>
        <EventSetter Event="LostMouseCapture" Handler="UIElement_OnLostMouseCapture"/>
    </Style>
</Window.Resources>

    <Rectangle Grid.Row="1" Grid.Column="1" Style="{StaticResource DiagonalSplitterRectangle}" Tag="0,0"/>
    <Rectangle Grid.Row="1" Grid.Column="3" Style="{StaticResource DiagonalSplitterRectangle}" Tag="0,4"/>
    <Rectangle Grid.Row="3" Grid.Column="1" Style="{StaticResource DiagonalSplitterRectangle}" Tag="4,0"/>
    <Rectangle Grid.Row="3" Grid.Column="3" Style="{StaticResource DiagonalSplitterRectangle}" Tag="4,4"/>

Simple mouse capture events:

    private bool _isMouseCaptured;

    public MainWindow()
    {
        InitializeComponent();
    }

    private void UIElement_OnMouseDown(object sender, MouseButtonEventArgs e)
    {
        var uiElement = sender as UIElement;
        if (uiElement == null)
            return;

        if (uiElement.CaptureMouse())
            _isMouseCaptured = true;
    }

    private void UIElement_OnMouseMove(object sender, MouseEventArgs e)
    {
        if (!_isMouseCaptured)
            return;

        var clientWindow = Content as FrameworkElement;
        if (clientWindow == null)
            return;

        var rectangle = sender as Rectangle;
        if (rectangle == null)
            return;

        Point position = Mouse.GetPosition(GlobalGrid); ;

        if (position.X < 0 || position.Y < 0 || position.X > clientWindow.ActualWidth || position.Y > clientWindow.ActualHeight)
            return;

        GridUpdate(position, rectangle, clientWindow);
    }

    private void UIElement_OnMouseUp(object sender, MouseButtonEventArgs e)
    {
        if (!_isMouseCaptured)
            return;

        var uiElement = sender as UIElement;
        if (uiElement == null)
            return;

        uiElement.ReleaseMouseCapture();
    }

    private void UIElement_OnLostMouseCapture(object sender, MouseEventArgs e)
    {
        _isMouseCaptured = false;
    }

Resize grid columns and rows according to value stored in rectangle.Tag property. For correct behavior was needed to change opposite column and row measures too.

    private void GridUpdate(Point position, Rectangle rectangle, FrameworkElement clientWindow)
    {
        var gridPosition = new GridPosition(rectangle.Tag.ToString());
        var oppositeGridPosition = GetOppositeGridPosition(gridPosition);

        var rowHeight = GetMeasure(gridPosition.Row, position.Y, clientWindow.ActualHeight);
        var columnWidth = GetMeasure(gridPosition.Column, position.X, clientWindow.ActualWidth);

        var oppositeRowHeight = GlobalGrid.RowDefinitions[oppositeGridPosition.Row].ActualHeight;
        var oppositeColumnWidth = GlobalGrid.ColumnDefinitions[oppositeGridPosition.Column].ActualWidth;

        GlobalGrid.RowDefinitions[gridPosition.Row].Height = new GridLength(rowHeight);
        GlobalGrid.ColumnDefinitions[gridPosition.Column].Width = new GridLength(columnWidth);

        GlobalGrid.RowDefinitions[oppositeGridPosition.Row].Height = new GridLength(oppositeRowHeight);
        GlobalGrid.ColumnDefinitions[oppositeGridPosition.Column].Width = new GridLength(oppositeColumnWidth);
    }

    private GridPosition GetOppositeGridPosition(GridPosition gridPosition)
    {
        var row = (gridPosition.Row == 0) ? 4 : 0;
        var column = (gridPosition.Column == 0) ? 4 : 0;

        return new GridPosition(row, column);
    }

    private double GetMeasure(int gridPosition, double position, double windowMeasure)
    {
        return gridPosition == 0 ? position : windowMeasure - position;
    }

GridPosition is structure that stores column and row index values.

public struct GridPosition
{
    public int Row { get; private set; }
    public int Column { get; private set; }

    public GridPosition(int row, int column)
        : this()
    {
        Row = row;
        Column = column;
    }

    public GridPosition(string gridPostion)
        : this()
    {
        Row = Convert.ToInt32(gridPostion.Split(',')[0]);
        Column = Convert.ToInt32(gridPostion.Split(',')[1]);
    }
}

Upvotes: 1

Related Questions