From 0c55a8fe357010c7fcfc008831397e310d6297a8 Mon Sep 17 00:00:00 2001 From: Eli Arbel Date: Thu, 24 Aug 2017 20:33:02 +0300 Subject: [PATCH 1/4] Defer changes to dirty visuals --- .../Rendering/DirtyVisuals.cs | 91 ++++++++++++++++--- 1 file changed, 76 insertions(+), 15 deletions(-) diff --git a/src/Avalonia.Visuals/Rendering/DirtyVisuals.cs b/src/Avalonia.Visuals/Rendering/DirtyVisuals.cs index f14f5bc912..895b1679b0 100644 --- a/src/Avalonia.Visuals/Rendering/DirtyVisuals.cs +++ b/src/Avalonia.Visuals/Rendering/DirtyVisuals.cs @@ -17,6 +17,8 @@ namespace Avalonia.Rendering { private SortedDictionary> _inner = new SortedDictionary>(); private Dictionary _index = new Dictionary(); + private List<(DeferredChange change, IVisual visual)> _deferredChanges = new List<(DeferredChange, IVisual)>(); + private bool _deferring; /// /// Gets the number of dirty visuals. @@ -29,10 +31,15 @@ namespace Avalonia.Rendering /// The dirty visual. public void Add(IVisual visual) { + if (_deferring) + { + _deferredChanges.Add((DeferredChange.Add, visual)); + return; + } + var distance = visual.CalculateDistanceFromAncestor(visual.VisualRoot); - int existingDistance; - if (_index.TryGetValue(visual, out existingDistance)) + if (_index.TryGetValue(visual, out var existingDistance)) { if (distance == existingDistance) { @@ -43,9 +50,7 @@ namespace Avalonia.Rendering _index.Remove(visual); } - List list; - - if (!_inner.TryGetValue(distance, out list)) + if (!_inner.TryGetValue(distance, out var list)) { list = new List(); _inner.Add(distance, list); @@ -60,6 +65,12 @@ namespace Avalonia.Rendering /// public void Clear() { + if (_deferring) + { + _deferredChanges.Add((DeferredChange.Clear, null)); + return; + } + _inner.Clear(); _index.Clear(); } @@ -68,19 +79,19 @@ namespace Avalonia.Rendering /// Removes a visual from the dirty list. /// /// The visual. - /// True if the visual was present in the list; otherwise false. - public bool Remove(IVisual visual) + public void Remove(IVisual visual) { - int distance; + if (_deferring) + { + _deferredChanges.Add((DeferredChange.Remove, visual)); + return; + } - if (_index.TryGetValue(visual, out distance)) + if (_index.TryGetValue(visual, out var distance)) { _inner[distance].Remove(visual); _index.Remove(visual); - return true; } - - return false; } /// @@ -89,19 +100,69 @@ namespace Avalonia.Rendering /// A collection of visuals. public IEnumerator GetEnumerator() { - foreach (var i in _inner) + using (DeferChanges()) { - foreach (var j in i.Value) + foreach (var i in _inner) { - yield return j; + foreach (var j in i.Value) + { + yield return j; + } } } } + private DeferDisposer DeferChanges() + { + _deferring = true; + return new DeferDisposer(this); + } + + private void EndDefer() + { + if (!_deferring) return; + + _deferring = false; + + foreach (var change in _deferredChanges) + { + switch (change.change) + { + case DeferredChange.Add: + Add(change.visual); + break; + case DeferredChange.Remove: + Remove(change.visual); + break; + case DeferredChange.Clear: + Clear(); + break; + } + } + + _deferredChanges.Clear(); + } + /// /// Gets the dirty visuals, in ascending order of distance to their root. /// /// A collection of visuals. IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + private struct DeferDisposer : IDisposable + { + private DirtyVisuals _parent; + + internal DeferDisposer(DirtyVisuals parent) => _parent = parent; + + public void Dispose() => _parent?.EndDefer(); + } + + private enum DeferredChange + { + Add, + Remove, + Clear + } } } From f6ed69be28c162936a4152066bb3fea1436edffa Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sat, 26 Aug 2017 20:08:38 +0200 Subject: [PATCH 2/4] StyleResource -> DynamicResource --- samples/ControlCatalog/Pages/BorderPage.xaml | 10 ++++----- samples/ControlCatalog/Pages/ButtonPage.xaml | 8 +++---- .../ControlCatalog/Pages/ContextMenuPage.xaml | 2 +- .../ControlCatalog/Pages/DropDownPage.xaml | 2 +- .../Pages/LayoutTransformControlPage.xaml | 8 +++---- samples/ControlCatalog/Pages/ToolTipPage.xaml | 2 +- samples/ControlCatalog/SideBar.xaml | 4 ++-- samples/RenderTest/Pages/ClippingPage.xaml | 2 +- samples/RenderTest/Pages/DrawingPage.xaml | 8 +++---- samples/RenderTest/SideBar.xaml | 4 ++-- src/Avalonia.Themes.Default/Button.xaml | 14 ++++++------ src/Avalonia.Themes.Default/CheckBox.xaml | 10 ++++----- src/Avalonia.Themes.Default/DropDown.xaml | 10 ++++----- .../EmbeddableControlRoot.xaml | 4 ++-- src/Avalonia.Themes.Default/GridSplitter.xaml | 8 +++---- src/Avalonia.Themes.Default/ListBox.xaml | 6 ++--- src/Avalonia.Themes.Default/MenuItem.xaml | 18 +++++++-------- src/Avalonia.Themes.Default/PopupRoot.xaml | 2 +- src/Avalonia.Themes.Default/ProgressBar.xaml | 4 ++-- src/Avalonia.Themes.Default/RadioButton.xaml | 10 ++++----- src/Avalonia.Themes.Default/ScrollBar.xaml | 4 ++-- src/Avalonia.Themes.Default/Separator.xaml | 4 ++-- src/Avalonia.Themes.Default/Slider.xaml | 6 ++--- src/Avalonia.Themes.Default/TabStripItem.xaml | 6 ++--- src/Avalonia.Themes.Default/TextBox.xaml | 22 +++++++++---------- src/Avalonia.Themes.Default/ToggleButton.xaml | 18 +++++++-------- src/Avalonia.Themes.Default/ToolTip.xaml | 6 ++--- src/Avalonia.Themes.Default/TreeView.xaml | 4 ++-- src/Avalonia.Themes.Default/TreeViewItem.xaml | 2 +- src/Avalonia.Themes.Default/Window.xaml | 4 ++-- .../Xaml/Style2.xaml | 6 ++--- 31 files changed, 109 insertions(+), 109 deletions(-) diff --git a/samples/ControlCatalog/Pages/BorderPage.xaml b/samples/ControlCatalog/Pages/BorderPage.xaml index 9842745413..a81bd13ddd 100644 --- a/samples/ControlCatalog/Pages/BorderPage.xaml +++ b/samples/ControlCatalog/Pages/BorderPage.xaml @@ -7,22 +7,22 @@ Margin="0,16,0,0" HorizontalAlignment="Center" Gap="16"> - + Border - Border and Background - Rounded Corners - Rounded Corners diff --git a/samples/ControlCatalog/Pages/ButtonPage.xaml b/samples/ControlCatalog/Pages/ButtonPage.xaml index e595f27263..b5335ff15e 100644 --- a/samples/ControlCatalog/Pages/ButtonPage.xaml +++ b/samples/ControlCatalog/Pages/ButtonPage.xaml @@ -11,7 +11,7 @@ - + - - - + + + diff --git a/samples/ControlCatalog/Pages/ContextMenuPage.xaml b/samples/ControlCatalog/Pages/ContextMenuPage.xaml index f029b1106f..3af823befc 100644 --- a/samples/ControlCatalog/Pages/ContextMenuPage.xaml +++ b/samples/ControlCatalog/Pages/ContextMenuPage.xaml @@ -7,7 +7,7 @@ Margin="0,16,0,0" HorizontalAlignment="Center" Gap="16"> - diff --git a/samples/ControlCatalog/Pages/DropDownPage.xaml b/samples/ControlCatalog/Pages/DropDownPage.xaml index b392770060..0a7a88e331 100644 --- a/samples/ControlCatalog/Pages/DropDownPage.xaml +++ b/samples/ControlCatalog/Pages/DropDownPage.xaml @@ -14,7 +14,7 @@ - + Control Items diff --git a/samples/ControlCatalog/Pages/LayoutTransformControlPage.xaml b/samples/ControlCatalog/Pages/LayoutTransformControlPage.xaml index 850eab8818..b428cd1b9f 100644 --- a/samples/ControlCatalog/Pages/LayoutTransformControlPage.xaml +++ b/samples/ControlCatalog/Pages/LayoutTransformControlPage.xaml @@ -10,10 +10,10 @@ RowDefinitions="24,Auto,24" HorizontalAlignment="Center" VerticalAlignment="Center"> - - - - + + + + diff --git a/samples/ControlCatalog/Pages/ToolTipPage.xaml b/samples/ControlCatalog/Pages/ToolTipPage.xaml index 29df11510c..0c55fa28e4 100644 --- a/samples/ControlCatalog/Pages/ToolTipPage.xaml +++ b/samples/ControlCatalog/Pages/ToolTipPage.xaml @@ -7,7 +7,7 @@ Margin="0,16,0,0" HorizontalAlignment="Center" Gap="16"> - diff --git a/samples/ControlCatalog/SideBar.xaml b/samples/ControlCatalog/SideBar.xaml index 950de71e2b..c03bc432d4 100644 --- a/samples/ControlCatalog/SideBar.xaml +++ b/samples/ControlCatalog/SideBar.xaml @@ -3,7 +3,7 @@ - + diff --git a/samples/RenderTest/Pages/ClippingPage.xaml b/samples/RenderTest/Pages/ClippingPage.xaml index 47e9d51e3c..238e3449de 100644 --- a/samples/RenderTest/Pages/ClippingPage.xaml +++ b/samples/RenderTest/Pages/ClippingPage.xaml @@ -5,7 +5,7 @@ Width="100" Height="100" Clip="M 58.625 0.07421875 C 50.305778 0.26687364 42.411858 7.0346526 41.806641 15.595703 C 42.446442 22.063923 39.707425 13.710754 36.982422 12.683594 C 29.348395 6.1821635 16.419398 8.4359222 11.480469 17.195312 C 6.0935256 25.476803 9.8118851 37.71125 18.8125 41.6875 C 9.1554771 40.62945 -0.070876925 49.146842 0.21679688 58.857422 C 0.21545578 60.872512 0.56758794 62.88911 1.2617188 64.78125 C 4.3821886 74.16708 16.298268 78.921772 25.03125 74.326172 C 28.266843 72.062552 26.298191 74.214838 25.414062 76.398438 C 21.407348 85.589198 27.295992 97.294293 37.097656 99.501953 C 46.864883 102.3541 57.82177 94.726518 58.539062 84.580078 C 58.142158 79.498998 59.307538 83.392694 61.207031 85.433594 C 67.532324 93.056874 80.440232 93.192029 86.882812 85.630859 C 93.836392 78.456939 92.396838 65.538666 84.115234 60.009766 C 79.783641 57.904836 83.569793 58.802369 86.375 58.193359 C 96.383335 56.457569 102.87506 44.824101 99.083984 35.394531 C 95.963498 26.008711 84.047451 21.254079 75.314453 25.849609 C 72.078834 28.113269 74.047517 25.960974 74.931641 23.777344 C 78.93827 14.586564 73.049722 2.8815081 63.248047 0.67382812 C 61.721916 0.22817968 60.165597 0.038541919 58.625 0.07421875 z "> - + diff --git a/samples/RenderTest/Pages/DrawingPage.xaml b/samples/RenderTest/Pages/DrawingPage.xaml index 81181e01fc..ee892774f0 100644 --- a/samples/RenderTest/Pages/DrawingPage.xaml +++ b/samples/RenderTest/Pages/DrawingPage.xaml @@ -49,7 +49,7 @@ BorderThickness="1" BorderBrush="Gray" Margin="5"> - + - @@ -76,7 +76,7 @@ BorderThickness="1" BorderBrush="Gray" Margin="5"> - @@ -91,7 +91,7 @@ BorderThickness="1" BorderBrush="Gray" Margin="5"> - diff --git a/samples/RenderTest/SideBar.xaml b/samples/RenderTest/SideBar.xaml index 950de71e2b..c03bc432d4 100644 --- a/samples/RenderTest/SideBar.xaml +++ b/samples/RenderTest/SideBar.xaml @@ -3,7 +3,7 @@ - + diff --git a/src/Avalonia.Themes.Default/Button.xaml b/src/Avalonia.Themes.Default/Button.xaml index daa2973b21..908f293fa7 100644 --- a/src/Avalonia.Themes.Default/Button.xaml +++ b/src/Avalonia.Themes.Default/Button.xaml @@ -1,9 +1,9 @@ \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/CheckBox.xaml b/src/Avalonia.Themes.Default/CheckBox.xaml index 2fc19b2679..195ec098c9 100644 --- a/src/Avalonia.Themes.Default/CheckBox.xaml +++ b/src/Avalonia.Themes.Default/CheckBox.xaml @@ -1,8 +1,8 @@ \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/DropDown.xaml b/src/Avalonia.Themes.Default/DropDown.xaml index 5a3d44360c..0e8b409cfd 100644 --- a/src/Avalonia.Themes.Default/DropDown.xaml +++ b/src/Avalonia.Themes.Default/DropDown.xaml @@ -1,7 +1,7 @@ \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/EmbeddableControlRoot.xaml b/src/Avalonia.Themes.Default/EmbeddableControlRoot.xaml index edea0ddf64..f39720bb65 100644 --- a/src/Avalonia.Themes.Default/EmbeddableControlRoot.xaml +++ b/src/Avalonia.Themes.Default/EmbeddableControlRoot.xaml @@ -1,7 +1,7 @@ @@ -25,7 +25,7 @@ diff --git a/src/Avalonia.Themes.Default/ListBox.xaml b/src/Avalonia.Themes.Default/ListBox.xaml index 5aa23f5275..aa63a1b6c3 100644 --- a/src/Avalonia.Themes.Default/ListBox.xaml +++ b/src/Avalonia.Themes.Default/ListBox.xaml @@ -1,7 +1,7 @@ \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/ScrollBar.xaml b/src/Avalonia.Themes.Default/ScrollBar.xaml index 89f6f26c08..1520e12962 100644 --- a/src/Avalonia.Themes.Default/ScrollBar.xaml +++ b/src/Avalonia.Themes.Default/ScrollBar.xaml @@ -2,7 +2,7 @@ diff --git a/src/Avalonia.Themes.Default/Slider.xaml b/src/Avalonia.Themes.Default/Slider.xaml index 4fa293fbc5..b6f3cff318 100644 --- a/src/Avalonia.Themes.Default/Slider.xaml +++ b/src/Avalonia.Themes.Default/Slider.xaml @@ -16,7 +16,7 @@ - + @@ -43,7 +43,7 @@ - + @@ -61,6 +61,6 @@ \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/TabStripItem.xaml b/src/Avalonia.Themes.Default/TabStripItem.xaml index cee1c5e460..7f7fef0a1a 100644 --- a/src/Avalonia.Themes.Default/TabStripItem.xaml +++ b/src/Avalonia.Themes.Default/TabStripItem.xaml @@ -1,8 +1,8 @@ \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/TextBox.xaml b/src/Avalonia.Themes.Default/TextBox.xaml index 8a5a41845b..8acc97d663 100644 --- a/src/Avalonia.Themes.Default/TextBox.xaml +++ b/src/Avalonia.Themes.Default/TextBox.xaml @@ -1,8 +1,8 @@ \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/ToggleButton.xaml b/src/Avalonia.Themes.Default/ToggleButton.xaml index 0c8a3fa425..12d7daacda 100644 --- a/src/Avalonia.Themes.Default/ToggleButton.xaml +++ b/src/Avalonia.Themes.Default/ToggleButton.xaml @@ -1,9 +1,9 @@ \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/ToolTip.xaml b/src/Avalonia.Themes.Default/ToolTip.xaml index 46e297fbc2..f3e819c101 100644 --- a/src/Avalonia.Themes.Default/ToolTip.xaml +++ b/src/Avalonia.Themes.Default/ToolTip.xaml @@ -1,7 +1,7 @@ \ No newline at end of file From a9748ee901456432a25fc7e93011b58eeeeca850 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sun, 27 Aug 2017 00:36:06 +0200 Subject: [PATCH 3/4] Removed StyleResource from docs. --- docs/tutorial/from-wpf.md | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/docs/tutorial/from-wpf.md b/docs/tutorial/from-wpf.md index 0eb6e80327..d244fb076b 100644 --- a/docs/tutorial/from-wpf.md +++ b/docs/tutorial/from-wpf.md @@ -73,17 +73,6 @@ and includes `DirectProperty` for turning standard CLR properties into Avalonia properties. The common base class of `StyledProperty` and `DirectProperty` is `AvaloniaProperty`. -# Resources - -There is no `Resources` collection on controls in Avalonia, however `Style`s -do have a `Resources` collection for style-related resources. These can be -referred to using the `{StyleResource}` markup extension both inside and outside -styles. - -For non-style-related resources, we suggest defining them in code and referring -to them in markup using the `{Static}` markup extension. To read more about the reasoning for this, -see [this issue comment](https://github.com/AvaloniaUI/Avalonia/issues/462#issuecomment-191849723). - ## Grid Column and row definitions can be specified in Avalonia using strings, avoiding From e069eb8014b931db4be695d89772c0ecb2175dd2 Mon Sep 17 00:00:00 2001 From: Eli Arbel Date: Sat, 2 Sep 2017 15:48:28 +0300 Subject: [PATCH 4/4] PR comments --- .../Rendering/DirtyVisuals.cs | 79 ++++--------------- 1 file changed, 17 insertions(+), 62 deletions(-) diff --git a/src/Avalonia.Visuals/Rendering/DirtyVisuals.cs b/src/Avalonia.Visuals/Rendering/DirtyVisuals.cs index 895b1679b0..00bc236b9c 100644 --- a/src/Avalonia.Visuals/Rendering/DirtyVisuals.cs +++ b/src/Avalonia.Visuals/Rendering/DirtyVisuals.cs @@ -17,8 +17,8 @@ namespace Avalonia.Rendering { private SortedDictionary> _inner = new SortedDictionary>(); private Dictionary _index = new Dictionary(); - private List<(DeferredChange change, IVisual visual)> _deferredChanges = new List<(DeferredChange, IVisual)>(); - private bool _deferring; + private List _deferredChanges = new List(); + private int _deferring; /// /// Gets the number of dirty visuals. @@ -31,9 +31,9 @@ namespace Avalonia.Rendering /// The dirty visual. public void Add(IVisual visual) { - if (_deferring) + if (_deferring > 0) { - _deferredChanges.Add((DeferredChange.Add, visual)); + _deferredChanges.Add(visual); return; } @@ -65,42 +65,23 @@ namespace Avalonia.Rendering /// public void Clear() { - if (_deferring) + if (_deferring > 0) { - _deferredChanges.Add((DeferredChange.Clear, null)); - return; + throw new InvalidOperationException("Cannot clear while enumerating"); } _inner.Clear(); _index.Clear(); } - /// - /// Removes a visual from the dirty list. - /// - /// The visual. - public void Remove(IVisual visual) - { - if (_deferring) - { - _deferredChanges.Add((DeferredChange.Remove, visual)); - return; - } - - if (_index.TryGetValue(visual, out var distance)) - { - _inner[distance].Remove(visual); - _index.Remove(visual); - } - } - /// /// Gets the dirty visuals, in ascending order of distance to their root. /// /// A collection of visuals. public IEnumerator GetEnumerator() { - using (DeferChanges()) + BeginDefer(); + try { foreach (var i in _inner) { @@ -110,34 +91,24 @@ namespace Avalonia.Rendering } } } + finally + { + EndDefer(); + } } - private DeferDisposer DeferChanges() + private void BeginDefer() { - _deferring = true; - return new DeferDisposer(this); + ++_deferring; } private void EndDefer() { - if (!_deferring) return; + if (--_deferring > 0) return; - _deferring = false; - - foreach (var change in _deferredChanges) + foreach (var visual in _deferredChanges) { - switch (change.change) - { - case DeferredChange.Add: - Add(change.visual); - break; - case DeferredChange.Remove: - Remove(change.visual); - break; - case DeferredChange.Clear: - Clear(); - break; - } + Add(visual); } _deferredChanges.Clear(); @@ -148,21 +119,5 @@ namespace Avalonia.Rendering /// /// A collection of visuals. IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - - private struct DeferDisposer : IDisposable - { - private DirtyVisuals _parent; - - internal DeferDisposer(DirtyVisuals parent) => _parent = parent; - - public void Dispose() => _parent?.EndDefer(); - } - - private enum DeferredChange - { - Add, - Remove, - Clear - } } }