summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Core/Grid.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Xamarin.Forms.Core/Grid.cs')
-rw-r--r--Xamarin.Forms.Core/Grid.cs359
1 files changed, 359 insertions, 0 deletions
diff --git a/Xamarin.Forms.Core/Grid.cs b/Xamarin.Forms.Core/Grid.cs
new file mode 100644
index 00000000..442146c2
--- /dev/null
+++ b/Xamarin.Forms.Core/Grid.cs
@@ -0,0 +1,359 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Linq;
+
+namespace Xamarin.Forms
+{
+ public partial class Grid : Layout<View>
+ {
+ public static readonly BindableProperty RowProperty = BindableProperty.CreateAttached("Row", typeof(int), typeof(Grid), default(int), validateValue: (bindable, value) => (int)value >= 0);
+
+ public static readonly BindableProperty RowSpanProperty = BindableProperty.CreateAttached("RowSpan", typeof(int), typeof(Grid), 1, validateValue: (bindable, value) => (int)value >= 1);
+
+ public static readonly BindableProperty ColumnProperty = BindableProperty.CreateAttached("Column", typeof(int), typeof(Grid), default(int), validateValue: (bindable, value) => (int)value >= 0);
+
+ public static readonly BindableProperty ColumnSpanProperty = BindableProperty.CreateAttached("ColumnSpan", typeof(int), typeof(Grid), 1, validateValue: (bindable, value) => (int)value >= 1);
+
+ public static readonly BindableProperty RowSpacingProperty = BindableProperty.Create("RowSpacing", typeof(double), typeof(Grid), 6d,
+ propertyChanged: (bindable, oldValue, newValue) => ((Grid)bindable).InvalidateMeasure(InvalidationTrigger.MeasureChanged));
+
+ public static readonly BindableProperty ColumnSpacingProperty = BindableProperty.Create("ColumnSpacing", typeof(double), typeof(Grid), 6d,
+ propertyChanged: (bindable, oldValue, newValue) => ((Grid)bindable).InvalidateMeasure(InvalidationTrigger.MeasureChanged));
+
+ public static readonly BindableProperty ColumnDefinitionsProperty = BindableProperty.Create("ColumnDefinitions", typeof(ColumnDefinitionCollection), typeof(Grid), null,
+ validateValue: (bindable, value) => value != null, propertyChanged: (bindable, oldvalue, newvalue) =>
+ {
+ if (oldvalue != null)
+ ((ColumnDefinitionCollection)oldvalue).ItemSizeChanged -= ((Grid)bindable).OnDefinitionChanged;
+ if (newvalue != null)
+ ((ColumnDefinitionCollection)newvalue).ItemSizeChanged += ((Grid)bindable).OnDefinitionChanged;
+ }, defaultValueCreator: bindable =>
+ {
+ var colDef = new ColumnDefinitionCollection();
+ colDef.ItemSizeChanged += ((Grid)bindable).OnDefinitionChanged;
+ return colDef;
+ });
+
+ public static readonly BindableProperty RowDefinitionsProperty = BindableProperty.Create("RowDefinitions", typeof(RowDefinitionCollection), typeof(Grid), null,
+ validateValue: (bindable, value) => value != null, propertyChanged: (bindable, oldvalue, newvalue) =>
+ {
+ if (oldvalue != null)
+ ((RowDefinitionCollection)oldvalue).ItemSizeChanged -= ((Grid)bindable).OnDefinitionChanged;
+ if (newvalue != null)
+ ((RowDefinitionCollection)newvalue).ItemSizeChanged += ((Grid)bindable).OnDefinitionChanged;
+ }, defaultValueCreator: bindable =>
+ {
+ var rowDef = new RowDefinitionCollection();
+ rowDef.ItemSizeChanged += ((Grid)bindable).OnDefinitionChanged;
+ return rowDef;
+ });
+
+ readonly GridElementCollection _children;
+
+ public Grid()
+ {
+ _children = new GridElementCollection(InternalChildren, this) { Parent = this };
+ }
+
+ public new IGridList<View> Children
+ {
+ get { return _children; }
+ }
+
+ public ColumnDefinitionCollection ColumnDefinitions
+ {
+ get { return (ColumnDefinitionCollection)GetValue(ColumnDefinitionsProperty); }
+ set { SetValue(ColumnDefinitionsProperty, value); }
+ }
+
+ public double ColumnSpacing
+ {
+ get { return (double)GetValue(ColumnSpacingProperty); }
+ set { SetValue(ColumnSpacingProperty, value); }
+ }
+
+ public RowDefinitionCollection RowDefinitions
+ {
+ get { return (RowDefinitionCollection)GetValue(RowDefinitionsProperty); }
+ set { SetValue(RowDefinitionsProperty, value); }
+ }
+
+ public double RowSpacing
+ {
+ get { return (double)GetValue(RowSpacingProperty); }
+ set { SetValue(RowSpacingProperty, value); }
+ }
+
+ public static int GetColumn(BindableObject bindable)
+ {
+ return (int)bindable.GetValue(ColumnProperty);
+ }
+
+ public static int GetColumnSpan(BindableObject bindable)
+ {
+ return (int)bindable.GetValue(ColumnSpanProperty);
+ }
+
+ public static int GetRow(BindableObject bindable)
+ {
+ return (int)bindable.GetValue(RowProperty);
+ }
+
+ public static int GetRowSpan(BindableObject bindable)
+ {
+ return (int)bindable.GetValue(RowSpanProperty);
+ }
+
+ public static void SetColumn(BindableObject bindable, int value)
+ {
+ bindable.SetValue(ColumnProperty, value);
+ }
+
+ public static void SetColumnSpan(BindableObject bindable, int value)
+ {
+ bindable.SetValue(ColumnSpanProperty, value);
+ }
+
+ public static void SetRow(BindableObject bindable, int value)
+ {
+ bindable.SetValue(RowProperty, value);
+ }
+
+ public static void SetRowSpan(BindableObject bindable, int value)
+ {
+ bindable.SetValue(RowSpanProperty, value);
+ }
+
+ protected override void OnAdded(View view)
+ {
+ base.OnAdded(view);
+ view.PropertyChanged += OnItemPropertyChanged;
+ }
+
+ protected override void OnBindingContextChanged()
+ {
+ UpdateInheritedBindingContexts();
+ base.OnBindingContextChanged();
+ }
+
+ protected override void OnRemoved(View view)
+ {
+ base.OnRemoved(view);
+ view.PropertyChanged -= OnItemPropertyChanged;
+ }
+
+ internal override void ComputeConstraintForView(View view)
+ {
+ LayoutOptions vOptions = view.VerticalOptions;
+ LayoutOptions hOptions = view.HorizontalOptions;
+
+ var result = LayoutConstraint.None;
+
+ if (_rows == null || _columns == null)
+ EnsureRowsColumnsInitialized();
+
+ if (vOptions.Alignment == LayoutAlignment.Fill)
+ {
+ int row = GetRow(view);
+ int rowSpan = GetRowSpan(view);
+ List<RowDefinition> rowDefinitions = _rows;
+
+ var canFix = true;
+
+ for (int i = row; i < row + rowSpan && i < rowDefinitions.Count; i++)
+ {
+ GridLength height = rowDefinitions[i].Height;
+ if (height.IsAuto)
+ {
+ canFix = false;
+ break;
+ }
+ if ((Constraint & LayoutConstraint.VerticallyFixed) == 0 && height.IsStar)
+ {
+ canFix = false;
+ break;
+ }
+ }
+
+ if (canFix)
+ result |= LayoutConstraint.VerticallyFixed;
+ }
+
+ if (hOptions.Alignment == LayoutAlignment.Fill)
+ {
+ int col = GetColumn(view);
+ int colSpan = GetColumnSpan(view);
+ List<ColumnDefinition> columnDefinitions = _columns;
+
+ var canFix = true;
+
+ for (int i = col; i < col + colSpan && i < columnDefinitions.Count; i++)
+ {
+ GridLength width = columnDefinitions[i].Width;
+ if (width.IsAuto)
+ {
+ canFix = false;
+ break;
+ }
+ if ((Constraint & LayoutConstraint.HorizontallyFixed) == 0 && width.IsStar)
+ {
+ canFix = false;
+ break;
+ }
+ }
+
+ if (canFix)
+ result |= LayoutConstraint.HorizontallyFixed;
+ }
+
+ view.ComputedConstraint = result;
+ }
+
+ internal override void InvalidateMeasure(InvalidationTrigger trigger)
+ {
+ base.InvalidateMeasure(trigger);
+ _columns = null;
+ _rows = null;
+ }
+
+ void OnDefinitionChanged(object sender, EventArgs args)
+ {
+ ComputeConstrainsForChildren();
+ UpdateInheritedBindingContexts();
+ InvalidateLayout();
+ }
+
+ void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == ColumnProperty.PropertyName || e.PropertyName == ColumnSpanProperty.PropertyName || e.PropertyName == RowProperty.PropertyName ||
+ e.PropertyName == RowSpanProperty.PropertyName)
+ {
+ var child = sender as View;
+ if (child != null)
+ {
+ ComputeConstraintForView(child);
+ }
+
+ InvalidateLayout();
+ }
+ }
+
+ void UpdateInheritedBindingContexts()
+ {
+ object bindingContext = BindingContext;
+ RowDefinitionCollection rowDefs = RowDefinitions;
+ if (rowDefs != null)
+ {
+ for (var i = 0; i < rowDefs.Count; i++)
+ {
+ RowDefinition rowdef = rowDefs[i];
+ SetInheritedBindingContext(rowdef, bindingContext);
+ }
+ }
+
+ ColumnDefinitionCollection colDefs = ColumnDefinitions;
+ if (colDefs != null)
+ {
+ for (var i = 0; i < colDefs.Count; i++)
+ {
+ ColumnDefinition coldef = colDefs[i];
+ SetInheritedBindingContext(coldef, bindingContext);
+ }
+ }
+ }
+
+ public interface IGridList<T> : IList<T> where T : View
+ {
+ void Add(View view, int left, int top);
+ void Add(View view, int left, int right, int top, int bottom);
+ void AddHorizontal(IEnumerable<View> views);
+ void AddHorizontal(View view);
+ void AddVertical(IEnumerable<View> views);
+ void AddVertical(View view);
+ }
+
+ class GridElementCollection : ElementCollection<View>, IGridList<View>
+ {
+ public GridElementCollection(ObservableCollection<Element> inner, Grid parent) : base(inner)
+ {
+ Parent = parent;
+ }
+
+ internal Grid Parent { get; set; }
+
+ public void Add(View view, int left, int top)
+ {
+ if (left < 0)
+ throw new ArgumentOutOfRangeException("left");
+ if (top < 0)
+ throw new ArgumentOutOfRangeException("top");
+ Add(view, left, left + 1, top, top + 1);
+ }
+
+ public void Add(View view, int left, int right, int top, int bottom)
+ {
+ if (left < 0)
+ throw new ArgumentOutOfRangeException("left");
+ if (top < 0)
+ throw new ArgumentOutOfRangeException("top");
+ if (left >= right)
+ throw new ArgumentOutOfRangeException("right");
+ if (top >= bottom)
+ throw new ArgumentOutOfRangeException("bottom");
+ if (view == null)
+ throw new ArgumentNullException("view");
+
+ SetRow(view, top);
+ SetRowSpan(view, bottom - top);
+ SetColumn(view, left);
+ SetColumnSpan(view, right - left);
+
+ Add(view);
+ }
+
+ public void AddHorizontal(IEnumerable<View> views)
+ {
+ if (views == null)
+ throw new ArgumentNullException("views");
+
+ views.ForEach(AddHorizontal);
+ }
+
+ public void AddHorizontal(View view)
+ {
+ if (view == null)
+ throw new ArgumentNullException("view");
+
+ int lastRow = this.Any() ? this.Max(w => GetRow(w) + GetRowSpan(w) - 1) : -1;
+ lastRow = Math.Max(lastRow, Parent.RowDefinitions.Count - 1);
+ int lastCol = this.Any() ? this.Max(w => GetColumn(w) + GetColumnSpan(w) - 1) : -1;
+ lastCol = Math.Max(lastCol, Parent.ColumnDefinitions.Count - 1);
+
+ Add(view, lastCol + 1, lastCol + 2, 0, Math.Max(1, lastRow));
+ }
+
+ public void AddVertical(IEnumerable<View> views)
+ {
+ if (views == null)
+ throw new ArgumentNullException("views");
+
+ views.ForEach(AddVertical);
+ }
+
+ public void AddVertical(View view)
+ {
+ if (view == null)
+ throw new ArgumentNullException("view");
+
+ int lastRow = this.Any() ? this.Max(w => GetRow(w) + GetRowSpan(w) - 1) : -1;
+ lastRow = Math.Max(lastRow, Parent.RowDefinitions.Count - 1);
+ int lastCol = this.Any() ? this.Max(w => GetColumn(w) + GetColumnSpan(w) - 1) : -1;
+ lastCol = Math.Max(lastCol, Parent.ColumnDefinitions.Count - 1);
+
+ Add(view, 0, Math.Max(1, lastCol), lastRow + 1, lastRow + 2);
+ }
+ }
+ }
+} \ No newline at end of file