Изменить VisualState через свойство зависимости (UWP) - PullRequest
0 голосов
/ 03 мая 2020

У меня есть текстовое поле внутри UserControl, я хочу иметь два дополнительных состояния для этого текстового поля, Действительный и Недействительный. Мой код выглядит следующим образом

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

И в коде позади

  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);
            }
        }

И я вызываю этот usercontrol внутри моей страницы вот так

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

В отладчике Я вижу, что эта строка выполняется VisualStateManager.GoToState(mytxt, "InvalidState", false); Но визуальное состояние никогда не меняется, и красный цвет никогда не приходит для этой строки. Кто-нибудь может указать, что мне не хватает?

1 Ответ

1 голос
/ 04 мая 2020

Я проверил ваш код, нет ничего плохого в самом вашем элементе управления, проблема заключается в синхронизации назначения переменной HasError в MainPage:

Попробуйте это:

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;
    }
}

Сначала HasError по умолчанию имеет значение false, если значение не назначено. Вы можете вручную изменить его значение, но вам нужно уведомить пользовательский интерфейс после изменения. Для этого требуется, чтобы родительский класс наследовал интерфейс INotifyPropertyChanged и вызывал метод OnPropertyChanged при изменении данных.

Во-вторых, изменение значения HasError должно выполняться при обеспечении загрузки элемента управления, в противном случае, хотя вы изменили значение, но элемент управления не был загружен, это изменение свойства недопустимо.

Спасибо.

...