Change VisualState through Dependency Property (UWP)

∥☆過路亽.° 提交于 2020-05-17 07:09:05

问题


I have a textbox inside a UserControl, I want to have two extra states for that textbox, Valid and Invalid. My code looks like this

<UserControl.Resources>
    <Style TargetType="TextBox" x:Key="ExtendeTextBoxStyle">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="TextBox">
                    <Grid>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="ValidationState">
                                <VisualState x:Name="InvalidState">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement"
                                                                           Storyboard.TargetProperty="Stroke">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="Red" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="ValidState"></VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="Auto" />
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="Auto" />
                        </Grid.RowDefinitions>
                        <TextBlock Grid.Row="0" Text="{TemplateBinding PlaceholderText}" Visibility="Collapsed" x:Name="HeaderText" Foreground="{ThemeResource ColorCompany}" ></TextBlock>
                        <Border x:Name="BackgroundElement"
                            Grid.Row="2"
                            Background="{TemplateBinding Background}"
                            Margin="{TemplateBinding BorderThickness}"
                            Grid.ColumnSpan="2"
                            Grid.RowSpan="1"/>
                        <Line  x:Name="BorderElement" Stroke="{ThemeResource ColorCompany}" X2="10000"  Grid.Row="3" Grid.ColumnSpan="2" 
                                      StrokeThickness="{ThemeResource TextBoxStrokeThickness}"   />
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</UserControl.Resources>
<Grid>
    <TextBox x:Name="txtbox"  Width="438" Height="56" Style="{StaticResource ExtendeTextBoxStyle}"
                 PlaceholderText="{x:Bind PlaceholderText, Mode=OneWay}" ></TextBox>
</Grid>

And in code-behind

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

        /// <summary>
        /// This is a dependency property that will indicate if there's an error. 
        /// This DP can be bound to a property of the VM.
        /// </summary>
        public static readonly DependencyProperty HasErrorProperty =
            DependencyProperty.RegisterAttached("HasError", typeof(bool), typeof(EditTextControl), new PropertyMetadata(false, HasErrorUpdated));

        // This method will update the Validation visual state which will be defined later in the Style
        private static void HasErrorUpdated(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {

            EditTextControl textBox = d as EditTextControl;

            Grid sds = textBox.Content as Grid;
            var mytxt = sds.Children.FirstOrDefault() as TextBox;

            if (textBox != null)
            {
                if (textBox.HasError)
                    VisualStateManager.GoToState(mytxt, "InvalidState", false);
                else
                    VisualStateManager.GoToState(mytxt, "ValidState", false);
            }
        }

And I am calling this usercontrol inside my page like this

  <editors1:EditTextControl HasError="{x:Bind HasError, Mode=OneWay}"></editors1:EditTextControl>

On debugger, I can see that this line gets executed VisualStateManager.GoToState(mytxt, "InvalidState", false); But the visual state never changes and Red color never comes for that line. Can anyone please point out what I am missing?


回答1:


I checked your code, there is nothing wrong with your control itself, the problem lies in the assignment timing of the HasError variable in the MainPage:

Try this:

Xaml

<Grid>
    <editors1:EditTextControl HasError="{x:Bind HasError, Mode=OneWay}"
                              Loaded="EditTextControl_Loaded"/>
</Grid>

Xaml.cs

public sealed partial class MainPage : Page,INotifyPropertyChanged
{
    private bool _hasError;
    public bool HasError
    {
        get => _hasError;
        set
        {
            _hasError = value;
            OnPropertyChanged();
        }
    }

    public MainPage()
    {
        this.InitializeComponent();
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged([CallerMemberName]string name = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }

    private void EditTextControl_Loaded(object sender, RoutedEventArgs e)
    {
        HasError = true;
    }
}

First, HasError defaults to false when no value is assigned. You can manually change its value, but you need to notify the UI after the change. This requires the parent class inheriting the INotifyPropertyChanged interface and calling the OnPropertyChanged method when modifying the data.

Secondly, changing the value of HasError should be done when ensuring that the control has been loaded, otherwise although you have changed the value, but the control has not been loaded, this property change is invalid.

Thanks.



来源:https://stackoverflow.com/questions/61570182/change-visualstate-through-dependency-property-uwp

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