问题描述
当用户提交文本框所属的表单时,我试图在输入验证期间使用视觉状态将文本框输入标记为无效(通过将其边框颜色更改为红色)。我有以下代码:
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”确实存在,正如预期的那样。
我已经看到了几种解决方案,包括 here 和 here,它们建议将 XAML 中的 <visualstatemanager.VisualStateGroups>
标记移到 TextBox
的外部,或者移到Page
。两者都不适合我。
我也看过这两个解决方案 here 和 here,但似乎都与我的情况无关,因为两者似乎都与我没有做的事情有关。
解决方法
我可以重现您的问题。您需要将 <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);
”来跳过状态。