Skip to content

Commit 5650edc

Browse files
emmaussmaxkatz6
andcommitted
fix EntendClient hints not being applied window show (#15552)
Co-authored-by: Max Katz <[email protected]>
1 parent 0aaa591 commit 5650edc

File tree

9 files changed

+401
-168
lines changed

9 files changed

+401
-168
lines changed

src/Avalonia.Controls/Button.cs

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@ public enum ClickMode
3434
[PseudoClasses(pcFlyoutOpen, pcPressed)]
3535
public class Button : ContentControl, ICommandSource, IClickableControl
3636
{
37-
private const string pcPressed = ":pressed";
37+
private const string pcPressed = ":pressed";
3838
private const string pcFlyoutOpen = ":flyout-open";
39+
private EventHandler? _canExecuteChangeHandler = default;
40+
private EventHandler CanExecuteChangedHandler => _canExecuteChangeHandler ??= new(CanExecuteChanged);
3941

4042
/// <summary>
4143
/// Defines the <see cref="ClickMode"/> property.
@@ -250,10 +252,11 @@ protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e
250252

251253
base.OnAttachedToLogicalTree(e);
252254

253-
if (Command != null)
255+
(var command, var parameter) = (Command, CommandParameter);
256+
if (command is not null)
254257
{
255-
Command.CanExecuteChanged += CanExecuteChanged;
256-
CanExecuteChanged(this, EventArgs.Empty);
258+
command.CanExecuteChanged += CanExecuteChangedHandler;
259+
CanExecuteChanged(command, parameter);
257260
}
258261
}
259262

@@ -269,9 +272,9 @@ protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs
269272

270273
base.OnDetachedFromLogicalTree(e);
271274

272-
if (Command != null)
275+
if (Command is { } command)
273276
{
274-
Command.CanExecuteChanged -= CanExecuteChanged;
277+
command.CanExecuteChanged -= CanExecuteChangedHandler;
275278
}
276279
}
277280

@@ -343,9 +346,10 @@ protected virtual void OnClick()
343346
var e = new RoutedEventArgs(ClickEvent);
344347
RaiseEvent(e);
345348

346-
if (!e.Handled && Command?.CanExecute(CommandParameter) == true)
349+
(var command, var parameter) = (Command, CommandParameter);
350+
if (!e.Handled && command is not null && command.CanExecute(parameter))
347351
{
348-
Command.Execute(CommandParameter);
352+
command.Execute(parameter);
349353
e.Handled = true;
350354
}
351355
}
@@ -451,25 +455,24 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang
451455

