diff --git a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm index 45d78b3926..77f53332cd 100644 --- a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm @@ -48,7 +48,6 @@ WindowBaseImpl::WindowBaseImpl(IAvnWindowBaseEvents *events, IAvnGlContext *gl, [Window setContentMaxSize:lastMaxSize]; [Window setOpaque:false]; - [Window setHasShadow:true]; } HRESULT WindowBaseImpl::ObtainNSViewHandle(void **ret) { diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.mm b/native/Avalonia.Native/src/OSX/WindowImpl.mm index 85a89955f4..95f61422cb 100644 --- a/native/Avalonia.Native/src/OSX/WindowImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowImpl.mm @@ -24,6 +24,8 @@ WindowImpl::WindowImpl(IAvnWindowEvents *events, IAvnGlContext *gl) : WindowBase _lastTitle = @""; _parent = nullptr; WindowEvents = events; + + [Window setHasShadow:true]; OnInitialiseNSWindow(); } diff --git a/samples/ControlCatalog.Web/App.razor.cs b/samples/ControlCatalog.Web/App.razor.cs index c0b7ddbe1e..560e8079a6 100644 --- a/samples/ControlCatalog.Web/App.razor.cs +++ b/samples/ControlCatalog.Web/App.razor.cs @@ -11,6 +11,7 @@ public partial class App { ControlCatalog.Pages.EmbedSample.Implementation = new EmbedSampleWeb(); }) + //.With(new SkiaOptions { CustomGpuFactory = null }) // uncomment to disable GPU/GL rendering .SetupWithSingleViewLifetime(); base.OnParametersSet(); diff --git a/src/Avalonia.Base/ValueStore.cs b/src/Avalonia.Base/ValueStore.cs index 69c644dff9..bf29e0b0ac 100644 --- a/src/Avalonia.Base/ValueStore.cs +++ b/src/Avalonia.Base/ValueStore.cs @@ -462,10 +462,6 @@ namespace Avalonia values.Remove(entry.property); } } - else - { - throw new AvaloniaInternalException("Value could not be found at the end of batch update."); - } // If a new batch update was started while ending this one, abort. if (_batchUpdateCount > 0) diff --git a/src/Avalonia.Controls/Flyouts/FlyoutBase.cs b/src/Avalonia.Controls/Flyouts/FlyoutBase.cs index 4801fa69f0..1504d2b25f 100644 --- a/src/Avalonia.Controls/Flyouts/FlyoutBase.cs +++ b/src/Avalonia.Controls/Flyouts/FlyoutBase.cs @@ -223,6 +223,7 @@ namespace Avalonia.Controls.Primitives { Popup.PlacementTarget = Target = placementTarget; ((ISetLogicalParent)Popup).SetParent(placementTarget); + Popup.SetValue(StyledElement.TemplatedParentProperty, placementTarget.TemplatedParent); } if (Popup.Child == null) diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs index 95e5e25c42..1501d97470 100644 --- a/src/Avalonia.Controls/Primitives/Popup.cs +++ b/src/Avalonia.Controls/Primitives/Popup.cs @@ -860,22 +860,7 @@ namespace Avalonia.Controls.Primitives { if (control != null) { - var templatedParent = TemplatedParent; - - if (control.TemplatedParent == null) - { - control.SetValue(TemplatedParentProperty, templatedParent); - } - - control.ApplyTemplate(); - - if (!(control is IPresenter) && control.TemplatedParent == templatedParent) - { - foreach (IControl child in control.VisualChildren) - { - SetTemplatedParentAndApplyChildTemplates(child); - } - } + TemplatedControl.ApplyTemplatedParent(control, TemplatedParent); } } diff --git a/src/Avalonia.Controls/Primitives/TemplatedControl.cs b/src/Avalonia.Controls/Primitives/TemplatedControl.cs index db029d38c0..4403bfce51 100644 --- a/src/Avalonia.Controls/Primitives/TemplatedControl.cs +++ b/src/Avalonia.Controls/Primitives/TemplatedControl.cs @@ -285,7 +285,7 @@ namespace Avalonia.Controls.Primitives Logger.TryGet(LogEventLevel.Verbose, LogArea.Control)?.Log(this, "Creating control template"); var (child, nameScope) = template.Build(this); - ApplyTemplatedParent(child); + ApplyTemplatedParent(child, this); ((ISetLogicalParent)child).SetParent(this); VisualChildren.Add(child); @@ -387,18 +387,18 @@ namespace Avalonia.Controls.Primitives /// Sets the TemplatedParent property for the created template children. /// /// The control. - private void ApplyTemplatedParent(IControl control) + internal static void ApplyTemplatedParent(IStyledElement control, ITemplatedControl? templatedParent) { - control.SetValue(TemplatedParentProperty, this); + control.SetValue(TemplatedParentProperty, templatedParent); var children = control.LogicalChildren; var count = children.Count; for (var i = 0; i < count; i++) { - if (children[i] is IControl child) + if (children[i] is IStyledElement child) { - ApplyTemplatedParent(child); + ApplyTemplatedParent(child, templatedParent); } } } diff --git a/src/Avalonia.Controls/ToolTip.cs b/src/Avalonia.Controls/ToolTip.cs index 91c93c87c8..bb18bf4c64 100644 --- a/src/Avalonia.Controls/ToolTip.cs +++ b/src/Avalonia.Controls/ToolTip.cs @@ -271,8 +271,9 @@ namespace Avalonia.Controls _popupHost = OverlayPopupHost.CreatePopupHost(control, null); _popupHost.SetChild(this); ((ISetLogicalParent)_popupHost).SetParent(control); - - _popupHost.ConfigurePosition(control, GetPlacement(control), + ApplyTemplatedParent(this, control.TemplatedParent); + + _popupHost.ConfigurePosition(control, GetPlacement(control), new Point(GetHorizontalOffset(control), GetVerticalOffset(control))); WindowManagerAddShadowHintChanged(_popupHost, false); diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs index e383c160e3..f8e2e0544f 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs @@ -113,6 +113,8 @@ namespace Avalonia.Diagnostics.ViewModels } } + public bool CanNavigateToParentProperty => _selectedEntitiesStack.Count >= 1; + private (object resourceKey, bool isDynamic)? GetResourceInfo(object? value) { if (value is StaticResourceExtension staticResource) @@ -415,7 +417,14 @@ namespace Avalonia.Diagnostics.ViewModels } } - public void ApplySelectedProperty() + private static IEnumerable GetAllPublicProperties(Type type) + { + return type + .GetProperties() + .Concat(type.GetInterfaces().SelectMany(i => i.GetProperties())); + } + + public void NavigateToSelectedProperty() { var selectedProperty = SelectedProperty; var selectedEntity = SelectedEntity; @@ -423,72 +432,103 @@ namespace Avalonia.Diagnostics.ViewModels if (selectedEntity == null || selectedProperty == null || selectedProperty.PropertyType == typeof(string) - || selectedProperty.PropertyType.IsValueType - ) + || selectedProperty.PropertyType.IsValueType) return; - object? property; - if (selectedProperty.Key is AvaloniaProperty avaloniaProperty) + object? property = null; + + switch (selectedProperty) { - property = (_selectedEntity as IControl)?.GetValue(avaloniaProperty); + case AvaloniaPropertyViewModel avaloniaProperty: + + property = (_selectedEntity as IControl)?.GetValue(avaloniaProperty.Property); + + break; + + case ClrPropertyViewModel clrProperty: + { + property = GetAllPublicProperties(selectedEntity.GetType()) + .FirstOrDefault(pi => clrProperty.Property == pi)? + .GetValue(selectedEntity); + + break; + } } - else + + if (property == null) + return; + + _selectedEntitiesStack.Push((Name:selectedEntityName!, Entry:selectedEntity)); + + var propertyName = selectedProperty.Name; + + //Strip out interface names + if (propertyName.LastIndexOf('.') is var p && p != -1) { - property = selectedEntity.GetType().GetProperties() - .FirstOrDefault(pi => pi.Name == selectedProperty.Name - && pi.DeclaringType == selectedProperty.DeclaringType - && pi.PropertyType.Name == selectedProperty.PropertyType.Name) - ?.GetValue(selectedEntity); + propertyName = propertyName.Substring(p + 1); } - if (property == null) return; - _selectedEntitiesStack.Push((Name:selectedEntityName!,Entry:selectedEntity)); - NavigateToProperty(property, selectedProperty.Name); + + NavigateToProperty(property, selectedEntityName + "." + propertyName); + + RaisePropertyChanged(nameof(CanNavigateToParentProperty)); } - public void ApplyParentProperty() + public void NavigateToParentProperty() { - if (_selectedEntitiesStack.Any()) + if (_selectedEntitiesStack.Count > 0) { var property = _selectedEntitiesStack.Pop(); NavigateToProperty(property.Entry, property.Name); + + RaisePropertyChanged(nameof(CanNavigateToParentProperty)); } } - protected void NavigateToProperty(object o, string? entityName) + protected void NavigateToProperty(object o, string? entityName) { var oldSelectedEntity = SelectedEntity; - if (oldSelectedEntity is IAvaloniaObject ao1) - { - ao1.PropertyChanged -= ControlPropertyChanged; - } - else if (oldSelectedEntity is INotifyPropertyChanged inpc1) + + switch (oldSelectedEntity) { - inpc1.PropertyChanged -= ControlPropertyChanged; + case IAvaloniaObject ao1: + ao1.PropertyChanged -= ControlPropertyChanged; + break; + + case INotifyPropertyChanged inpc1: + inpc1.PropertyChanged -= ControlPropertyChanged; + break; } - + SelectedEntity = o; SelectedEntityName = entityName; SelectedEntityType = o.ToString(); + var properties = GetAvaloniaProperties(o) .Concat(GetClrProperties(o, _showImplementedInterfaces)) .OrderBy(x => x, PropertyComparer.Instance) .ThenBy(x => x.Name) .ToArray(); - _propertyIndex = properties.GroupBy(x => x.Key).ToDictionary(x => x.Key, x => x.ToArray()); + _propertyIndex = properties + .GroupBy(x => x.Key) + .ToDictionary(x => x.Key, x => x.ToArray()); + + TreePage.PropertiesFilter.FilterString = string.Empty; var view = new DataGridCollectionView(properties); view.GroupDescriptions.Add(new DataGridPathGroupDescription(nameof(AvaloniaPropertyViewModel.Group))); view.Filter = FilterProperty; PropertiesView = view; - if (o is IAvaloniaObject ao2) + switch (o) { - ao2.PropertyChanged += ControlPropertyChanged; - } - else if (o is INotifyPropertyChanged inpc2) - { - inpc2.PropertyChanged += ControlPropertyChanged; + case IAvaloniaObject ao2: + ao2.PropertyChanged += ControlPropertyChanged; + break; + + case INotifyPropertyChanged inpc2: + inpc2.PropertyChanged += ControlPropertyChanged; + break; } } @@ -498,7 +538,9 @@ namespace Avalonia.Diagnostics.ViewModels if (SelectedEntity != _avaloniaObject) { - NavigateToProperty(_avaloniaObject, (_avaloniaObject as IControl)?.Name ?? _avaloniaObject.ToString()); + NavigateToProperty( + _avaloniaObject, + (_avaloniaObject as IControl)?.Name ?? _avaloniaObject.ToString()); } if (PropertiesView is null) diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml b/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml index cc392853be..a426b387f7 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml @@ -30,7 +30,11 @@ -