csharpc-sharpdotnetxamlavaloniauicross-platformcross-platform-xamlavaloniaguimulti-platformuser-interfacedotnetcore
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
165 lines
5.1 KiB
165 lines
5.1 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using Avalonia.Animation;
|
|
using Avalonia.Controls;
|
|
using Avalonia.Metadata;
|
|
using Avalonia.PropertyStore;
|
|
using Avalonia.Styling.Activators;
|
|
|
|
namespace Avalonia.Styling
|
|
{
|
|
/// <summary>
|
|
/// Base class for <see cref="Style"/> and <see cref="ControlTheme"/>.
|
|
/// </summary>
|
|
public abstract class StyleBase : AvaloniaObject, IStyle, IResourceProvider
|
|
{
|
|
private IResourceHost? _owner;
|
|
private StyleChildren? _children;
|
|
private IResourceDictionary? _resources;
|
|
private List<ISetter>? _setters;
|
|
private List<IAnimation>? _animations;
|
|
private StyleInstance? _sharedInstance;
|
|
|
|
public IList<IStyle> Children => _children ??= new(this);
|
|
|
|
public IResourceHost? Owner
|
|
{
|
|
get => _owner;
|
|
private set
|
|
{
|
|
if (_owner != value)
|
|
{
|
|
_owner = value;
|
|
OwnerChanged?.Invoke(this, EventArgs.Empty);
|
|
}
|
|
}
|
|
}
|
|
|
|
public IStyle? Parent { get; private set; }
|
|
|
|
public IResourceDictionary Resources
|
|
{
|
|
get => _resources ?? (Resources = new ResourceDictionary());
|
|
set
|
|
{
|
|
value = value ?? throw new ArgumentNullException(nameof(value));
|
|
|
|
var hadResources = _resources?.HasResources ?? false;
|
|
|
|
_resources = value;
|
|
|
|
if (Owner is object)
|
|
{
|
|
_resources.AddOwner(Owner);
|
|
|
|
if (hadResources || _resources.HasResources)
|
|
{
|
|
Owner.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Empty);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public IList<ISetter> Setters => _setters ??= new List<ISetter>();
|
|
public IList<IAnimation> Animations => _animations ??= new List<IAnimation>();
|
|
|
|
bool IResourceNode.HasResources => _resources?.Count > 0;
|
|
IReadOnlyList<IStyle> IStyle.Children => (IReadOnlyList<IStyle>?)_children ?? Array.Empty<IStyle>();
|
|
|
|
internal bool HasChildren => _children?.Count > 0;
|
|
internal bool HasSettersOrAnimations => _setters?.Count > 0 || _animations?.Count > 0;
|
|
|
|
public void Add(ISetter setter) => Setters.Add(setter);
|
|
public void Add(IStyle style) => Children.Add(style);
|
|
|
|
public event EventHandler? OwnerChanged;
|
|
|
|
public bool TryGetResource(object key, out object? result)
|
|
{
|
|
if (_resources is not null && _resources.TryGetResource(key, out result))
|
|
return true;
|
|
|
|
if (_children is not null)
|
|
{
|
|
for (var i = 0; i < _children.Count; ++i)
|
|
{
|
|
if (_children[i].TryGetResource(key, out result))
|
|
return true;
|
|
}
|
|
}
|
|
|
|
result= null;
|
|
return false;
|
|
}
|
|
|
|
internal abstract SelectorMatchResult TryAttach(IStyleable target, object? host);
|
|
|
|
internal ValueFrame Attach(IStyleable target, IStyleActivator? activator)
|
|
{
|
|
if (target is not AvaloniaObject ao)
|
|
throw new InvalidOperationException("Styles can only be applied to AvaloniaObjects.");
|
|
|
|
StyleInstance instance;
|
|
|
|
if (_sharedInstance is not null)
|
|
{
|
|
instance = _sharedInstance;
|
|
}
|
|
else
|
|
{
|
|
var canShareInstance = activator is null;
|
|
|
|
instance = new StyleInstance(this, activator);
|
|
|
|
if (_setters is not null)
|
|
{
|
|
foreach (var setter in _setters)
|
|
{
|
|
var setterInstance = setter.Instance(instance, target);
|
|
instance.Add(setterInstance);
|
|
canShareInstance &= setterInstance == setter;
|
|
}
|
|
}
|
|
|
|
if (_animations is not null)
|
|
instance.Add(_animations);
|
|
|
|
if (canShareInstance)
|
|
{
|
|
instance.MakeShared();
|
|
_sharedInstance = instance;
|
|
}
|
|
}
|
|
|
|
ao.GetValueStore().AddFrame(instance);
|
|
instance.ApplyAnimations(ao);
|
|
return instance;
|
|
}
|
|
|
|
internal virtual void SetParent(StyleBase? parent) => Parent = parent;
|
|
|
|
void IResourceProvider.AddOwner(IResourceHost owner)
|
|
{
|
|
owner = owner ?? throw new ArgumentNullException(nameof(owner));
|
|
|
|
if (Owner != null)
|
|
{
|
|
throw new InvalidOperationException("The Style already has a parent.");
|
|
}
|
|
|
|
Owner = owner;
|
|
_resources?.AddOwner(owner);
|
|
}
|
|
|
|
void IResourceProvider.RemoveOwner(IResourceHost owner)
|
|
{
|
|
owner = owner ?? throw new ArgumentNullException(nameof(owner));
|
|
|
|
if (Owner == owner)
|
|
{
|
|
Owner = null;
|
|
_resources?.RemoveOwner(owner);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|