Reputation: 2107
I'm trying to get an object's current VisualState. I found an answer on SO that this isn't possible, and another blog elsewhere that I should be able to get these like this:
var currentState = VisualStateManager.GetVisualStateGroups(ContainerGrid);
However curentState doesn't seem to get anything. What am I doing wrong?
Upvotes: 2
Views: 3096
Reputation: 51
In UWP XAML just name de VisualStateGroup:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="PopupStates">
<VisualState x:Name="Mobile">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0"/>
</VisualState.StateTriggers>
and you get the name using:
PopupStates.CurrentState.Name
Upvotes: 1
Reputation: 2107
I found this answer worked better for me, as I didn't need anything external: Silverlight: VisualStateManager.GetVisualStateGroups doesn't, How can I get them?
Upvotes: 2
Reputation: 31724
The WinRT XAML Toolkit has this extension method - AwaitableUI.ControlExtensions.GoToVisualStateAsync()
that finds the storyboard for visual state transition using the method you mentioned (VisualStateManager.GetVisualStateGroups()
) and awaits its completion after calling the regular VisualStateManager.GoToState()
method. It has worked fine for me so far. The only thing of note is that you need to call GetVisualStateGroups()
on the element that specifies the visual state groups, so in most cases you might need to dig into the control template's visual tree since that is where they are usually defined - somewhere deeper in the template than the actual logical control.
Here is my full sample class:
using System;
using System.Linq;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Animation;
namespace WinRTXamlToolkit.AwaitableUI
{
/// <summary>
/// Extension methods for Control class.
/// </summary>
public static class ControlExtensions
{
#region GoToVisualStateAsync()
/// <summary>
/// Goes to specified visual state, waiting for the transition to complete.
/// </summary>
/// <param name="control">
/// Control to transition.
/// </param>
/// <param name="visualStatesHost">
/// FrameworkElement that defines the visual states
/// (usually the root of the control's template).
/// </param>
/// <param name="stateGroupName">
/// Name of the state group
/// (speeds up the search for the state transition storyboard).
/// </param>
/// <param name="stateName">
/// State to transition to.
/// </param>
/// <returns>
/// Awaitable task that completes when the transition storyboard completes.
/// </returns>
/// <remarks>
/// If a state transition storyboard is not found - the task
/// completes immediately.
/// </remarks>
public static async Task GoToVisualStateAsync(
this Control control,
FrameworkElement visualStatesHost,
string stateGroupName,
string stateName)
{
var tcs = new TaskCompletionSource<Storyboard>();
Storyboard storyboard =
GetStoryboardForVisualState(visualStatesHost, stateGroupName, stateName);
if (storyboard != null)
{
EventHandler<object> eh = null;
eh = (s, e) =>
{
storyboard.Completed -= eh;
tcs.SetResult(storyboard);
};
storyboard.Completed += eh;
}
VisualStateManager.GoToState(control, stateName, true);
if (storyboard == null)
{
return;
}
await tcs.Task;
}
#endregion
#region GetStoryboardForVisualState()
/// <summary>
/// Gets the state transition storyboard for the specified state.
/// </summary>
/// <param name="visualStatesHost">
/// FrameworkElement that defines the visual states
/// (usually the root of the control's template).
/// </param>
/// <param name="stateGroupName">
/// Name of the state group
/// (speeds up the search for the state transition storyboard).
/// </param>
/// <param name="stateName">
/// State to transition to.
/// </param>
/// <returns>The state transition storyboard.</returns>
private static Storyboard GetStoryboardForVisualState(
FrameworkElement visualStatesHost,
string stateGroupName,
string stateName)
{
Storyboard storyboard = null;
var stateGroups = VisualStateManager.GetVisualStateGroups(visualStatesHost);
VisualStateGroup stateGroup = null;
if (!string.IsNullOrEmpty(stateGroupName))
{
stateGroup = stateGroups.FirstOrDefault(g => g.Name == stateGroupName);
}
VisualState state = null;
if (stateGroup != null)
{
state = stateGroup.States.FirstOrDefault(s => s.Name == stateName);
}
if (state == null)
{
foreach (var group in stateGroups)
{
state = group.States.FirstOrDefault(s => s.Name == stateName);
if (state != null)
{
break;
}
}
}
if (state != null)
{
storyboard = state.Storyboard;
}
return storyboard;
}
#endregion
}
}
This is how I call it:
await this.GoToVisualStateAsync(_layoutRoot, PopupStatesGroupName, OpenPopupStateName);
Where this
is my InputDialog
control and _layoutRoot
is a part of its template defined like this:
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate
TargetType="controls:InputDialog">
<Grid
x:Name="LayoutRoot"
Background="{TemplateBinding BackgroundScreenBrush}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup
x:Name="PopupStates">
<VisualState
x:Name="OpenPopupState">
<Storyboard>
...
Once you extract that visual state group you can get the last set state by getting stateGroup.CurrentState
.
Upvotes: 1