-
-
Notifications
You must be signed in to change notification settings - Fork 54
chore: refactor window activated event #642
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,102 @@ | ||||||||||||||||||||||||||||||||
using Windows.UI.Core; | ||||||||||||||||||||||||||||||||
using Windows.UI.Xaml; | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
namespace Screenbox.Triggers; | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
/// <summary> | ||||||||||||||||||||||||||||||||
/// Represents a declarative rule that applies visual states based on the <see cref="CoreWindow.ActivationMode"/> property. | ||||||||||||||||||||||||||||||||
/// </summary> | ||||||||||||||||||||||||||||||||
/// <remarks> | ||||||||||||||||||||||||||||||||
/// Use WindowActivationModeTriggers to create rules that automatically triggers a VisualState change when | ||||||||||||||||||||||||||||||||
/// the window is a specified activation state. When you use WindowActivationModeTriggers in your XAML markup, | ||||||||||||||||||||||||||||||||
/// you don't need to handle the <see cref="CoreWindow.Activated"/> event and call <see cref="VisualStateManager.GoToState"/> in your code. | ||||||||||||||||||||||||||||||||
/// </remarks> | ||||||||||||||||||||||||||||||||
/// <example> | ||||||||||||||||||||||||||||||||
/// This example shows how to use the <see cref="VisualState.StateTriggers"/> property with an <see cref="WindowActivationModeTrigger"/> | ||||||||||||||||||||||||||||||||
/// to create a declarative rule in XAML markup based on the activation state of the window. | ||||||||||||||||||||||||||||||||
/// <code lang="xaml"> | ||||||||||||||||||||||||||||||||
/// <Grid> | ||||||||||||||||||||||||||||||||
/// <StackPanel> | ||||||||||||||||||||||||||||||||
/// <TextBlock x:Name="FirstText" | ||||||||||||||||||||||||||||||||
/// Foreground="{ThemeResource TextFillColorPrimaryBrush}" | ||||||||||||||||||||||||||||||||
/// Text="This is a block of text. It is the 1st text block." /> | ||||||||||||||||||||||||||||||||
/// <TextBlock x:Name="LastText" | ||||||||||||||||||||||||||||||||
/// Foreground="{ThemeResource TextFillColorPrimaryBrush}" | ||||||||||||||||||||||||||||||||
/// Text="This is a block of text. It is the 2nd text block." /> | ||||||||||||||||||||||||||||||||
/// </StackPanel> | ||||||||||||||||||||||||||||||||
/// <VisualStateManager.VisualStateGroups> | ||||||||||||||||||||||||||||||||
/// <VisualStateGroup> | ||||||||||||||||||||||||||||||||
/// <VisualState> | ||||||||||||||||||||||||||||||||
/// <VisualState.StateTriggers> | ||||||||||||||||||||||||||||||||
/// <!-- VisualState to be triggered when the activation state of the window is Deactivated. --> | ||||||||||||||||||||||||||||||||
/// <local:WindowActivationModeTrigger ActivationMode="Deactivated" /> | ||||||||||||||||||||||||||||||||
/// </VisualState.StateTriggers> | ||||||||||||||||||||||||||||||||
/// | ||||||||||||||||||||||||||||||||
/// <VisualState.Setters> | ||||||||||||||||||||||||||||||||
/// <Setter Target="FirstText.Foreground" Value="{ThemeResource TextFillColorDisabledBrush}" /> | ||||||||||||||||||||||||||||||||
/// <Setter Target="LastText.Opacity" Value="0.4" /> | ||||||||||||||||||||||||||||||||
/// </VisualState.Setters> | ||||||||||||||||||||||||||||||||
/// </VisualState> | ||||||||||||||||||||||||||||||||
/// </VisualStateGroup> | ||||||||||||||||||||||||||||||||
/// </VisualStateManager.VisualStateGroups> | ||||||||||||||||||||||||||||||||
/// </Grid> | ||||||||||||||||||||||||||||||||
/// </code> | ||||||||||||||||||||||||||||||||
/// </example> | ||||||||||||||||||||||||||||||||
[Windows.Foundation.Metadata.ContractVersion(typeof(Windows.Foundation.UniversalApiContract), 327680u)] | ||||||||||||||||||||||||||||||||
public sealed class WindowActivationModeTrigger : StateTriggerBase | ||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||
private readonly CoreWindow _coreWindow; | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
/// <summary> | ||||||||||||||||||||||||||||||||
/// Identifies the <see cref="ActivationMode"/> dependency property. | ||||||||||||||||||||||||||||||||
/// </summary> | ||||||||||||||||||||||||||||||||
public static readonly DependencyProperty ActivationModeProperty = DependencyProperty.Register( | ||||||||||||||||||||||||||||||||
nameof(ActivationMode), typeof(CoreWindowActivationMode), typeof(WindowActivationModeTrigger), new PropertyMetadata(CoreWindowActivationMode.None, OnActivationModePropertyChanged)); | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
/// <summary> | ||||||||||||||||||||||||||||||||
/// Gets or sets the activation mode that indicates whether the trigger should be applied. | ||||||||||||||||||||||||||||||||
/// </summary> | ||||||||||||||||||||||||||||||||
public CoreWindowActivationMode ActivationMode | ||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||
get { return (CoreWindowActivationMode)GetValue(ActivationModeProperty); } | ||||||||||||||||||||||||||||||||
set { SetValue(ActivationModeProperty, value); } | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
private static void OnActivationModePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) | ||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||
if (d is WindowActivationModeTrigger trigger) | ||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||
trigger.UpdateTrigger(); | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
/// <summary> | ||||||||||||||||||||||||||||||||
/// Initializes a new instance of the <see cref="WindowActivationModeTrigger"/> class, | ||||||||||||||||||||||||||||||||
/// and registers a handler for when the window completes activation or deactivation. | ||||||||||||||||||||||||||||||||
/// </summary> | ||||||||||||||||||||||||||||||||
public WindowActivationModeTrigger() | ||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||
_coreWindow = Window.Current?.CoreWindow; | ||||||||||||||||||||||||||||||||
if (_coreWindow != null) | ||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||
_coreWindow.Activated += CoreWindow_Activated; | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Window.Current property may not be available in multi-window scenarios or when called from background threads. Consider using a more robust method to obtain the CoreWindow reference or handle potential null scenarios more explicitly.
Suggested change
Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
private void CoreWindow_Activated(CoreWindow sender, WindowActivatedEventArgs args) | ||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||
UpdateTrigger(); | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
private void UpdateTrigger() | ||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||
if (_coreWindow != null) | ||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||
SetActive(_coreWindow.ActivationMode == ActivationMode); | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
else | ||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||
SetActive(false); | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The event handler is subscribed in the constructor but never unsubscribed, which could lead to memory leaks. Consider implementing IDisposable or providing a cleanup mechanism to unsubscribe from the event when the trigger is no longer needed.
Copilot uses AI. Check for mistakes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've been thinking about this and I don't think we can call Dispose on a CoreWindow or XAML trigger. Instead, we probably should cache the Activated event to prevent multiple calls.