Added a small helper property to deal with controls that fail to update the measurements in response to complex data binding situations
This commit is contained in:
parent
1da1a82b09
commit
12fb020a27
121
Source/Properties.cs
Normal file
121
Source/Properties.cs
Normal file
@ -0,0 +1,121 @@
|
||||
#region Apache License 2.0
|
||||
/*
|
||||
Nuclex Foundation libraries for .NET
|
||||
Copyright (C) 2002-2025 Markus Ewald / Nuclex Development Labs
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
#endregion // Apache License 2.0
|
||||
|
||||
using System;
|
||||
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace Nuclex.Avalonia {
|
||||
|
||||
/// <summary>Additional properties that can be attached to Avalonia objects</summary>
|
||||
public static class Properties {
|
||||
|
||||
#region class InvalidateMeasureOnChangeObserver
|
||||
|
||||
/// <summary>
|
||||
/// Invalidates the calculated measurement of the control that is reporting
|
||||
/// a change to the property value
|
||||
/// </summary>
|
||||
private class InvalidateMeasureOnChangeObserver :
|
||||
IObserver<AvaloniaPropertyChangedEventArgs<object>> {
|
||||
|
||||
/// <summary>The one and only instance you need</summary>
|
||||
public static readonly InvalidateMeasureOnChangeObserver Instance = new();
|
||||
|
||||
/// <summary>Called after all observers have been notified successfully</summary>
|
||||
public void OnCompleted() {}
|
||||
|
||||
/// <summary>Reports when the observed control encountered an error</summary>
|
||||
/// <param name="error">Error the observed control has encountered</param>
|
||||
public void OnError(Exception error) {}
|
||||
|
||||
/// <summary>Reports the updated value of the property to the observer</summary>
|
||||
/// <param name="value">New value the property has assumed</param>
|
||||
public void OnNext(AvaloniaPropertyChangedEventArgs<object> value) {
|
||||
if(value.Sender is Control senderAsControl) {
|
||||
senderAsControl.InvalidateMeasure();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion // class InvalidateMeasureOnChangeObserver
|
||||
|
||||
/// <summary>
|
||||
/// Invalidates the object's measured size of a control and triggers a new layout pass
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// If, for some reason, an Avalonia control whose size depends on a data-bound value
|
||||
/// (for example, a <Border /> that holds a <TextBlock /gt; that uses data
|
||||
/// binding) does not update its own size, that is an Avalonia bug.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// By attaching this property to the misbehaving control and data-binding its value
|
||||
/// to the trigger that should cause a reevaluation of its dimensions, you can work
|
||||
/// around the issue:
|
||||
/// </para>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// <Border
|
||||
/// CornerRadius="4"
|
||||
/// Padding="4,0"
|
||||
/// HorizontalAlignment="Center"
|
||||
/// nuclex:Properties.InvalidateMeasureOnChange="{Binding Status}"
|
||||
/// >
|
||||
/// <TextBlock
|
||||
/// HorizontalAlignment="Center"
|
||||
/// Text="{Binding Status}"
|
||||
/// />
|
||||
/// </Border>
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </remarks>
|
||||
public static readonly AttachedProperty<object> InvalidateMeasureOnChangeProperty = (
|
||||
AvaloniaProperty.RegisterAttached<Control, object>(
|
||||
"InvalidateMeasureOnChange",
|
||||
typeof(Properties),
|
||||
defaultValue: null!,
|
||||
inherits: false
|
||||
)
|
||||
);
|
||||
|
||||
/// <summary>Initializes all static members of the class</summary>
|
||||
static Properties() {
|
||||
InvalidateMeasureOnChangeProperty.Changed.Subscribe(InvalidateMeasureOnChangeObserver.Instance);
|
||||
}
|
||||
|
||||
/// <summary>Reads the value of the 'InvalidateMeasureOnChange' property</summary>
|
||||
/// <param name="control">Control from which the property will be read</param>
|
||||
/// <returns>The current value of the property attached to the control</returns>
|
||||
public static object GetInvalidateMeasureOnChange(Control control) {
|
||||
return control.GetValue(InvalidateMeasureOnChangeProperty);
|
||||
}
|
||||
|
||||
/// <summary>Updates the value of the 'InvalidateMeasureOnChange' property</summary>
|
||||
/// <param name="control">Control on which the property will be updated</param>
|
||||
/// <param name="value">New value to assign to the attached property</param>
|
||||
public static void SetInvalidateMeasureOnChange(Control control, object value) {
|
||||
control.SetValue(InvalidateMeasureOnChangeProperty, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Avalonia
|
Loading…
Reference in New Issue
Block a user