diff --git a/src/Avalonia.Base/Styling/ITemplate.cs b/src/Avalonia.Base/Styling/ITemplate.cs index 8a130cb3b4..d183d3ff74 100644 --- a/src/Avalonia.Base/Styling/ITemplate.cs +++ b/src/Avalonia.Base/Styling/ITemplate.cs @@ -2,6 +2,6 @@ { public interface ITemplate { - object Build(); + object? Build(); } } diff --git a/src/Avalonia.Controls/Carousel.cs b/src/Avalonia.Controls/Carousel.cs index 84601e8690..1e0405dab4 100644 --- a/src/Avalonia.Controls/Carousel.cs +++ b/src/Avalonia.Controls/Carousel.cs @@ -1,7 +1,6 @@ using Avalonia.Animation; using Avalonia.Controls.Primitives; using Avalonia.Controls.Templates; -using Avalonia.Controls.Utils; namespace Avalonia.Controls { @@ -20,8 +19,8 @@ namespace Avalonia.Controls /// The default value of for /// . /// - private static readonly ITemplate PanelTemplate = - new FuncTemplate(() => new VirtualizingCarouselPanel()); + private static readonly FuncTemplate DefaultPanel = + new(() => new VirtualizingCarouselPanel()); private IScrollable? _scroller; @@ -31,7 +30,7 @@ namespace Avalonia.Controls static Carousel() { SelectionModeProperty.OverrideDefaultValue(SelectionMode.AlwaysSelected); - ItemsPanelProperty.OverrideDefaultValue(PanelTemplate); + ItemsPanelProperty.OverrideDefaultValue(DefaultPanel); } /// diff --git a/src/Avalonia.Controls/ComboBox.cs b/src/Avalonia.Controls/ComboBox.cs index f6e4b32d6b..1234b66383 100644 --- a/src/Avalonia.Controls/ComboBox.cs +++ b/src/Avalonia.Controls/ComboBox.cs @@ -1,13 +1,10 @@ using System; -using System.Diagnostics; using System.Linq; using Avalonia.Automation.Peers; using Avalonia.Controls.Metadata; using Avalonia.Controls.Primitives; -using Avalonia.Controls.Selection; using Avalonia.Controls.Shapes; using Avalonia.Controls.Templates; -using Avalonia.Controls.Utils; using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.Layout; @@ -29,8 +26,8 @@ namespace Avalonia.Controls /// /// The default value for the property. /// - private static readonly FuncTemplate DefaultPanel = - new FuncTemplate(() => new VirtualizingStackPanel()); + private static readonly FuncTemplate DefaultPanel = + new(() => new VirtualizingStackPanel()); /// /// Defines the property. diff --git a/src/Avalonia.Controls/ContextMenu.cs b/src/Avalonia.Controls/ContextMenu.cs index f46594ff96..fc4b11bd4a 100644 --- a/src/Avalonia.Controls/ContextMenu.cs +++ b/src/Avalonia.Controls/ContextMenu.cs @@ -4,7 +4,6 @@ using System.ComponentModel; using Avalonia.Automation.Peers; using System.Linq; using Avalonia.Controls.Diagnostics; -using Avalonia.Controls.Generators; using Avalonia.Controls.Platform; using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives.PopupPositioning; @@ -84,8 +83,8 @@ namespace Avalonia.Controls public static readonly StyledProperty PlacementTargetProperty = Popup.PlacementTargetProperty.AddOwner(); - private static readonly ITemplate DefaultPanel = - new FuncTemplate(() => new StackPanel { Orientation = Orientation.Vertical }); + private static readonly FuncTemplate DefaultPanel = + new(() => new StackPanel { Orientation = Orientation.Vertical }); private Popup? _popup; private List? _attachedControls; private IInputElement? _previousFocus; diff --git a/src/Avalonia.Controls/ItemsControl.cs b/src/Avalonia.Controls/ItemsControl.cs index 4460ff0486..1123f42afa 100644 --- a/src/Avalonia.Controls/ItemsControl.cs +++ b/src/Avalonia.Controls/ItemsControl.cs @@ -2,9 +2,7 @@ using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; -using System.Diagnostics.CodeAnalysis; using Avalonia.Automation.Peers; -using Avalonia.Collections; using Avalonia.Controls.Generators; using Avalonia.Controls.Metadata; using Avalonia.Controls.Presenters; @@ -29,8 +27,8 @@ namespace Avalonia.Controls /// /// The default value for the property. /// - private static readonly FuncTemplate DefaultPanel = - new FuncTemplate(() => new StackPanel()); + private static readonly FuncTemplate DefaultPanel = + new(() => new StackPanel()); /// /// Defines the property. @@ -58,8 +56,8 @@ namespace Avalonia.Controls /// /// Defines the property. /// - public static readonly StyledProperty> ItemsPanelProperty = - AvaloniaProperty.Register>(nameof(ItemsPanel), DefaultPanel); + public static readonly StyledProperty> ItemsPanelProperty = + AvaloniaProperty.Register>(nameof(ItemsPanel), DefaultPanel); /// /// Defines the property. @@ -202,7 +200,7 @@ namespace Avalonia.Controls /// /// Gets or sets the panel used to display the items. /// - public ITemplate ItemsPanel + public ITemplate ItemsPanel { get => GetValue(ItemsPanelProperty); set => SetValue(ItemsPanelProperty, value); diff --git a/src/Avalonia.Controls/ListBox.cs b/src/Avalonia.Controls/ListBox.cs index 80d1677c2f..e665c2db90 100644 --- a/src/Avalonia.Controls/ListBox.cs +++ b/src/Avalonia.Controls/ListBox.cs @@ -1,13 +1,10 @@ using System.Collections; -using Avalonia.Controls.Generators; using Avalonia.Controls.Metadata; -using Avalonia.Controls.Presenters; using Avalonia.Controls.Primitives; using Avalonia.Controls.Selection; using Avalonia.Controls.Templates; using Avalonia.Input; using Avalonia.Input.Platform; -using Avalonia.VisualTree; namespace Avalonia.Controls { @@ -20,8 +17,8 @@ namespace Avalonia.Controls /// /// The default value for the property. /// - private static readonly FuncTemplate DefaultPanel = - new FuncTemplate(() => new VirtualizingStackPanel()); + private static readonly FuncTemplate DefaultPanel = + new(() => new VirtualizingStackPanel()); /// /// Defines the property. diff --git a/src/Avalonia.Controls/Menu.cs b/src/Avalonia.Controls/Menu.cs index dbdcad8217..ac0262c9b2 100644 --- a/src/Avalonia.Controls/Menu.cs +++ b/src/Avalonia.Controls/Menu.cs @@ -1,7 +1,6 @@ using Avalonia.Automation; using Avalonia.Automation.Peers; using Avalonia.Controls.Platform; -using Avalonia.Controls.Primitives; using Avalonia.Controls.Templates; using Avalonia.Input; using Avalonia.Interactivity; @@ -14,9 +13,8 @@ namespace Avalonia.Controls /// public class Menu : MenuBase, IMainMenu { - private static readonly ITemplate DefaultPanel = - new FuncTemplate(() => new StackPanel { Orientation = Orientation.Horizontal }); - + private static readonly FuncTemplate DefaultPanel = + new (() => new StackPanel { Orientation = Orientation.Horizontal }); /// /// Initializes a new instance of the class. diff --git a/src/Avalonia.Controls/MenuItem.cs b/src/Avalonia.Controls/MenuItem.cs index 03e3444d71..06d84e715d 100644 --- a/src/Avalonia.Controls/MenuItem.cs +++ b/src/Avalonia.Controls/MenuItem.cs @@ -4,7 +4,6 @@ using System.Linq; using Avalonia.Reactive; using System.Windows.Input; using Avalonia.Automation.Peers; -using Avalonia.Controls.Generators; using Avalonia.Controls.Metadata; using Avalonia.Controls.Mixins; using Avalonia.Controls.Primitives; @@ -107,8 +106,8 @@ namespace Avalonia.Controls /// /// The default value for the property. /// - private static readonly ITemplate DefaultPanel = - new FuncTemplate(() => new StackPanel()); + private static readonly FuncTemplate DefaultPanel = + new(() => new StackPanel()); private bool _commandCanExecute = true; private bool _commandBindingError; diff --git a/src/Avalonia.Controls/Presenters/ItemsPresenter.cs b/src/Avalonia.Controls/Presenters/ItemsPresenter.cs index a0020a0b6e..88d1e10ba4 100644 --- a/src/Avalonia.Controls/Presenters/ItemsPresenter.cs +++ b/src/Avalonia.Controls/Presenters/ItemsPresenter.cs @@ -16,7 +16,7 @@ namespace Avalonia.Controls.Presenters /// /// Defines the property. /// - public static readonly StyledProperty> ItemsPanelProperty = + public static readonly StyledProperty> ItemsPanelProperty = ItemsControl.ItemsPanelProperty.AddOwner(); private PanelContainerGenerator? _generator; @@ -68,7 +68,7 @@ namespace Avalonia.Controls.Presenters /// /// Gets or sets a template which creates the used to display the items. /// - public ITemplate ItemsPanel + public ITemplate ItemsPanel { get => GetValue(ItemsPanelProperty); set => SetValue(ItemsPanelProperty, value); @@ -166,6 +166,12 @@ namespace Avalonia.Controls.Presenters } Panel = ItemsPanel.Build(); + + if (Panel is null) + { + return; + } + Panel.TemplatedParent = TemplatedParent; Panel.IsItemsHost = true; _scrollSnapPointsInfo = Panel as IScrollSnapPointsInfo; @@ -183,7 +189,7 @@ namespace Avalonia.Controls.Presenters else CreateSimplePanelGenerator(); - if(Panel is IScrollSnapPointsInfo scrollSnapPointsInfo) + if (Panel is IScrollSnapPointsInfo scrollSnapPointsInfo) { scrollSnapPointsInfo.VerticalSnapPointsChanged += (s, e) => { diff --git a/src/Avalonia.Controls/Primitives/TabStrip.cs b/src/Avalonia.Controls/Primitives/TabStrip.cs index b8790d2a44..25cd1cd65b 100644 --- a/src/Avalonia.Controls/Primitives/TabStrip.cs +++ b/src/Avalonia.Controls/Primitives/TabStrip.cs @@ -1,15 +1,13 @@ -using Avalonia.Controls.Generators; using Avalonia.Controls.Templates; using Avalonia.Input; using Avalonia.Layout; -using Avalonia.VisualTree; namespace Avalonia.Controls.Primitives { public class TabStrip : SelectingItemsControl { - private static readonly FuncTemplate DefaultPanel = - new FuncTemplate(() => new WrapPanel { Orientation = Orientation.Horizontal }); + private static readonly FuncTemplate DefaultPanel = + new(() => new WrapPanel { Orientation = Orientation.Horizontal }); static TabStrip() { diff --git a/src/Avalonia.Controls/Primitives/TemplatedControl.cs b/src/Avalonia.Controls/Primitives/TemplatedControl.cs index e1cf25d89f..44d68fcf30 100644 --- a/src/Avalonia.Controls/Primitives/TemplatedControl.cs +++ b/src/Avalonia.Controls/Primitives/TemplatedControl.cs @@ -286,14 +286,17 @@ namespace Avalonia.Controls.Primitives { Logger.TryGet(LogEventLevel.Verbose, LogArea.Control)?.Log(this, "Creating control template"); - var (child, nameScope) = template.Build(this); - ApplyTemplatedParent(child, this); - ((ISetLogicalParent)child).SetParent(this); - VisualChildren.Add(child); - - var e = new TemplateAppliedEventArgs(nameScope); - OnApplyTemplate(e); - RaiseEvent(e); + if (template.Build(this) is { } templateResult) + { + var (child, nameScope) = templateResult; + ApplyTemplatedParent(child, this); + ((ISetLogicalParent)child).SetParent(this); + VisualChildren.Add(child); + + var e = new TemplateAppliedEventArgs(nameScope); + OnApplyTemplate(e); + RaiseEvent(e); + } } _appliedTemplate = template; diff --git a/src/Avalonia.Controls/TabControl.cs b/src/Avalonia.Controls/TabControl.cs index f12a66a4e6..74cf54beb8 100644 --- a/src/Avalonia.Controls/TabControl.cs +++ b/src/Avalonia.Controls/TabControl.cs @@ -1,8 +1,6 @@ -using System.ComponentModel; using System.Linq; using Avalonia.Collections; using Avalonia.Automation.Peers; -using Avalonia.Controls.Generators; using Avalonia.Controls.Presenters; using Avalonia.Controls.Primitives; using Avalonia.Controls.Templates; @@ -12,7 +10,6 @@ using Avalonia.LogicalTree; using Avalonia.VisualTree; using Avalonia.Automation; using Avalonia.Controls.Metadata; -using Avalonia.Data; namespace Avalonia.Controls { @@ -61,8 +58,8 @@ namespace Avalonia.Controls /// /// The default value for the property. /// - private static readonly FuncTemplate DefaultPanel = - new FuncTemplate(() => new WrapPanel()); + private static readonly FuncTemplate DefaultPanel = + new(() => new WrapPanel()); /// /// Initializes static members of the class. diff --git a/src/Avalonia.Controls/Templates/FuncTemplate`1.cs b/src/Avalonia.Controls/Templates/FuncTemplate`1.cs index 61da607a38..aa8fa43be9 100644 --- a/src/Avalonia.Controls/Templates/FuncTemplate`1.cs +++ b/src/Avalonia.Controls/Templates/FuncTemplate`1.cs @@ -7,7 +7,7 @@ namespace Avalonia.Controls.Templates /// Creates a control from a . /// /// The type of control. - public class FuncTemplate : ITemplate where TControl : Control + public class FuncTemplate : ITemplate where TControl : Control? { private readonly Func _func; @@ -31,6 +31,6 @@ namespace Avalonia.Controls.Templates return _func(); } - object ITemplate.Build() => Build(); + object? ITemplate.Build() => Build(); } } diff --git a/src/Avalonia.Controls/Templates/IControlTemplate.cs b/src/Avalonia.Controls/Templates/IControlTemplate.cs index 67e861f6ab..38ad6561ab 100644 --- a/src/Avalonia.Controls/Templates/IControlTemplate.cs +++ b/src/Avalonia.Controls/Templates/IControlTemplate.cs @@ -1,13 +1,11 @@ -using System; using Avalonia.Controls.Primitives; -using Avalonia.Styling; namespace Avalonia.Controls.Templates { /// /// Interface representing a template used to build a . /// - public interface IControlTemplate : ITemplate + public interface IControlTemplate : ITemplate { } diff --git a/src/Avalonia.Controls/TreeViewItem.cs b/src/Avalonia.Controls/TreeViewItem.cs index 3ac157f727..cf83ba8253 100644 --- a/src/Avalonia.Controls/TreeViewItem.cs +++ b/src/Avalonia.Controls/TreeViewItem.cs @@ -40,8 +40,8 @@ namespace Avalonia.Controls AvaloniaProperty.RegisterDirect( nameof(Level), o => o.Level); - private static readonly ITemplate DefaultPanel = - new FuncTemplate(() => new StackPanel()); + private static readonly FuncTemplate DefaultPanel = + new(() => new StackPanel()); private TreeView? _treeView; private Control? _header; diff --git a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj index da739c754c..05e937fc05 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj +++ b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj @@ -58,7 +58,6 @@ - @@ -69,6 +68,7 @@ + diff --git a/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs b/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs index 0b6a2c522f..834fa84b53 100644 --- a/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs +++ b/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs @@ -1,8 +1,7 @@ using System; using System.Diagnostics.CodeAnalysis; -using System.IO; using Avalonia.Platform; -#nullable enable + namespace Avalonia.Markup.Xaml { /// @@ -79,7 +78,7 @@ namespace Avalonia.Markup.Xaml var compiledLoader = assetLocator.GetAssembly(uri, baseUri) ?.GetType("CompiledAvaloniaXaml.!XamlLoader") - ?.GetMethod("TryLoad", new[] { typeof(System.IServiceProvider), typeof(string) }); + ?.GetMethod("TryLoad", new[] { typeof(IServiceProvider), typeof(string) }); if (compiledLoader != null) { var compiledResult = compiledLoader.Invoke(null, new object?[] { sp, absoluteUri.ToString()}); diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs index 5b660af887..0a5ecebe5d 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs @@ -14,18 +14,20 @@ namespace Avalonia.Markup.Xaml.Converters [RequiresUnreferencedCode(TrimmingMessages.XamlTypeResolvedRequiresUnreferenceCodeMessage)] public class AvaloniaPropertyTypeConverter : TypeConverter { - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + /// + public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) { return sourceType == typeof(string); } - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + /// + public override object ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) { var registry = AvaloniaPropertyRegistry.Instance; var (ns, owner, propertyName) = PropertyParser.Parse(new CharacterReader(((string)value).AsSpan())); var ownerType = TryResolveOwnerByName(context, ns, owner); - var targetType = context.GetFirstParent()?.TargetType ?? - context.GetFirstParent