为什么 VisualStateManager.GoToState 不能处理 WPF 中的控件?

Why doesn't VisualStateManager.GoToState work on a control in WPF?

我正在开发一个 WPF 应用程序,并尝试使用 Visual State Manager 制作响应式 UI,正如 MSDN 建议的 UWP 响应式设计,它适用于 UWP 但不适用于 WPF。

这是我在 WPF 上测试的示例。它应该在启动时将 StackPanel 的背景更改为 Red

XAML:

<Grid>
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup>
            <VisualState x:Name="DefaultState">
                <Storyboard>

                </Storyboard>
            </VisualState>

            <VisualState x:Name="WideState">
                <Storyboard >
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Menu" Storyboard.TargetProperty="StackPanel.Background">
                        <DiscreteObjectKeyFrame KeyTime="0" Value="Red"/>
                    </ObjectAnimationUsingKeyFrames>
                </Storyboard>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>

    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>

    <Grid.RowDefinitions>
        <RowDefinition Height="25"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="25"/>
    </Grid.RowDefinitions>

    <Grid x:Name="StackPanelCenetrofPage" Grid.Row="1">
        <Grid.ColumnDefinitions>
            <ColumnDefinition x:Name="MenuColumnWidth" Width="200"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <StackPanel x:Name="Menu"
                    Orientation="Vertical"
                    Background="AliceBlue"
                    HorizontalAlignment="Stretch"
                    Grid.Column="0">
            <Button Content="Hey"/>
        </StackPanel>
        <Frame Grid.Column="1"/>
    </Grid>
</Grid>

C# 代码:

private void Window_SizeChanged(object sender, SizeChangedEventArgs e) 
{
    if (e.PreviousSize.Width < 1024) 
    {
        VisualStateManager.GoToState(this, "WideState", true);
    }
    else 
    {
        VisualStateManager.GoToState(this, "DefaultState", false);
    }
}

根据 documentation:

Call the GoToState method if you are changing states in a control that uses the VisualStateManager in its ControlTemplate. Call the GoToElementState method to change states on an element outside of a ControlTemplate (for example, if you use a VisualStateManager in a UserControl or in a single element).

所以你应该使用 GoToElementState 而不是 GoToStateGoToElementState 的第一个参数是拥有 VisualStateManager 的控件,因此您应该将 VisualStateManager 移动到 Window 以继续在代码隐藏中使用 this

private void Window_SizeChanged(object sender, SizeChangedEventArgs e) {
    if (e.PreviousSize.Width < 1024) {
        var result = VisualStateManager.GoToElementState(this, "WideState", true); // <- Here
    } else {
        VisualStateManager.GoToElementState(this, "DefaultState", false);
    }
}

附带说明一下,您不能像这样为 Background 设置动画。您需要定义 ValueBrush 而不仅仅是 Color:

<DiscreteObjectKeyFrame KeyTime="0">
    <DiscreteObjectKeyFrame.Value>
        <SolidColorBrush Color="Red"/>
    </DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>