UWP VisualStateManager.GoToState 始终返回 False

问题描述

用户提交文本框所属的表单时,我试图在输入验证期间使用视觉状态将文本框输入标记为无效(通过将其边框颜色更改为红色)。我有以下代码

XAML

<Page.Resources>

    <!-- Other resources omitted for brevity -->

    <Flyout x:Key="NewTimeBlockFlyout">
        <StackPanel>

            <!-- Other stuff here omitted for brevity -->

            <TextBox Margin="5"
                     Header="Name"
                     x:Name="NewTimeBlockNameTextBox">
                <visualstatemanager.VisualStateGroups>
                    <VisualStateGroup>
                        <VisualState x:Name="Default"></VisualState>
                        <VisualState x:Name="Invalid">
                            <VisualState.Setters>
                                <Setter Target="NewTimeBlockNameTextBox.Background" Value="Red"></Setter>
                            </VisualState.Setters>
                        </VisualState>
                   </VisualStateGroup>
               </visualstatemanager.VisualStateGroups>
            </TextBox>

        <!-- The rest of the form omitted for brevity -->

        <Button x:Name="CreateTimeBlockButton"
                Grid.Column="0"
                Margin="0,2,0"
                HorizontalAlignment="Stretch"
                Tapped="CreateTimeBlockButton_Tapped">Create</Button>
        </StackPanel>
    </Flyout>
</Page.Resources>

注意:这是在 XAML Page 上。我没有使用自定义控件。

C#

private void CreateTimeBlockButton_Tapped(object sender,TappedRoutedEventArgs e)
{
    // Validate the input.
    if (String.IsNullOrWhiteSpace(this.NewTimeBlockNameTextBox.Text))
    {
        // These two lines of code confirm the visual state named "Invalid" does exist on the textBox.
        //List<VisualStateGroup> m = visualstatemanager.GetVisualStateGroups(this.NewTimeBlockNameTextBox).ToList();
        //List<VisualState> c = m.FirstOrDefault().States.ToList();

        // Assignment to bool just used to inspect the return value for debugging.
        bool did = visualstatemanager.GoToState(this.NewTimeBlockNameTextBox,"Invalid",false);
    }
}

问题

无论我尝试什么,对 visualstatemanager.GoToState()调用总是返回 false。

我尝试过的事情:

这是relevant documentation from Microsoft

如上面的 C# 代码所示,我已经验证了“NewTimeBlockNameTextBox”控件上的视觉状态“Invalid”确实存在,正如预期的那样。

我已经看到了几种解决方案,包括 herehere,它们建议将 XAML 中的 <visualstatemanager.VisualStateGroups> 标记移到 TextBox 的外部,或者移到Page。两者都不适合我。

我也看过这两个解决方herehere,但似乎都与我的情况无关,因为两者似乎都与我没有做的事情有关。

解决方法

我可以重现您的问题。您需要将 <VisualStateManager.VisualStateGroups> 放在 TextBox 之外并通过 VisualStateManager.GoToState(this,"Invalid",false); 跳过状态,请参考以下代码。

XML 代码:

<Page
   ……
   Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <StackPanel>
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup>
                <VisualState x:Name="Default"></VisualState>
                <VisualState x:Name="Invalid">
                    <VisualState.Setters>
                        <Setter Target="NewTimeBlockNameTextBox.BorderBrush" Value="Red"></Setter>
                    </VisualState.Setters>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>

        <TextBox  Margin="5"
                     Header="Name"
                     x:Name="NewTimeBlockNameTextBox" >
        </TextBox>       
     
            <Button x:Name="CreateTimeBlockButton"
                Grid.Row="1"
                Margin="0,2,0"
                HorizontalAlignment="Stretch"
                Tapped="CreateTimeBlockButton_Tapped">Create</Button>

        </StackPanel>
</Page>

背后的代码:

   private void CreateTimeBlockButton_Tapped(object sender,TappedRoutedEventArgs e)
    {                         
        bool a = VisualStateManager.GoToState(this,false);         
    }

更新:

用于使用 VisualStateManager.GoToState(),这总是通过更改其控制模板来完成。

您可以在 XAML 设计器中右键单击文本框,然后选择选项编辑模板->编辑副本,在这里您将看到默认的文本框样式放置在<Page.Resources> </Page.Resources> 标签。

<Style x:Key="TextBoxStyle1" TargetType="TextBox">
……
<Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="TextBox">
                    ……
                           <VisualStateManager.VisualStateGroups>
……
                             <VisualState x:Name="TestState">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="BorderBrush">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="red"/>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <ContentPresenter x:Name="HeaderContentPresenter" …/>
<Border x:Name="BorderElement" …/>
……
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
  </Style>

如您所见,您可以在其模板中放置自定义状态,然后您可以使用“VisualStateManager.GoToState(NewTimeBlockNameTextBox,"TestState",false);”来跳过状态。