문제

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#.

도움이 되었습니까?

해결책

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.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top