Custom VisualState not being set in WinRT XAML

风格不统一 提交于 2019-12-11 21:56:52

问题


I'm trying to create a custom textbox in WinRT XAML. I want the textbox to highlight red when there is an error with the entered data.

So first off I've modified the TextBox Temple and I've added a new VisualStateGroup (CustomStates - with HasError State) and I've also change the Focused group:

<Style TargetType="TextBox">
....
<VisualStateGroup x:Name="CommonStates">
    <VisualState x:Name="Focused">
        <Storyboard>
            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="BorderBrush">
                <DiscreteObjectKeyFrame KeyTime="0" Value="Blue" />
            </ObjectAnimationUsingKeyFrames>
            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="BorderThickness">
                <DiscreteObjectKeyFrame KeyTime="0" Value="2" />
            </ObjectAnimationUsingKeyFrames>
            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BackgroundElement" Storyboard.TargetProperty="Background">
                <DiscreteObjectKeyFrame KeyTime="0" Value="Blue" />
            </ObjectAnimationUsingKeyFrames>
            <DoubleAnimation Storyboard.TargetName="BackgroundElement" Storyboard.TargetProperty="Opacity" Duration="0" To="0.2" />
         </Storyboard>
     </VisualState>
 </VisualStateGroup>
    <VisualStateGroup x:Name="CustomStates">
         <VisualState x:Name="HasError">
             <Storyboard>
                 <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="BorderBrush">
                     <DiscreteObjectKeyFrame KeyTime="0" Value="Red" />
                 </ObjectAnimationUsingKeyFrames>
                 <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="BorderThickness">
                     <DiscreteObjectKeyFrame KeyTime="0" Value="2" />
                 </ObjectAnimationUsingKeyFrames>
                 <ObjectAnimationUsingKeyFrames  Storyboard.TargetName="BackgroundElement" Storyboard.TargetProperty="Background">
                     <DiscreteObjectKeyFrame KeyTime="0" Value="Red" />
                 </ObjectAnimationUsingKeyFrames>
                 <DoubleAnimation Storyboard.TargetName="BackgroundElement" Storyboard.TargetProperty="Opacity" Duration="0" To="0.2" />
             </Storyboard>
        </VisualState>
   </VisualStateGroup>
</Style>

So in C# code now I've created a custom TextBox class.

I've added a Dependency property call HasError which is just a bool to hold the error state. When this value changes the GoToState method is then called which sets the state to my HasError state.

I've added a delegate and event, which I use to validate if an error has happened.

Finally I've overridden the OnLostFocus and OnGotFocus methods. OnLostFocus call my delegate and OnGotFocus reset the error state

public class MyTextBox : TextBox
{
    public delegate void ValidateTextHandler(object sender, RoutedEventArgs e);

    public event ValidateTextHandler ValidateText = delegate { };

    public bool HasError
    {
        get { return (bool)GetValue(HasErrorProperty); }
        set { SetValue(HasErrorProperty, value); }
    }

    public static readonly DependencyProperty HasErrorProperty = DependencyProperty.Register("HasError", typeof(bool), typeof(MyTextBox), new  PropertyMetadata(false, HasErrorChangedCallback));

    private static void HasErrorChangedCallback(DependencyObject sender,  DependencyPropertyChangedEventArgs e)
    {
        MyTextBox textBox = sender as MyTextBox;

        textBox.GoToState(true);
    }

    void GoToState(bool useTransitions)
    {
        if (HasError)
        {                
            VisualStateManager.GoToState(this, "HasError", useTransitions);                
        }
    }

    protected override void OnGotFocus(RoutedEventArgs e)
    {
        HasError = false;
        base.OnGotFocus(e);
    }

    protected override void OnLostFocus(RoutedEventArgs e)
    {
        ValidateText(this, e);
        base.OnLostFocus(e);
    }
}

So, that's my textbox.

Now in the application I add an instance of a textbox to the form and subscribe to the ValidateText event and in that event just for testing I set the HasError property to true.

<MyTextBox x:Name="textTest" ValidateText="textTest_ValidateText" />

private void textTest_ValidateText(object sender, RoutedEventArgs e)
{
    textTest.HasError = true;
}        

So, now when I run this and the focus is lost from the textbox it is highlighted red which is just what I want. However, if I select the same textbox again and move the focus away again the HasError state isn't applied and the textBox just shows back in it's default view. The HasError code is running so I can't understand why the red error color isn't showing!??!?!

Anyway can anybody help? I hope it all makes sense.

This is a Windows 8 application using WinRT XAML and C#.


回答1:


You should not use two states from different groups to animate the same property. In this case, this is not working because you already are in the state HasError the second time (you never leave that state).

A solution is to add an extra state to your "CustomStates" group called "NoError".

Add visual element (such as an additional rectangle or border that only your state will animate). Then you'll have to trigger the NoError state from OnGoFocus override.



来源:https://stackoverflow.com/questions/19290301/custom-visualstate-not-being-set-in-winrt-xaml

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!