committed by
GitHub
45 changed files with 902 additions and 197 deletions
@ -0,0 +1,14 @@ |
|||||
|
namespace Avalonia.Controls |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Internal interface for listening to changes in <see cref="Classes"/> in a more
|
||||
|
/// performant manner than subscribing to CollectionChanged.
|
||||
|
/// </summary>
|
||||
|
internal interface IClassesChangedListener |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Notifies the listener that the <see cref="Classes"/> collection has changed.
|
||||
|
/// </summary>
|
||||
|
void Changed(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Globalization; |
||||
|
using System.Linq; |
||||
|
using Avalonia.Data; |
||||
|
using Avalonia.Data.Converters; |
||||
|
|
||||
|
namespace Avalonia.Controls.Converters; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Calls <see cref="string.Format(string, object[])"/> on the passed in values, where the first element in the list
|
||||
|
/// is the string, and everything after it is passed into the object array in order.
|
||||
|
/// </summary>
|
||||
|
public class StringFormatConverter : IMultiValueConverter |
||||
|
{ |
||||
|
public object? Convert(IList<object?> values, Type targetType, object? parameter, CultureInfo culture) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
return string.Format((string)values[0]!, values.Skip(1).ToArray()); |
||||
|
} |
||||
|
catch (Exception e) |
||||
|
{ |
||||
|
return new BindingNotification(e, BindingErrorType.Error); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,85 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.Runtime.CompilerServices; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Styling; |
||||
|
using BenchmarkDotNet.Attributes; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Benchmarks.Styling |
||||
|
{ |
||||
|
[MemoryDiagnoser] |
||||
|
public class Style_ClassSelector |
||||
|
{ |
||||
|
private Style _style = null!; |
||||
|
|
||||
|
public Style_ClassSelector() |
||||
|
{ |
||||
|
RuntimeHelpers.RunClassConstructor(typeof(TestClass).TypeHandle); |
||||
|
} |
||||
|
|
||||
|
[GlobalSetup] |
||||
|
public void Setup() |
||||
|
{ |
||||
|
_style = new Style(x => x.OfType<TestClass>().Class("foo")) |
||||
|
{ |
||||
|
Setters = { new Setter(TestClass.StringProperty, "foo") } |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
[Benchmark(OperationsPerInvoke = 50)] |
||||
|
public void Apply() |
||||
|
{ |
||||
|
var target = new TestClass(); |
||||
|
|
||||
|
target.BeginBatchUpdate(); |
||||
|
|
||||
|
for (var i = 0; i < 50; ++i) |
||||
|
_style.TryAttach(target, null); |
||||
|
|
||||
|
target.EndBatchUpdate(); |
||||
|
} |
||||
|
|
||||
|
[Benchmark(OperationsPerInvoke = 50)] |
||||
|
public void Apply_Toggle() |
||||
|
{ |
||||
|
var target = new TestClass(); |
||||
|
|
||||
|
target.BeginBatchUpdate(); |
||||
|
|
||||
|
for (var i = 0; i < 50; ++i) |
||||
|
_style.TryAttach(target, null); |
||||
|
|
||||
|
target.EndBatchUpdate(); |
||||
|
|
||||
|
target.Classes.Add("foo"); |
||||
|
target.Classes.Remove("foo"); |
||||
|
} |
||||
|
|
||||
|
[Benchmark(OperationsPerInvoke = 50)] |
||||
|
public void Apply_Detach() |
||||
|
{ |
||||
|
var target = new TestClass(); |
||||
|
|
||||
|
target.BeginBatchUpdate(); |
||||
|
|
||||
|
for (var i = 0; i < 50; ++i) |
||||
|
_style.TryAttach(target, null); |
||||
|
|
||||
|
target.EndBatchUpdate(); |
||||
|
|
||||
|
target.DetachStyles(); |
||||
|
} |
||||
|
|
||||
|
private class TestClass : Control |
||||
|
{ |
||||
|
public static readonly StyledProperty<string?> StringProperty = |
||||
|
AvaloniaProperty.Register<TestClass, string?>("String"); |
||||
|
public void DetachStyles() => InvalidateStyles(); |
||||
|
} |
||||
|
|
||||
|
private class TestClass2 : Control |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue