diff --git a/samples/BehaviorsTestApplication/ViewModels/MainWindowViewModel.cs b/samples/BehaviorsTestApplication/ViewModels/MainWindowViewModel.cs index af08615df..fe7d937eb 100644 --- a/samples/BehaviorsTestApplication/ViewModels/MainWindowViewModel.cs +++ b/samples/BehaviorsTestApplication/ViewModels/MainWindowViewModel.cs @@ -21,6 +21,8 @@ public partial class MainWindowViewModel : ViewModelBase public IObservable Values { get; } + public ICommand InitializeCommand { get; set; } + public ICommand MoveLeftCommand { get; set; } public ICommand MoveRightCommand { get; set; } @@ -31,6 +33,8 @@ public MainWindowViewModel() { Count = 0; Position = 100.0; + InitializeCommand = ReactiveCommand.Create(Initialize); + MoveLeftCommand = ReactiveCommand.Create(() => Position -= 5.0); MoveLeftCommand = ReactiveCommand.Create(() => Position -= 5.0); MoveRightCommand = ReactiveCommand.Create(() => Position += 5.0); ResetMoveCommand = ReactiveCommand.Create(() => Position = 100.0); @@ -89,6 +93,11 @@ public MainWindowViewModel() Values = Observable.Interval(TimeSpan.FromSeconds(1)).Select(_ => _value++); } + private void Initialize() + { + Console.WriteLine("InitializeCommand"); + } + public void IncrementCount() => Count++; public void DecrementCount(object? sender, object parameter) => Count--; diff --git a/samples/BehaviorsTestApplication/Views/MainWindow.axaml b/samples/BehaviorsTestApplication/Views/MainWindow.axaml index ee4ba1772..719d2b2f1 100644 --- a/samples/BehaviorsTestApplication/Views/MainWindow.axaml +++ b/samples/BehaviorsTestApplication/Views/MainWindow.axaml @@ -1,7 +1,15 @@ + Title="XamlBehaviors Test Application" Width="1000" Height="700" + x:DataType="vm:MainWindowViewModel" + x:CompileBindings="False"> + + + + + diff --git a/src/Avalonia.Xaml.Interactivity/StyledElementBehavior.cs b/src/Avalonia.Xaml.Interactivity/StyledElementBehavior.cs index 83079e653..45bcbd193 100644 --- a/src/Avalonia.Xaml.Interactivity/StyledElementBehavior.cs +++ b/src/Avalonia.Xaml.Interactivity/StyledElementBehavior.cs @@ -61,6 +61,12 @@ public void Attach(AvaloniaObject? associatedObject) Debug.Assert(associatedObject is not null, "Cannot attach the behavior to a null object."); AssociatedObject = associatedObject ?? throw new ArgumentNullException(nameof(associatedObject)); _dataContextDisposable = SynchronizeDataContext(associatedObject); + + // NOTE: Special case handling for TopLevel as it does not trigger attached to logical or visual tree events. + if (AssociatedObject is TopLevel) + { + AttachBehaviorToLogicalTree(); + } OnAttached(); } @@ -189,17 +195,32 @@ protected virtual void OnUnloaded() internal virtual void AttachBehaviorToLogicalTree() { - if (AssociatedObject is not StyledElement styledElement || styledElement.Parent is null) + StyledElement? parent = null; + AvaloniaObject? templatedParent = null; + + if (AssociatedObject is TopLevel topLevel) { - return; + parent = topLevel; + templatedParent = topLevel.TemplatedParent; + } + + if (parent is null) + { + if (AssociatedObject is not StyledElement styledElement || styledElement.Parent is null) + { + return; + } + + parent = styledElement; + templatedParent = styledElement.TemplatedParent; } // Required for $parent binding in XAML ((ISetLogicalParent)this).SetParent(null); - ((ISetLogicalParent)this).SetParent(styledElement); + ((ISetLogicalParent)this).SetParent(parent); // Required for TemplateBinding in XAML - if (styledElement.TemplatedParent is { } templatedParent) + if (templatedParent is not null) { TemplatedParentHelper.SetTemplatedParent(this, templatedParent); } @@ -209,7 +230,7 @@ internal virtual void DetachBehaviorFromLogicalTree() { ((ISetLogicalParent)this).SetParent(null); - if (AssociatedObject is StyledElement { TemplatedParent: not null }) + if (AssociatedObject is StyledElement { TemplatedParent: not null } or TopLevel) { TemplatedParentHelper.SetTemplatedParent(this, null); } diff --git a/src/Avalonia.Xaml.Interactivity/StyledElementTrigger.cs b/src/Avalonia.Xaml.Interactivity/StyledElementTrigger.cs index 5094a8a7d..c778f5d41 100644 --- a/src/Avalonia.Xaml.Interactivity/StyledElementTrigger.cs +++ b/src/Avalonia.Xaml.Interactivity/StyledElementTrigger.cs @@ -1,3 +1,4 @@ +using Avalonia.Controls; using Avalonia.Metadata; namespace Avalonia.Xaml.Interactivity; @@ -25,12 +26,21 @@ internal override void AttachBehaviorToLogicalTree() { base.AttachBehaviorToLogicalTree(); - if (AssociatedObject is not StyledElement styledElement || styledElement.Parent is null) + StyledElement? parent = null; + + if (AssociatedObject is TopLevel topLevel) { - return; + parent = topLevel; } + else + { + if (AssociatedObject is not StyledElement styledElement || styledElement.Parent is null) + { + return; + } - var parent = this; + parent = this; + } foreach (var action in Actions) {