using System; using System.Collections.Generic; using System.Reactive.Concurrency; using System.Threading; using Avalonia.Animation; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.Templates; using Avalonia.Input; using Avalonia.Input.Platform; using Avalonia.Input.Raw; using Avalonia.Platform; using Avalonia.Rendering; using Avalonia.Styling; using Avalonia.Threading; #nullable enable namespace Avalonia { /// /// Encapsulates a Avalonia application. /// /// /// The class encapsulates Avalonia application-specific /// functionality, including: /// - A global set of . /// - A global set of . /// - A . /// - An . /// - Registers services needed by the rest of Avalonia in the /// method. /// - Tracks the lifetime of the application. /// public class Application : AvaloniaObject, IDataContextProvider, IGlobalDataTemplates, IGlobalStyles, IResourceHost, IApplicationPlatformEvents { /// /// The application-global data templates. /// private DataTemplates? _dataTemplates; private readonly Lazy _clipboard = new Lazy(() => (IClipboard)AvaloniaLocator.Current.GetService(typeof(IClipboard))); private readonly Styler _styler = new Styler(); private Styles? _styles; private IResourceDictionary? _resources; private bool _notifyingResourcesChanged; private Action>? _stylesAdded; private Action>? _stylesRemoved; /// /// Defines the property. /// public static readonly StyledProperty DataContextProperty = StyledElement.DataContextProperty.AddOwner(); /// public event EventHandler? ResourcesChanged; public event EventHandler? UrlsOpened; /// /// Creates an instance of the class. /// public Application() { Name = "Avalonia Application"; } /// /// Gets or sets the Applications's data context. /// /// /// The data context property specifies the default object that will /// be used for data binding. /// public object? DataContext { get { return GetValue(DataContextProperty); } set { SetValue(DataContextProperty, value); } } /// /// Gets the current instance of the class. /// /// /// The current instance of the class. /// public static Application Current { get { return AvaloniaLocator.Current.GetService(); } } /// /// Gets or sets the application's global data templates. /// /// /// The application's global data templates. /// public DataTemplates DataTemplates => _dataTemplates ?? (_dataTemplates = new DataTemplates()); /// /// Gets the application's focus manager. /// /// /// The application's focus manager. /// public IFocusManager? FocusManager { get; private set; } /// /// Gets the application's input manager. /// /// /// The application's input manager. /// public InputManager? InputManager { get; private set; } /// /// Gets the application clipboard. /// public IClipboard Clipboard => _clipboard.Value; /// /// Gets the application's global resource dictionary. /// public IResourceDictionary Resources { get => _resources ??= new ResourceDictionary(this); set { value = value ?? throw new ArgumentNullException(nameof(value)); _resources?.RemoveOwner(this); _resources = value; _resources.AddOwner(this); } } /// /// Gets the application's global styles. /// /// /// The application's global styles. /// /// /// Global styles apply to all windows in the application. /// public Styles Styles => _styles ??= new Styles(this); /// bool IDataTemplateHost.IsDataTemplatesInitialized => _dataTemplates != null; /// bool IResourceNode.HasResources => (_resources?.HasResources ?? false) || (((IResourceNode?)_styles)?.HasResources ?? false); /// /// Gets the styling parent of the application, which is null. /// IStyleHost? IStyleHost.StylingParent => null; /// bool IStyleHost.IsStylesInitialized => _styles != null; /// /// Application lifetime, use it for things like setting the main window and exiting the app from code /// Currently supported lifetimes are: /// - /// - /// - /// public IApplicationLifetime? ApplicationLifetime { get; set; } event Action> IGlobalStyles.GlobalStylesAdded { add => _stylesAdded += value; remove => _stylesAdded -= value; } event Action> IGlobalStyles.GlobalStylesRemoved { add => _stylesRemoved += value; remove => _stylesRemoved -= value; } /// /// Initializes the application by loading XAML etc. /// public virtual void Initialize() { } /// bool IResourceNode.TryGetResource(object key, out object? value) { value = null; return (_resources?.TryGetResource(key, out value) ?? false) || Styles.TryGetResource(key, out value); } void IResourceHost.NotifyHostedResourcesChanged(ResourcesChangedEventArgs e) { ResourcesChanged?.Invoke(this, e); } void IStyleHost.StylesAdded(IReadOnlyList styles) { _stylesAdded?.Invoke(styles); } void IStyleHost.StylesRemoved(IReadOnlyList styles) { _stylesRemoved?.Invoke(styles); } /// /// Register's the services needed by Avalonia. /// public virtual void RegisterServices() { AvaloniaSynchronizationContext.InstallIfNeeded(); FocusManager = new FocusManager(); InputManager = new InputManager(); AvaloniaLocator.CurrentMutable .Bind().ToTransient() .Bind().ToConstant(this) .Bind().ToConstant(this) .Bind().ToConstant(FocusManager) .Bind().ToConstant(InputManager) .Bind().ToTransient() .Bind().ToConstant(_styler) .Bind().ToConstant(AvaloniaScheduler.Instance) .Bind().ToConstant(DragDropDevice.Instance); // TODO: Fix this, for now we keep this behavior since someone might be relying on it in 0.9.x if (AvaloniaLocator.Current.GetService() == null) AvaloniaLocator.CurrentMutable .Bind().ToTransient(); var clock = new RenderLoopClock(); AvaloniaLocator.CurrentMutable .Bind().ToConstant(clock) .GetService()?.Add(clock); } public virtual void OnFrameworkInitializationCompleted() { } void IApplicationPlatformEvents.RaiseUrlsOpened(string[] urls) { UrlsOpened?.Invoke(this, new UrlOpenedEventArgs (urls)); } private void NotifyResourcesChanged(ResourcesChangedEventArgs e) { if (_notifyingResourcesChanged) { return; } try { _notifyingResourcesChanged = true; ResourcesChanged?.Invoke(this, ResourcesChangedEventArgs.Empty); } finally { _notifyingResourcesChanged = false; } } private void ThisResourcesChanged(object sender, ResourcesChangedEventArgs e) { NotifyResourcesChanged(e); } private string? _name; /// /// Defines Name property /// public static readonly DirectProperty NameProperty = AvaloniaProperty.RegisterDirect("Name", o => o.Name, (o, v) => o.Name = v); /// /// Application name to be used for various platform-specific purposes /// public string? Name { get => _name; set => SetAndRaise(NameProperty, ref _name, value); } } }