Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions src/MaterialDesignThemes.Wpf/DialogHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -667,14 +667,9 @@ public override void OnApplyTemplate()

VisualStateManager.GoToState(this, GetStateName(), false);

if (GetTemplateChild(RootContentPartName) is FrameworkElement root &&
VisualStateManager.GetVisualStateGroups(root) is [VisualStateGroup stateGroup, ..])
if (GetTemplateChild(RootContentPartName) is FrameworkElement root)
{
var stateNames = stateGroup.States.OfType<VisualState>().Select(x => x.Name).ToList();
if (stateNames.Contains(OpenStateName) && stateNames.Contains(ClosedStateName))
{
_visualStateMonitor = new(stateGroup);
}
_visualStateMonitor = new(root);
}
base.OnApplyTemplate();
}
Expand Down
60 changes: 46 additions & 14 deletions src/MaterialDesignThemes.Wpf/Internal/VisualStateMonitor.cs
Original file line number Diff line number Diff line change
@@ -1,41 +1,73 @@
using System.Threading;
using System.Threading;

namespace MaterialDesignThemes.Wpf.Internal;

internal sealed class VisualStateMonitor(VisualStateGroup visualStateGroup)
public sealed class VisualStateMonitor
{
private readonly VisualStateGroup _visualStateGroup = visualStateGroup ??
throw new ArgumentNullException(nameof(visualStateGroup));
public static VisualStateMonitor? GetMonitor(DependencyObject obj)
=> (VisualStateMonitor?)obj.GetValue(MonitorProperty);

public static void SetMonitor(DependencyObject obj, VisualStateMonitor? value)
=> obj.SetValue(MonitorProperty, value);

public static readonly DependencyProperty MonitorProperty =
DependencyProperty.RegisterAttached("Monitor", typeof(VisualStateMonitor), typeof(VisualStateMonitor), new PropertyMetadata(null));

public static string? GetCurrentState(DependencyObject obj)
=> (string?)obj.GetValue(CurrentStateProperty);

public static void SetCurrentState(DependencyObject obj, string? value)
=> obj.SetValue(CurrentStateProperty, value);

public static readonly DependencyProperty CurrentStateProperty =
DependencyProperty.RegisterAttached("CurrentState", typeof(string), typeof(VisualStateMonitor), new PropertyMetadata("", OnCurrentStateChanged));

private static void OnCurrentStateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (GetMonitor(d) is { } monitor)
{
monitor.StateChanged((string)e.NewValue);
}
}

private string _currentState = "";
private event EventHandler<string>? CurrentStateChanged;

public VisualStateMonitor(DependencyObject source) => SetMonitor(source, this);

public void StateChanged(string state)
{
_currentState = state;
CurrentStateChanged?.Invoke(this, state);
}

public Task WaitForState(string state, CancellationToken cancellationToken)
{
string currentState = _visualStateGroup.CurrentState.Name;
if (currentState == state) return Task.CompletedTask;
if (_currentState == state) return Task.CompletedTask;

TaskCompletionSource<string> tcs = new();

EventHandler<VisualStateChangedEventArgs> stateChanged = null!;
EventHandler<string> stateChanged = null!;
stateChanged = (sender, e) =>
{
if (e.NewState.Name == state)
if (e == state)
{
_visualStateGroup.CurrentStateChanged -= stateChanged;
CurrentStateChanged -= stateChanged;
tcs.TrySetResult(state);
}
};

cancellationToken.Register(() =>
{
_visualStateGroup.CurrentStateChanged -= stateChanged;
CurrentStateChanged -= stateChanged;
tcs.TrySetCanceled(cancellationToken);
});

_visualStateGroup.CurrentStateChanged += stateChanged;
CurrentStateChanged += stateChanged;

currentState = _visualStateGroup.CurrentState.Name;
if (currentState == state)
if (_currentState == state)
{
_visualStateGroup.CurrentStateChanged -= stateChanged;
CurrentStateChanged -= stateChanged;

return Task.CompletedTask;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wpf="clr-namespace:MaterialDesignThemes.Wpf"
xmlns:internal="clr-namespace:MaterialDesignThemes.Wpf.Internal"
xmlns:converters="clr-namespace:MaterialDesignThemes.Wpf.Converters"
xmlns:convertersInternal="clr-namespace:MaterialDesignThemes.Wpf.Converters.Internal">
<ResourceDictionary.MergedDictionaries>
Expand Down Expand Up @@ -66,6 +67,10 @@
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_DialogHostRoot"
Storyboard.TargetProperty="(internal:VisualStateMonitor.CurrentState)">
<DiscreteObjectKeyFrame KeyTime="0:0:0.3" Value="{x:Static wpf:DialogHost.OpenStateName}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
<VisualTransition From="{x:Static wpf:DialogHost.OpenStateName}" To="{x:Static wpf:DialogHost.ClosedStateName}">
Expand Down Expand Up @@ -108,6 +113,10 @@
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_DialogHostRoot"
Storyboard.TargetProperty="(internal:VisualStateMonitor.CurrentState)">
<DiscreteObjectKeyFrame KeyTime="0:0:0.3" Value="{x:Static wpf:DialogHost.ClosedStateName}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
Expand All @@ -134,6 +143,10 @@
Storyboard.TargetProperty="ScaleY"
To="1"
Duration="0" />
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_DialogHostRoot"
Storyboard.TargetProperty="(internal:VisualStateMonitor.CurrentState)">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static wpf:DialogHost.OpenStateName}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState Name="{x:Static wpf:DialogHost.ClosedStateName}">
Expand All @@ -145,6 +158,10 @@
Storyboard.TargetProperty="Opacity"
To="0"
Duration="0" />
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_DialogHostRoot"
Storyboard.TargetProperty="(internal:VisualStateMonitor.CurrentState)">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static wpf:DialogHost.ClosedStateName}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
Expand Down
Loading