diff --git a/src/Avalonia.Controls/GridSplitter.cs b/src/Avalonia.Controls/GridSplitter.cs
index 4b8ef06400..8112b2babd 100644
--- a/src/Avalonia.Controls/GridSplitter.cs
+++ b/src/Avalonia.Controls/GridSplitter.cs
@@ -11,62 +11,32 @@ using Avalonia.VisualTree;
namespace Avalonia.Controls
{
///
- /// Represents the control that redistributes space between columns or rows of a Grid control.
+ /// Represents the control that redistributes space between columns or rows of a Grid control.
///
///
- /// Unlike WPF GridSplitter, Avalonia GridSplitter has only one Behavior, GridResizeBehavior.PreviousAndNext.
+ /// Unlike WPF GridSplitter, Avalonia GridSplitter has only one Behavior, GridResizeBehavior.PreviousAndNext.
///
public class GridSplitter : Thumb
{
- ///
- /// Defines the property.
- ///
- public static readonly StyledProperty OrientationProperty =
- AvaloniaProperty.Register(nameof(Orientation));
-
- protected Grid _grid;
+ private List _definitions;
- private DefinitionBase _prevDefinition;
+ private Grid _grid;
private DefinitionBase _nextDefinition;
- private List _definitions;
-
- ///
- /// Gets or sets the orientation of the GridsSlitter.
- ///
- ///
- /// if null, it's inferred from column/row definition (should be auto).
- ///
- public Orientation Orientation {
- get
- {
- return GetValue(OrientationProperty);
- }
- set
- {
- SetValue(OrientationProperty, value);
- }
- }
+ private Orientation _orientation;
- ///
- /// Initializes static members of the class.
- ///
- static GridSplitter()
- {
- PseudoClass(OrientationProperty, o => o == Avalonia.Controls.Orientation.Vertical, ":vertical");
- PseudoClass(OrientationProperty, o => o == Avalonia.Controls.Orientation.Horizontal, ":horizontal");
- }
+ private DefinitionBase _prevDefinition;
private void GetDeltaConstraints(out double min, out double max)
{
- double prevDefinitionLen = GetActualLength(_prevDefinition);
- double prevDefinitionMin = GetMinLength(_prevDefinition);
- double prevDefinitionMax = GetMaxLength(_prevDefinition);
+ var prevDefinitionLen = GetActualLength(_prevDefinition);
+ var prevDefinitionMin = GetMinLength(_prevDefinition);
+ var prevDefinitionMax = GetMaxLength(_prevDefinition);
- double nextDefinitionLen = GetActualLength(_nextDefinition);
- double nextDefinitionMin = GetMinLength(_nextDefinition);
- double nextDefinitionMax = GetMaxLength(_nextDefinition);
+ var nextDefinitionLen = GetActualLength(_nextDefinition);
+ var nextDefinitionMin = GetMinLength(_nextDefinition);
+ var nextDefinitionMax = GetMaxLength(_nextDefinition);
// Determine the minimum and maximum the columns can be resized
min = -Math.Min(prevDefinitionLen - prevDefinitionMin, nextDefinitionMax - nextDefinitionLen);
max = Math.Min(prevDefinitionMax - prevDefinitionLen, nextDefinitionLen - nextDefinitionMin);
@@ -74,7 +44,7 @@ namespace Avalonia.Controls
protected override void OnDragDelta(VectorEventArgs e)
{
- var delta = Orientation == Orientation.Vertical ? e.Vector.X : e.Vector.Y;
+ var delta = _orientation == Orientation.Vertical ? e.Vector.X : e.Vector.Y;
double max;
double min;
GetDeltaConstraints(out min, out max);
@@ -98,26 +68,32 @@ namespace Avalonia.Controls
private double GetActualLength(DefinitionBase definition)
{
+ if (definition == null)
+ return 0;
var columnDefinition = definition as ColumnDefinition;
- return columnDefinition?.ActualWidth ?? ((RowDefinition)definition).ActualHeight;
+ return columnDefinition?.ActualWidth ?? ((RowDefinition) definition).ActualHeight;
}
private double GetMinLength(DefinitionBase definition)
{
+ if (definition == null)
+ return 0;
var columnDefinition = definition as ColumnDefinition;
- return columnDefinition?.MinWidth ?? ((RowDefinition)definition).MinHeight;
+ return columnDefinition?.MinWidth ?? ((RowDefinition) definition).MinHeight;
}
private double GetMaxLength(DefinitionBase definition)
{
+ if (definition == null)
+ return 0;
var columnDefinition = definition as ColumnDefinition;
- return columnDefinition?.MaxWidth ?? ((RowDefinition)definition).MaxHeight;
+ return columnDefinition?.MaxWidth ?? ((RowDefinition) definition).MaxHeight;
}
private bool IsStar(DefinitionBase definition)
{
var columnDefinition = definition as ColumnDefinition;
- return columnDefinition?.Width.IsStar ?? ((RowDefinition)definition).Height.IsStar;
+ return columnDefinition?.Width.IsStar ?? ((RowDefinition) definition).Height.IsStar;
}
private void SetLengthInStars(DefinitionBase definition, double value)
@@ -129,7 +105,7 @@ namespace Avalonia.Controls
}
else
{
- ((RowDefinition)definition).Height = new GridLength(value, GridUnitType.Star);
+ ((RowDefinition) definition).Height = new GridLength(value, GridUnitType.Star);
}
}
@@ -137,24 +113,58 @@ namespace Avalonia.Controls
{
base.OnAttachedToVisualTree(e);
_grid = this.GetVisualParent();
-
- if (Orientation == Orientation.Vertical)
+
+ _orientation = DetectOrientation();
+
+ int defenitionIndex; //row or col
+ if (_orientation == Orientation.Vertical)
{
Cursor = new Cursor(StandardCursorType.SizeWestEast);
- var col = GetValue(Grid.ColumnProperty);
_definitions = _grid.ColumnDefinitions.Cast().ToList();
- _prevDefinition = _definitions[col - 1];
- _nextDefinition = _definitions[col + 1];
+ defenitionIndex = GetValue(Grid.ColumnProperty);
+ PseudoClasses.Add(":vertical");
}
else
{
Cursor = new Cursor(StandardCursorType.SizeNorthSouth);
- var row = GetValue(Grid.RowProperty);
+ defenitionIndex = GetValue(Grid.RowProperty);
_definitions = _grid.RowDefinitions.Cast().ToList();
- _prevDefinition = _definitions[row - 1];
- _nextDefinition = _definitions[row + 1];
+ PseudoClasses.Add(":horizontal");
}
+
+ if (defenitionIndex > 0)
+ _prevDefinition = _definitions[defenitionIndex - 1];
+
+ if (defenitionIndex < _definitions.Count - 1)
+ _nextDefinition = _definitions[defenitionIndex + 1];
}
- }
-}
+ private Orientation DetectOrientation()
+ {
+ if (!_grid.ColumnDefinitions.Any())
+ return Orientation.Horizontal;
+ if (!_grid.RowDefinitions.Any())
+ return Orientation.Vertical;
+
+ var col = GetValue(Grid.ColumnProperty);
+ var row = GetValue(Grid.RowProperty);
+ var width = _grid.ColumnDefinitions[col].Width;
+ var height = _grid.RowDefinitions[row].Height;
+ if (width.IsAuto && !height.IsAuto)
+ {
+ return Orientation.Vertical;
+ }
+ if (!width.IsAuto && height.IsAuto)
+ {
+ return Orientation.Horizontal;
+ }
+ if (_grid.Children.OfType() // Decision based on other controls in the same column
+ .Where(c => Grid.GetColumn(c) == col)
+ .Any(c => c.GetType() != typeof (GridSplitter)))
+ {
+ return Orientation.Horizontal;
+ }
+ return Orientation.Vertical;
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/Avalonia.Controls.UnitTests/GridSplitterTests.cs b/tests/Avalonia.Controls.UnitTests/GridSplitterTests.cs
index 90b9913141..5d622a5fc1 100644
--- a/tests/Avalonia.Controls.UnitTests/GridSplitterTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/GridSplitterTests.cs
@@ -1,116 +1,202 @@
-using Moq;
-
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Platform;
using Avalonia.UnitTests;
+
+using Moq;
+
using Xunit;
namespace Avalonia.Controls.UnitTests
{
public class GridSplitterTests
{
- [Fact]
- public void Vertical_Stays_Within_Constraints()
+ public GridSplitterTests()
{
var cursorFactoryImpl = new Mock();
AvaloniaLocator.CurrentMutable.Bind().ToConstant(cursorFactoryImpl.Object);
+ }
- var control1 = new Border { [Grid.ColumnProperty] = 0 };
- var splitter = new GridSplitter
- {
- Orientation = Orientation.Vertical,
- [Grid.ColumnProperty] = 1,
- };
- var control2 = new Border { [Grid.ColumnProperty] = 2 };
+ [Fact]
+ public void Detects_Horizontal_Orientation()
+ {
+ var grid = new Grid()
+ {
+ RowDefinitions = new RowDefinitions("*,Auto,*"),
+ ColumnDefinitions = new ColumnDefinitions("*,*"),
+ Children = new Controls()
+ {
+ new Border { [Grid.RowProperty] = 0 },
+ new GridSplitter { [Grid.RowProperty] = 1, Name = "splitter" },
+ new Border { [Grid.RowProperty] = 2 }
+ }
+ };
- var columnDefinitions = new ColumnDefinitions()
- {
- new ColumnDefinition(1, GridUnitType.Star) {MinWidth = 10, MaxWidth = 190},
- new ColumnDefinition(GridLength.Auto),
- new ColumnDefinition(1, GridUnitType.Star) {MinWidth = 80, MaxWidth = 120},
- };
+ var root = new TestRoot { Child = grid };
+ root.Measure(new Size(100, 300));
+ root.Arrange(new Rect(0, 0, 100, 300));
+ Assert.Contains(grid.FindControl("splitter").Classes, ":horizontal".Equals);
+ }
+ [Fact]
+ public void Detects_Vertical_Orientation()
+ {
var grid = new Grid()
- {
- ColumnDefinitions = columnDefinitions,
- Children = new Controls()
- {
- control1, splitter, control2
- }
- };
+ {
+ ColumnDefinitions = new ColumnDefinitions("*,Auto,*"),
+ RowDefinitions = new RowDefinitions("*,*"),
+ Children = new Controls()
+ {
+ new Border { [Grid.ColumnProperty] = 0 },
+ new GridSplitter { [Grid.ColumnProperty] = 1, Name = "splitter" },
+ new Border { [Grid.ColumnProperty] = 2 },
+ }
+ };
var root = new TestRoot { Child = grid };
- Assert.Equal(splitter.Orientation, Orientation.Vertical);
+ root.Measure(new Size(100, 300));
+ root.Arrange(new Rect(0, 0, 100, 300));
+ Assert.Contains(grid.FindControl("splitter").Classes, ":vertical".Equals);
+ }
- root.Measure(new Size(200, 100));
- root.Arrange(new Rect(0, 0, 200, 100));
+ [Fact]
+ public void Detects_With_Both_Auto()
+ {
+ var grid = new Grid()
+ {
+ ColumnDefinitions = new ColumnDefinitions("Auto,Auto,Auto"),
+ RowDefinitions = new RowDefinitions("Auto,Auto"),
+ Children = new Controls()
+ {
+ new Border { [Grid.ColumnProperty] = 0 },
+ new GridSplitter { [Grid.ColumnProperty] = 1, Name = "splitter" },
+ new Border { [Grid.ColumnProperty] = 2 },
+ }
+ };
- splitter.RaiseEvent(new VectorEventArgs
- {
- RoutedEvent = Thumb.DragDeltaEvent,
- Vector = new Vector(-100,0)
- });
- Assert.Equal(columnDefinitions[0].Width, new GridLength(80,GridUnitType.Star));
- Assert.Equal(columnDefinitions[2].Width, new GridLength(120,GridUnitType.Star));
- splitter.RaiseEvent(new VectorEventArgs
- {
- RoutedEvent = Thumb.DragDeltaEvent,
- Vector = new Vector(100, 0)
- });
- Assert.Equal(columnDefinitions[0].Width, new GridLength(120, GridUnitType.Star));
- Assert.Equal(columnDefinitions[2].Width, new GridLength(80, GridUnitType.Star));
+ var root = new TestRoot { Child = grid };
+ root.Measure(new Size(100, 300));
+ root.Arrange(new Rect(0, 0, 100, 300));
+ Assert.Contains(grid.FindControl("splitter").Classes, ":vertical".Equals);
}
[Fact]
public void Horizontal_Stays_Within_Constraints()
{
- var cursorFactoryImpl = new Mock();
- AvaloniaLocator.CurrentMutable.Bind().ToConstant(cursorFactoryImpl.Object);
-
var control1 = new Border { [Grid.RowProperty] = 0 };
var splitter = new GridSplitter
- {
- Orientation = Orientation.Horizontal,
- [Grid.RowProperty] = 1,
- };
+ {
+ [Grid.RowProperty] = 1,
+ };
var control2 = new Border { [Grid.RowProperty] = 2 };
var rowDefinitions = new RowDefinitions()
- {
- new RowDefinition(1, GridUnitType.Star) {MinHeight = 70, MaxHeight = 110},
- new RowDefinition(GridLength.Auto),
- new RowDefinition(1, GridUnitType.Star) { MinHeight = 10, MaxHeight = 140},
- };
+ {
+ new RowDefinition(1, GridUnitType.Star) { MinHeight = 70, MaxHeight = 110 },
+ new RowDefinition(GridLength.Auto),
+ new RowDefinition(1, GridUnitType.Star) { MinHeight = 10, MaxHeight = 140 },
+ };
var grid = new Grid()
- {
- RowDefinitions = rowDefinitions,
- Children = new Controls()
- {
- control1, splitter, control2
- }
- };
+ {
+ RowDefinitions = rowDefinitions,
+ Children = new Controls()
+ {
+ control1, splitter, control2
+ }
+ };
var root = new TestRoot { Child = grid };
- Assert.Equal(splitter.Orientation, Orientation.Horizontal);
root.Measure(new Size(100, 200));
root.Arrange(new Rect(0, 0, 100, 200));
splitter.RaiseEvent(new VectorEventArgs
- {
- RoutedEvent = Thumb.DragDeltaEvent,
- Vector = new Vector(0, -100)
- });
+ {
+ RoutedEvent = Thumb.DragDeltaEvent,
+ Vector = new Vector(0, -100)
+ });
Assert.Equal(rowDefinitions[0].Height, new GridLength(70, GridUnitType.Star));
Assert.Equal(rowDefinitions[2].Height, new GridLength(130, GridUnitType.Star));
splitter.RaiseEvent(new VectorEventArgs
- {
- RoutedEvent = Thumb.DragDeltaEvent,
- Vector = new Vector(0, 100)
- });
+ {
+ RoutedEvent = Thumb.DragDeltaEvent,
+ Vector = new Vector(0, 100)
+ });
Assert.Equal(rowDefinitions[0].Height, new GridLength(110, GridUnitType.Star));
Assert.Equal(rowDefinitions[2].Height, new GridLength(90, GridUnitType.Star));
}
+
+ [Fact]
+ public void In_First_Position_Doesnt_Throw_Exception()
+ {
+ var grid = new Grid()
+ {
+ ColumnDefinitions = new ColumnDefinitions("Auto,*,*"),
+ RowDefinitions = new RowDefinitions("*,*"),
+ Children = new Controls()
+ {
+ new GridSplitter { [Grid.ColumnProperty] = 0, Name = "splitter" },
+ new Border { [Grid.ColumnProperty] = 1 },
+ new Border { [Grid.ColumnProperty] = 2 },
+ }
+ };
+
+ var root = new TestRoot { Child = grid };
+ root.Measure(new Size(100, 300));
+ root.Arrange(new Rect(0, 0, 100, 300));
+ var splitter = grid.FindControl("splitter");
+ splitter.RaiseEvent(new VectorEventArgs
+ {
+ RoutedEvent = Thumb.DragDeltaEvent,
+ Vector = new Vector(100, 1000)
+ });
+ }
+
+ [Fact]
+ public void Vertical_Stays_Within_Constraints()
+ {
+ var control1 = new Border { [Grid.ColumnProperty] = 0 };
+ var splitter = new GridSplitter
+ {
+ [Grid.ColumnProperty] = 1,
+ };
+ var control2 = new Border { [Grid.ColumnProperty] = 2 };
+
+ var columnDefinitions = new ColumnDefinitions()
+ {
+ new ColumnDefinition(1, GridUnitType.Star) { MinWidth = 10, MaxWidth = 190 },
+ new ColumnDefinition(GridLength.Auto),
+ new ColumnDefinition(1, GridUnitType.Star) { MinWidth = 80, MaxWidth = 120 },
+ };
+
+ var grid = new Grid()
+ {
+ ColumnDefinitions = columnDefinitions,
+ Children = new Controls()
+ {
+ control1, splitter, control2
+ }
+ };
+
+ var root = new TestRoot { Child = grid };
+
+ root.Measure(new Size(200, 100));
+ root.Arrange(new Rect(0, 0, 200, 100));
+
+ splitter.RaiseEvent(new VectorEventArgs
+ {
+ RoutedEvent = Thumb.DragDeltaEvent,
+ Vector = new Vector(-100, 0)
+ });
+ Assert.Equal(columnDefinitions[0].Width, new GridLength(80, GridUnitType.Star));
+ Assert.Equal(columnDefinitions[2].Width, new GridLength(120, GridUnitType.Star));
+ splitter.RaiseEvent(new VectorEventArgs
+ {
+ RoutedEvent = Thumb.DragDeltaEvent,
+ Vector = new Vector(100, 0)
+ });
+ Assert.Equal(columnDefinitions[0].Width, new GridLength(120, GridUnitType.Star));
+ Assert.Equal(columnDefinitions[2].Width, new GridLength(80, GridUnitType.Star));
+ }
}
}
\ No newline at end of file