ControlTheme_Change.cs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Runtime.CompilerServices;
  4. using Avalonia.Controls;
  5. using Avalonia.Media;
  6. using Avalonia.Styling;
  7. using Avalonia.UnitTests;
  8. using BenchmarkDotNet.Attributes;
  9. namespace Avalonia.Benchmarks.Styling
  10. {
  11. [MemoryDiagnoser]
  12. public class ControlTheme_Change : IDisposable
  13. {
  14. private readonly IDisposable _app;
  15. private readonly TestRoot _root;
  16. private readonly TextBox _control;
  17. private readonly ControlTheme _theme1;
  18. private readonly ControlTheme _theme2;
  19. public ControlTheme_Change()
  20. {
  21. _app = UnitTestApplication.Start(
  22. TestServices.StyledWindow.With(
  23. renderInterface: new NullRenderingPlatform(),
  24. dispatcherImpl: new NullThreadingPlatform()));
  25. // Simulate an application with a lot of styles by creating a tree of nested panels,
  26. // each with a bunch of styles applied.
  27. var (rootPanel, leafPanel) = CreateNestedPanels(10);
  28. // We're benchmarking how long it takes to switch control theme on a TextBox in this
  29. // situation.
  30. var baseTheme = (ControlTheme)Application.Current.FindResource(typeof(TextBox)) ??
  31. throw new Exception("Base TextBox theme not found.");
  32. _theme1 = new ControlTheme(typeof(TextBox))
  33. {
  34. BasedOn = baseTheme,
  35. Setters = { new Setter(TextBox.BackgroundProperty, Brushes.Red) },
  36. };
  37. _theme2 = new ControlTheme(typeof(TextBox))
  38. {
  39. BasedOn = baseTheme,
  40. Setters = { new Setter(TextBox.BackgroundProperty, Brushes.Green) },
  41. };
  42. _control = new TextBox { Theme = _theme1 };
  43. leafPanel.Children.Add(_control);
  44. _root = new TestRoot(true, rootPanel)
  45. {
  46. Renderer = new NullRenderer(),
  47. };
  48. _root.LayoutManager.ExecuteInitialLayoutPass();
  49. }
  50. [Benchmark]
  51. [MethodImpl(MethodImplOptions.NoInlining)]
  52. public void Change_ControlTheme()
  53. {
  54. if (_control.Background != Brushes.Red)
  55. throw new Exception("Invalid benchmark state");
  56. _control.Theme = _theme2;
  57. _root.LayoutManager.ExecuteLayoutPass();
  58. if (_control.Background != Brushes.Green)
  59. throw new Exception("Invalid benchmark state");
  60. _control.Theme = _theme1;
  61. _root.LayoutManager.ExecuteLayoutPass();
  62. if (_control.Background != Brushes.Red)
  63. throw new Exception("Invalid benchmark state");
  64. }
  65. public void Dispose()
  66. {
  67. _app.Dispose();
  68. }
  69. private static (Panel, Panel) CreateNestedPanels(int count)
  70. {
  71. var root = new Panel();
  72. var last = root;
  73. for (var i = 0; i < count; ++i)
  74. {
  75. var panel = new Panel();
  76. panel.Styles.AddRange(CreateStyles());
  77. last.Children.Add(panel);
  78. last = panel;
  79. }
  80. return (root, last);
  81. }
  82. private static IEnumerable<IStyle> CreateStyles()
  83. {
  84. var types = new[]
  85. {
  86. typeof(Border),
  87. typeof(Button),
  88. typeof(ButtonSpinner),
  89. typeof(Carousel),
  90. typeof(CheckBox),
  91. typeof(ComboBox),
  92. typeof(ContentControl),
  93. typeof(Expander),
  94. typeof(ItemsControl),
  95. typeof(Label),
  96. typeof(ListBox),
  97. typeof(ProgressBar),
  98. typeof(RadioButton),
  99. typeof(RepeatButton),
  100. typeof(ScrollViewer),
  101. typeof(Slider),
  102. typeof(Spinner),
  103. typeof(SplitView),
  104. typeof(TextBox),
  105. typeof(ToggleSwitch),
  106. typeof(TreeView),
  107. typeof(Viewbox),
  108. typeof(Window),
  109. };
  110. foreach (var type in types)
  111. {
  112. yield return new Style(x => x.OfType(type))
  113. {
  114. Setters = { new Setter(Control.TagProperty, type.Name) }
  115. };
  116. yield return new Style(x => x.OfType(type).Class("foo"))
  117. {
  118. Setters = { new Setter(Control.TagProperty, type.Name + " foo") }
  119. };
  120. yield return new Style(x => x.OfType(type).Class("bar"))
  121. {
  122. Setters = { new Setter(Control.TagProperty, type.Name + " bar") }
  123. };
  124. }
  125. }
  126. }
  127. }