So my xaml code looks like this -
<Grid x:Name="LayoutRoot">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
I can't use the GoToVisualState
behavior because I need to do some checks before running this animation. So I guess I will have to call something like GoToState
or GoToElementState
in code behind.
However, ExtendedVisualStateManager
doesn't seem to exist in WinRT. I tried using
VisualStateManager.GetCustomVisualStateManager(this.LayoutRoot)
but it always returns null
.
Is there any workaround for this?
Just figured this out.
First create a helper class just like how we used to use it in Silverlight or Windows Phone (I took this piece of code from here and modified it a little bit so when an element doesn't have any visual state groups attached, it automatically goes search for its parent until it finds any).
public class ExtendedVisualStateManager : VisualStateManager
{
protected override bool GoToStateCore(Control control, FrameworkElement stateGroupsRoot, string stateName, VisualStateGroup group, VisualState state, bool useTransitions)
{
if ((group == null) || (state == null))
{
return false;
}
if (control == null)
{
control = new ContentControl();
}
return base.GoToStateCore(control, stateGroupsRoot, stateName, group, state, useTransitions);
}
public static bool GoToElementState(FrameworkElement element, string stateName, bool useTransitions)
{
var root = FindNearestStatefulFrameworkElement(element);
var customVisualStateManager = VisualStateManager.GetCustomVisualStateManager(root) as ExtendedVisualStateManager;
return ((customVisualStateManager != null) && customVisualStateManager.GoToStateInternal(root, stateName, useTransitions));
}
private static FrameworkElement FindNearestStatefulFrameworkElement(FrameworkElement element)
{
while (element != null && VisualStateManager.GetCustomVisualStateManager(element) == null)
{
element = element.Parent as FrameworkElement;
}
return element;
}
private bool GoToStateInternal(FrameworkElement stateGroupsRoot, string stateName, bool useTransitions)
{
VisualStateGroup group;
VisualState state;
return (TryGetState(stateGroupsRoot, stateName, out group, out state) && this.GoToStateCore(null, stateGroupsRoot, stateName, group, state, useTransitions));
}
private static bool TryGetState(FrameworkElement element, string stateName, out VisualStateGroup group, out VisualState state)
{
group = null;
state = null;
foreach (VisualStateGroup group2 in VisualStateManager.GetVisualStateGroups(element))
{
foreach (VisualState state2 in group2.States)
{
if (state2.Name == stateName)
{
group = group2;
state = state2;
return true;
}
}
}
return false;
}
}
Then you will need to manually update the xaml to something like this -
<VisualStateManager.CustomVisualStateManager>
<common:ExtendedVisualStateManager />
</VisualStateManager.CustomVisualStateManager>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup .../>
</VisualStateManager.VisualStateGroups>
I guess the good thing about this solution is that you can still see the visual states in Blend's States tab, for Blend lovers this is just cool.
Typically I have a single UpdateVisualState(bool useTransitions)
method in my controls that makes all the GoToVisualState()
calls. If something can't be animated then I see two options:
- Make the change in code behind in my
UpdateVisualState()
method. The drawback of this solutions is that Blend will not show the change in the visual state editor. I don't personally care though because I rarely use Blend on already integrated designs and this solution is simple. - Create a(n attached) property or behavior that makes the expected change and animate that property from the visual state
Storyboard
. That's a bit more work, but could keep Blend support in your project.
来源:https://stackoverflow.com/questions/23697204/go-to-visual-states-inside-a-grid-in-code-behind-in-windows-store-apps