452456
if (change.Property == CommandProperty)
453457
{
458+
var (oldValue, newValue) = change.GetOldAndNewValue<ICommand?>();
454459
if (((ILogical)this).IsAttachedToLogicalTree)
455460
{
456-
var (oldValue, newValue) = change.GetOldAndNewValue<ICommand?>();
457461
if (oldValue is ICommand oldCommand)
458462
{
459-
oldCommand.CanExecuteChanged -= CanExecuteChanged;
463+
oldCommand.CanExecuteChanged -= CanExecuteChangedHandler;
460464
}
461465

462466
if (newValue is ICommand newCommand)
463467
{
464-
newCommand.CanExecuteChanged += CanExecuteChanged;
468+
newCommand.CanExecuteChanged += CanExecuteChangedHandler;
465469
}
466470
}
467-
468-
CanExecuteChanged(this, EventArgs.Empty);
471+
CanExecuteChanged(newValue, CommandParameter);
469472
}
470473
else if (change.Property == CommandParameterProperty)
471474
{
472-
CanExecuteChanged(this, EventArgs.Empty);
475+
CanExecuteChanged(Command, change.NewValue);
473476
}
474477
else if (change.Property == IsCancelProperty)
475478
{
@@ -557,7 +560,18 @@ protected override void UpdateDataValidation(
557560
/// <param name="e">The event args.</param>
558561
private void CanExecuteChanged(object? sender, EventArgs e)
559562
{
560-
var canExecute = Command == null || Command.CanExecute(CommandParameter);
563+
CanExecuteChanged(Command, CommandParameter);
564+
}
565+
566+
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
567+
private void CanExecuteChanged(ICommand? command, object? parameter)
568+
{
569+
if (!((ILogical)this).IsAttachedToLogicalTree)
570+
{
571+
return;
572+
}
573+
574+
var canExecute = command == null || command.CanExecute(parameter);
561575

562576
if (canExecute != _commandCanExecute)
563577
{

src/Avalonia.Controls/MenuItem.cs

Lines changed: 47 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Linq;
4-
using Avalonia.Reactive;
54
using System.Windows.Input;
65
using Avalonia.Automation.Peers;
76
using Avalonia.Controls.Metadata;
@@ -13,7 +12,7 @@
1312
using Avalonia.Input;
1413
using Avalonia.Interactivity;
1514
using Avalonia.LogicalTree;
16-
using Avalonia.Layout;
15+
using Avalonia.Reactive;
1716

1817
namespace Avalonia.Controls
1918
{
@@ -24,6 +23,9 @@ namespace Avalonia.Controls
2423
[PseudoClasses(":separator", ":radio", ":toggle", ":checked", ":icon", ":open", ":pressed", ":selected")]
2524
public class MenuItem : HeaderedSelectingItemsControl, IMenuItem, ISelectable, ICommandSource, IClickableControl, IRadioButton
2625
{
26+
private EventHandler? _canExecuteChangeHandler = default;
27+
private EventHandler CanExecuteChangedHandler => _canExecuteChangeHandler ??= new(CanExecuteChanged);
28+
2729
/// <summary>
2830
/// Defines the <see cref="Command"/> property.
2931
/// </summary>
@@ -83,7 +85,7 @@ public class MenuItem : HeaderedSelectingItemsControl, IMenuItem, ISelectable, I
8385
/// </summary>
8486
public static readonly StyledProperty<string?> GroupNameProperty =
8587
RadioButton.GroupNameProperty.AddOwner<MenuItem>();
86-
88+
8789
/// <summary>
8890
/// Defines the <see cref="Click"/> event.
8991
/// </summary>
@@ -292,7 +294,7 @@ public bool StaysOpenOnClick
292294
get => GetValue(StaysOpenOnClickProperty);
293295
set => SetValue(StaysOpenOnClickProperty, value);
294296
}
295-
297+
296298
/// <inheritdoc cref="IMenuItem.ToggleType" />
297299
public MenuItemToggleType ToggleType
298300
{
@@ -306,7 +308,7 @@ public bool IsChecked
306308
get => GetValue(IsCheckedProperty);
307309
set => SetValue(IsCheckedProperty, value);
308310
}
309-
311+
310312
bool IRadioButton.IsChecked
311313
{
312314
get => IsChecked;
@@ -319,7 +321,7 @@ public string? GroupName
319321
get => GetValue(GroupNameProperty);
320322
set => SetValue(GroupNameProperty, value);
321323
}
322-
324+
323325
/// <summary>
324326
/// Gets or sets a value that indicates whether the <see cref="MenuItem"/> has a submenu.
325327
/// </summary>
@@ -413,15 +415,16 @@ protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e
413415
{
414416
SetCurrentValue(HotKeyProperty, _hotkey);
415417
}
416-
418+
417419
base.OnAttachedToLogicalTree(e);
418420

419-
if (Command != null)
421+
(var command, var parameter) = (Command, CommandParameter);
422+
if (command is not null)
420423
{
421-
Command.CanExecuteChanged += CanExecuteChanged;
424+
command.CanExecuteChanged += CanExecuteChangedHandler;
422425
}
423-
424-
TryUpdateCanExecute();
426+
427+
TryUpdateCanExecute(command, parameter);
425428

426429
var parent = Parent;
427430

@@ -437,7 +440,7 @@ protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e
437440
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
438441
{
439442
base.OnAttachedToVisualTree(e);
440-
443+
441444
TryUpdateCanExecute();
442445
}
443446

@@ -454,7 +457,7 @@ protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs
454457

455458
if (Command != null)
456459
{
457-
Command.CanExecuteChanged -= CanExecuteChanged;
460+
Command.CanExecuteChanged -= CanExecuteChangedHandler;
458461
}
459462
}
460463

@@ -464,9 +467,10 @@ protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs
464467
/// <param name="e">The click event args.</param>
465468
protected virtual void OnClick(RoutedEventArgs e)
466469
{
467-
if (!e.Handled && Command?.CanExecute(CommandParameter) == true)
470+
(var command, var parameter) = (Command, CommandParameter);
471+
if (!e.Handled && command is not null && command.CanExecute(parameter) == true)
468472
{
469-
Command.Execute(CommandParameter);
473+
command.Execute(parameter);
470474
e.Handled = true;
471475
}
472476
}
@@ -577,21 +581,25 @@ private void CloseSubmenus()
577581
/// <param name="e">The event args.</param>
578582
private static void CommandChanged(AvaloniaPropertyChangedEventArgs e)
579583
{
580-
if (e.Sender is MenuItem menuItem &&
581-
((ILogical)menuItem).IsAttachedToLogicalTree)
584+
var newCommand = e.NewValue as ICommand;
585+
if (e.Sender is MenuItem menuItem)
586+
582587
{
583-
if (e.OldValue is ICommand oldCommand)
588+
if (((ILogical)menuItem).IsAttachedToLogicalTree)
584589
{
585-
oldCommand.CanExecuteChanged -= menuItem.CanExecuteChanged;
586-
}
590+
if (e.OldValue is ICommand oldCommand)
591+
{
592+
oldCommand.CanExecuteChanged -= menuItem.CanExecuteChangedHandler;
593+
}
587594

588-
if (e.NewValue is ICommand newCommand)
589-
{
590-
newCommand.CanExecuteChanged += menuItem.CanExecuteChanged;
595+
if (newCommand is not null)
596+
{
597+
newCommand.CanExecuteChanged += menuItem.CanExecuteChangedHandler;
598+
}
591599
}
592-
593-
menuItem.TryUpdateCanExecute();
600+
menuItem.TryUpdateCanExecute(newCommand, menuItem.CommandParameter);
594601
}
602+
595603
}
596604

597605
/// <summary>
@@ -602,7 +610,8 @@ private static void CommandParameterChanged(AvaloniaPropertyChangedEventArgs e)
602610
{
603611
if (e.Sender is MenuItem menuItem)
604612
{
605-
menuItem.TryUpdateCanExecute();
613+
(var command, var parameter) = (menuItem.Command, e.NewValue);
614+
menuItem.TryUpdateCanExecute(command, parameter);
606615
}
607616
}
608617

@@ -621,21 +630,27 @@ private void CanExecuteChanged(object? sender, EventArgs e)
621630
/// </summary>
622631
private void TryUpdateCanExecute()
623632
{
624-
if (Command == null)
633+
TryUpdateCanExecute(Command, CommandParameter);
634+
}
635+
636+
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
637+
private void TryUpdateCanExecute(ICommand? command, object? parameter)
638+
{
639+
if (command == null)
625640
{
626641
_commandCanExecute = !_commandBindingError;
627642
UpdateIsEffectivelyEnabled();
628643
return;
629644
}
630-
645+
631646
//Perf optimization - only raise CanExecute event if the menu is open
632647
if (!((ILogical)this).IsAttachedToLogicalTree ||
633648
Parent is MenuItem { IsSubMenuOpen: false })
634649
{
635650
return;
636651
}
637-
638-
var canExecute = Command.CanExecute(CommandParameter);
652+
653+
var canExecute = command.CanExecute(parameter);
639654
if (canExecute != _commandCanExecute)
640655
{
641656
_commandCanExecute = canExecute;
@@ -720,7 +735,7 @@ private void IsCheckedChanged(AvaloniaPropertyChangedEventArgs e)
720735
(MenuInteractionHandler as DefaultMenuInteractionHandler)?.OnCheckedChanged(this);
721736
}
722737
}
723-
738+
724739
/// <summary>
725740
/// Called when the <see cref="HeaderedSelectingItemsControl.Header"/> property changes.
726741
/// </summary>
@@ -834,7 +849,7 @@ private void PopupClosed(object? sender, EventArgs e)
834849
SelectedItem = null;
835850
}
836851

837-
void ICommandSource.CanExecuteChanged(object sender, EventArgs e) => this.CanExecuteChanged(sender, e);
852+
void ICommandSource.CanExecuteChanged(object sender, EventArgs e) => CanExecuteChangedHandler(sender, e);
838853

839854
void IClickableControl.RaiseClick()
840855
{

src/Avalonia.Controls/SplitButton/SplitButton.cs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,18 @@ public KeyGesture? HotKey
136136
/// <inheritdoc cref="ICommandSource.CanExecuteChanged"/>
137137
private void CanExecuteChanged(object? sender, EventArgs e)
138138
{
139-
var canExecute = Command == null || Command.CanExecute(CommandParameter);
139+
(var command, var parameter) = (Command, CommandParameter);
140+
CanExecuteChanged(command, parameter);
141+
}
142+
143+
private void CanExecuteChanged(ICommand? command, object? parameter)
144+
{
145+
if (!((ILogical)this).IsAttachedToLogicalTree)
146+
{
147+
return;
148+
}
149+
150+
var canExecute = command is null || command.CanExecute(parameter);
140151

141152
if (canExecute != _commandCanExecute)
142153
{
@@ -282,10 +293,11 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs e)
282293
{
283294
if (e.Property == CommandProperty)
284295
{
296+
// Must unregister events here while a reference to the old command still exists
297+
var (oldValue, newValue) = e.GetOldAndNewValue<ICommand?>();
298+
285299
if (_isAttachedToLogicalTree)
286300
{
287-
// Must unregister events here while a reference to the old command still exists
288-
var (oldValue, newValue) = e.GetOldAndNewValue<ICommand?>();
289301

290302
if (oldValue is ICommand oldCommand)
291303
{
@@ -298,11 +310,11 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs e)
298310
}
299311
}
300312

301-
CanExecuteChanged(this, EventArgs.Empty);
313+
CanExecuteChanged(newValue, CommandParameter);
302314
}
303-
else if (e.Property == CommandParameterProperty)
315+
else if (e.Property == CommandParameterProperty && IsLoaded)
304316
{
305-
CanExecuteChanged(this, EventArgs.Empty);
317+
CanExecuteChanged(Command, e.NewValue);
306318
}
307319
else if (e.Property == FlyoutProperty)
308320
{
@@ -386,15 +398,16 @@ protected override void OnKeyUp(KeyEventArgs e)
386398
/// <param name="e">The event args from the internal Click event.</param>
387399
protected virtual void OnClickPrimary(RoutedEventArgs? e)
388400
{
401+
(var command, var parameter) = (Command, CommandParameter);
389402
// Note: It is not currently required to check enabled status; however, this is a failsafe
390403
if (IsEffectivelyEnabled)
391404
{
392405
var eventArgs = new RoutedEventArgs(ClickEvent);
393406
RaiseEvent(eventArgs);
394407

395-
if (!eventArgs.Handled && Command?.CanExecute(CommandParameter) == true)
408+
if (!eventArgs.Handled && command?.CanExecute(parameter) == true)
396409
{
397-
Command.Execute(CommandParameter);
410+
command.Execute(parameter);
398411
eventArgs.Handled = true;
399412
}
400413
}

src/Windows/Avalonia.Win32/WindowImpl.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1205,6 +1205,8 @@ private void ShowWindow(WindowState state, bool activate)
12051205
UnmanagedMethods.ShowWindow(_hwnd, command.Value);
12061206
}
12071207

1208+
ExtendClientArea();
1209+
12081210
if (state == WindowState.Maximized)
12091211
{
12101212
MaximizeWithoutCoveringTaskbar();

0 commit comments

Comments
 (0)