【问题标题】:UWP VisualStateManager.GoToState Always Returns FalseUWP VisualStateManager.GoToState 始终返回 False
【发布时间】:2021-07-22 03:24:18
【问题描述】:

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

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,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”控件上,正如预期的那样。

我见过几个解决方案,包括herehere,它们建议将XAML 中的&lt;VisualStateManager.VisualStateGroups&gt; 标记移到TextBox 之外,或者移到Page 的根目录。两者都没有为我工作。

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

【问题讨论】:

    标签: c# validation xaml uwp visualstatemanager


    【解决方案1】:

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

    Xaml 代码:

    <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,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, "Invalid", false);         
        }
    

    更新:

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

    您可以在 XAML 设计器中右键单击文本框,然后选择选项Edit a Template->Edit a Copy,您将看到默认的文本框样式放置在&lt;Page.Resources&gt; &lt;/Page.Resources&gt; 标签。

    <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);”跳过状态。

    【讨论】:

    • 我试过这个,但它不起作用。 VisualStateManager.GoToState() 仍然返回 false。同样值得注意的是,我在尝试此操作时发现,&lt;VisualStateManager.VisualStateGroups&gt; 标记必须位于 &lt;StackPanel&gt; 标记的所有子标记之前,否则 XAML 将无法编译。
    • 如果不行,可以换一种方式,建议换个样式。我已经更新了我的答案,你可以关注它。
    猜你喜欢
    • 1970-01-01
    • 2017-11-18
    • 1970-01-01
    • 2011-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多