From 1f185f0701a517e7cd66112f762ee6351c63d0ee Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sat, 21 May 2016 12:31:35 +0200 Subject: [PATCH] Added a SimpleGrid to use in DevTools. As our `Grid` performance is currently terrible :( --- .../Avalonia.Diagnostics.csproj | 3 +- .../Views/ControlDetailsView.cs | 12 +- .../Views/GridRepeater.cs | 30 +--- src/Avalonia.Diagnostics/Views/SimpleGrid.cs | 147 ++++++++++++++++++ 4 files changed, 160 insertions(+), 32 deletions(-) create mode 100644 src/Avalonia.Diagnostics/Views/SimpleGrid.cs diff --git a/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj b/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj index 9b720ffbdb..84312f1927 100644 --- a/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj +++ b/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj @@ -1,4 +1,4 @@ - + @@ -105,6 +105,7 @@ + TreePageView.xaml diff --git a/src/Avalonia.Diagnostics/Views/ControlDetailsView.cs b/src/Avalonia.Diagnostics/Views/ControlDetailsView.cs index 8e24f68b26..7b01e28cf4 100644 --- a/src/Avalonia.Diagnostics/Views/ControlDetailsView.cs +++ b/src/Avalonia.Diagnostics/Views/ControlDetailsView.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Reactive.Linq; using Avalonia.Controls; using Avalonia.Diagnostics.ViewModels; +using Avalonia.Media; using Avalonia.Styling; using ReactiveUI; @@ -35,14 +36,8 @@ namespace Avalonia.Diagnostics.Views Content = new ScrollViewer { - Content = new Grid + Content = new SimpleGrid { - ColumnDefinitions = new ColumnDefinitions - { - new ColumnDefinition(GridLength.Auto), - new ColumnDefinition(GridLength.Auto), - new ColumnDefinition(GridLength.Auto), - }, Styles = new Styles { new Style(x => x.Is()) @@ -66,16 +61,19 @@ namespace Avalonia.Diagnostics.Views yield return new TextBlock { Text = property.Name, + TextWrapping = TextWrapping.NoWrap, [!ToolTip.TipProperty] = property.WhenAnyValue(x => x.Diagnostic), }; yield return new TextBlock { + TextWrapping = TextWrapping.NoWrap, [!TextBlock.TextProperty] = property.WhenAnyValue(v => v.Value).Select(v => v?.ToString()), }; yield return new TextBlock { + TextWrapping = TextWrapping.NoWrap, [!TextBlock.TextProperty] = property.WhenAnyValue(x => x.Priority), }; } diff --git a/src/Avalonia.Diagnostics/Views/GridRepeater.cs b/src/Avalonia.Diagnostics/Views/GridRepeater.cs index 4d05a71e60..ff12fde25b 100644 --- a/src/Avalonia.Diagnostics/Views/GridRepeater.cs +++ b/src/Avalonia.Diagnostics/Views/GridRepeater.cs @@ -11,10 +11,10 @@ namespace Avalonia.Diagnostics.Views internal static class GridRepeater { public static readonly AttachedProperty ItemsProperty = - AvaloniaProperty.RegisterAttached("Items", typeof(GridRepeater)); + AvaloniaProperty.RegisterAttached("Items", typeof(GridRepeater)); public static readonly AttachedProperty>> TemplateProperty = - AvaloniaProperty.RegisterAttached>>("Template", typeof(GridRepeater)); + AvaloniaProperty.RegisterAttached>>("Template", typeof(GridRepeater)); static GridRepeater() { @@ -23,7 +23,7 @@ namespace Avalonia.Diagnostics.Views private static void ItemsChanged(AvaloniaPropertyChangedEventArgs e) { - var grid = (Grid)e.Sender; + var grid = (SimpleGrid)e.Sender; var items = (IEnumerable)e.NewValue; var template = grid.GetValue(TemplateProperty); @@ -32,36 +32,18 @@ namespace Avalonia.Diagnostics.Views if (items != null) { int count = 0; - int cols = grid.ColumnDefinitions.Count; + int cols = 3; foreach (var item in items) { foreach (var control in template(item)) { grid.Children.Add(control); - Grid.SetColumn(control, count % cols); - Grid.SetRow(control, count / cols); + SimpleGrid.SetColumn(control, count % cols); + SimpleGrid.SetRow(control, count / cols); ++count; } } - - int rows = (int)Math.Ceiling((double)count / cols); - int difference = rows - grid.RowDefinitions.Count; - - if (difference > 0) - { - for (int i = 0; i < difference; ++i) - { - grid.RowDefinitions.Add(new RowDefinition(GridLength.Auto)); - } - } - else if (difference < 0) - { - for (int i = 0; i < difference; ++i) - { - grid.RowDefinitions.RemoveAt(grid.RowDefinitions.Count - 1); - } - } } } } diff --git a/src/Avalonia.Diagnostics/Views/SimpleGrid.cs b/src/Avalonia.Diagnostics/Views/SimpleGrid.cs new file mode 100644 index 0000000000..fb5b7821f3 --- /dev/null +++ b/src/Avalonia.Diagnostics/Views/SimpleGrid.cs @@ -0,0 +1,147 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System.Collections.Generic; +using System.Linq; +using Avalonia.Controls; + +namespace Avalonia.Diagnostics.Views +{ + /// + /// A simple grid control that lays out columns with a equal width and rows to their desired + /// size. + /// + /// + /// This is used in the devtools because our performance sucks. + /// + public class SimpleGrid : Panel + { + private List _columnWidths = new List(); + private List _rowHeights = new List(); + private double _totalWidth; + private double _totalHeight; + + /// + /// Defines the Column attached property. + /// + public static readonly AttachedProperty ColumnProperty = + AvaloniaProperty.RegisterAttached("Column"); + + /// + /// Defines the Row attached property. + /// + public static readonly AttachedProperty RowProperty = + AvaloniaProperty.RegisterAttached("Row"); + + /// + /// Gets the value of the Column attached property for a control. + /// + /// The control. + /// The control's column. + public static int GetColumn(IControl control) + { + return control.GetValue(ColumnProperty); + } + + /// + /// Gets the value of the Row attached property for a control. + /// + /// The control. + /// The control's row. + public static int GetRow(IControl control) + { + return control.GetValue(RowProperty); + } + + /// + /// Sets the value of the Column attached property for a control. + /// + /// The control. + /// The column value. + public static void SetColumn(IControl control, int value) + { + control.SetValue(ColumnProperty, value); + } + + + /// + /// Sets the value of the Row attached property for a control. + /// + /// The control. + /// The row value. + public static void SetRow(IControl control, int value) + { + control.SetValue(RowProperty, value); + } + + protected override Size MeasureOverride(Size availableSize) + { + _columnWidths.Clear(); + _rowHeights.Clear(); + _totalWidth = 0; + _totalHeight = 0; + + foreach (var child in Children) + { + var column = GetColumn(child); + var row = GetRow(child); + + child.Measure(availableSize); + + var desired = child.DesiredSize; + UpdateCell(_columnWidths, column, desired.Width, ref _totalWidth); + UpdateCell(_rowHeights, row, desired.Height, ref _totalHeight); + } + + return new Size(_totalWidth, _totalHeight); + } + + protected override Size ArrangeOverride(Size finalSize) + { + var columnWidth = finalSize.Width / _columnWidths.Count; + + foreach (var child in Children) + { + var column = GetColumn(child); + var row = GetRow(child); + var rect = new Rect(column * columnWidth, GetRowTop(row), columnWidth, _rowHeights[row]); + child.Arrange(rect); + } + + return new Size(finalSize.Width, _totalHeight); + } + + private double UpdateCell(IList cells, int cell, double value, ref double total) + { + while (cells.Count < cell + 1) + { + cells.Add(0); + } + + var existing = cells[cell]; + + if (value > existing) + { + cells[cell] = value; + total += value - existing; + return value; + } + else + { + return existing; + } + } + + private double GetRowTop(int row) + { + var result = 0.0; + + for (var i = 0; i < row; ++i) + { + result += _rowHeights[i]; + } + + return result; + } + } +}