|
|
@@ -382,11 +382,6 @@ namespace Avalonia
|
|
|
return _stylesApplied;
|
|
|
}
|
|
|
|
|
|
- /// <summary>
|
|
|
- /// Detaches all styles from the element and queues a restyle.
|
|
|
- /// </summary>
|
|
|
- protected virtual void InvalidateStyles() => DetachStyles();
|
|
|
-
|
|
|
protected void InitializeIfNeeded()
|
|
|
{
|
|
|
if (_initCount == 0 && !IsInitialized)
|
|
|
@@ -508,17 +503,16 @@ namespace Avalonia
|
|
|
};
|
|
|
}
|
|
|
|
|
|
- void IStyleable.DetachStyles() => DetachStyles();
|
|
|
-
|
|
|
void IStyleHost.StylesAdded(IReadOnlyList<IStyle> styles)
|
|
|
{
|
|
|
- InvalidateStylesOnThisAndDescendents();
|
|
|
+ if (HasSettersOrAnimations(styles))
|
|
|
+ InvalidateStyles(recurse: true);
|
|
|
}
|
|
|
|
|
|
void IStyleHost.StylesRemoved(IReadOnlyList<IStyle> styles)
|
|
|
{
|
|
|
- var allStyles = RecurseStyles(styles);
|
|
|
- DetachStylesFromThisAndDescendents(allStyles);
|
|
|
+ if (FlattenStyles(styles) is { } allStyles)
|
|
|
+ DetachStyles(allStyles);
|
|
|
}
|
|
|
|
|
|
protected virtual void LogicalChildrenCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
|
|
|
@@ -663,6 +657,23 @@ namespace Avalonia
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
+ internal virtual void InvalidateStyles(bool recurse)
|
|
|
+ {
|
|
|
+ var values = GetValueStore();
|
|
|
+ values.BeginStyling();
|
|
|
+ try { values.RemoveFrames(FrameType.Style); }
|
|
|
+ finally { values.EndStyling(); }
|
|
|
+
|
|
|
+ _stylesApplied = false;
|
|
|
+
|
|
|
+ if (recurse && GetInheritanceChildren() is { } children)
|
|
|
+ {
|
|
|
+ var childCount = children.Count;
|
|
|
+ for (var i = 0; i < childCount; ++i)
|
|
|
+ (children[i] as StyledElement)?.InvalidateStyles(recurse);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
private static void DataContextNotifying(IAvaloniaObject o, bool updateStarted)
|
|
|
{
|
|
|
if (o is StyledElement element)
|
|
|
@@ -822,7 +833,7 @@ namespace Avalonia
|
|
|
{
|
|
|
_logicalRoot = null;
|
|
|
_implicitTheme = null;
|
|
|
- DetachStyles();
|
|
|
+ InvalidateStyles(recurse: false);
|
|
|
OnDetachedFromLogicalTree(e);
|
|
|
DetachedFromLogicalTree?.Invoke(this, e);
|
|
|
|
|
|
@@ -884,71 +895,81 @@ namespace Avalonia
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void DetachStyles(IReadOnlyList<StyleBase>? styles = null)
|
|
|
+ private void DetachStyles(IReadOnlyList<Style> styles)
|
|
|
{
|
|
|
- var valueStore = GetValueStore();
|
|
|
-
|
|
|
- valueStore.BeginStyling();
|
|
|
+ var values = GetValueStore();
|
|
|
+ values.BeginStyling();
|
|
|
+ try { values.RemoveFrames(styles); }
|
|
|
+ finally { values.EndStyling(); }
|
|
|
|
|
|
- for (var i = valueStore.Frames.Count - 1; i >= 0; --i)
|
|
|
+ if (_logicalChildren is not null)
|
|
|
{
|
|
|
- if (valueStore.Frames[i] is StyleInstance si &&
|
|
|
- si.Source is not ControlTheme &&
|
|
|
- (styles is null || styles.Contains(si.Source)))
|
|
|
+ var childCount = _logicalChildren.Count;
|
|
|
+
|
|
|
+ for (var i = 0; i < childCount; ++i)
|
|
|
{
|
|
|
- valueStore.RemoveFrame(si);
|
|
|
+ (_logicalChildren[i] as StyledElement)?.DetachStyles(styles);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- valueStore.EndStyling();
|
|
|
- _stylesApplied = false;
|
|
|
}
|
|
|
|
|
|
- private void InvalidateStylesOnThisAndDescendents()
|
|
|
+ private void NotifyResourcesChanged(
|
|
|
+ ResourcesChangedEventArgs? e = null,
|
|
|
+ bool propagate = true)
|
|
|
{
|
|
|
- InvalidateStyles();
|
|
|
-
|
|
|
- if (_logicalChildren is object)
|
|
|
+ if (ResourcesChanged is object)
|
|
|
{
|
|
|
- var childCount = _logicalChildren.Count;
|
|
|
+ e ??= ResourcesChangedEventArgs.Empty;
|
|
|
+ ResourcesChanged(this, e);
|
|
|
+ }
|
|
|
|
|
|
- for (var i = 0; i < childCount; ++i)
|
|
|
- {
|
|
|
- (_logicalChildren[i] as StyledElement)?.InvalidateStylesOnThisAndDescendents();
|
|
|
- }
|
|
|
+ if (propagate)
|
|
|
+ {
|
|
|
+ e ??= ResourcesChangedEventArgs.Empty;
|
|
|
+ NotifyChildResourcesChanged(e);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void DetachStylesFromThisAndDescendents(IReadOnlyList<StyleBase> styles)
|
|
|
+ private static IReadOnlyList<Style>? FlattenStyles(IReadOnlyList<IStyle> styles)
|
|
|
{
|
|
|
- DetachStyles(styles);
|
|
|
+ List<Style>? result = null;
|
|
|
|
|
|
- if (_logicalChildren is object)
|
|
|
+ static void FlattenStyle(IStyle style, ref List<Style>? result)
|
|
|
{
|
|
|
- var childCount = _logicalChildren.Count;
|
|
|
+ if (style is Style s)
|
|
|
+ (result ??= new()).Add(s);
|
|
|
+ FlattenStyles(style.Children, ref result);
|
|
|
+ }
|
|
|
|
|
|
- for (var i = 0; i < childCount; ++i)
|
|
|
- {
|
|
|
- (_logicalChildren[i] as StyledElement)?.DetachStylesFromThisAndDescendents(styles);
|
|
|
- }
|
|
|
+ static void FlattenStyles(IReadOnlyList<IStyle> styles, ref List<Style>? result)
|
|
|
+ {
|
|
|
+ var count = styles.Count;
|
|
|
+ for (var i = 0; i < count; ++i)
|
|
|
+ FlattenStyle(styles[i], ref result);
|
|
|
}
|
|
|
+
|
|
|
+ FlattenStyles(styles, ref result);
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
- private void NotifyResourcesChanged(
|
|
|
- ResourcesChangedEventArgs? e = null,
|
|
|
- bool propagate = true)
|
|
|
+ private static bool HasSettersOrAnimations(IReadOnlyList<IStyle> styles)
|
|
|
{
|
|
|
- if (ResourcesChanged is object)
|
|
|
+ static bool StyleHasSettersOrAnimations(IStyle style)
|
|
|
{
|
|
|
- e ??= ResourcesChangedEventArgs.Empty;
|
|
|
- ResourcesChanged(this, e);
|
|
|
+ if (style is StyleBase s && s.HasSettersOrAnimations)
|
|
|
+ return true;
|
|
|
+ return HasSettersOrAnimations(style.Children);
|
|
|
}
|
|
|
|
|
|
- if (propagate)
|
|
|
+ var count = styles.Count;
|
|
|
+
|
|
|
+ for (var i = 0; i < count; ++i)
|
|
|
{
|
|
|
- e ??= ResourcesChangedEventArgs.Empty;
|
|
|
- NotifyChildResourcesChanged(e);
|
|
|
+ if (StyleHasSettersOrAnimations(styles[i]))
|
|
|
+ return true;
|
|
|
}
|
|
|
+
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
private static IReadOnlyList<StyleBase> RecurseStyles(IReadOnlyList<IStyle> styles)
|