【问题标题】:How to fire TextChanged event on a Xamarin Forms entry field programmatically?如何以编程方式在 Xamarin Forms 输入字段上触发 TextChanged 事件?
【发布时间】:2021-03-30 08:55:41
【问题描述】:

我们已经为非空输入字段等设置了一些 Xamarin 行为,当用户对字段进行更改然后我们更改了输入边框颜色时会触发此行为,红色表示无效。

但是,我们还希望在点击提交按钮时重用此行为。

所以我需要手动触发TextChanged 事件,有什么想法可以做到这一点,现在确定是否可行?

public class NotEmptyEntryBehaviour : Behavior<Entry>
{
    protected override void OnAttachedTo(Entry bindable)
    {
        bindable.TextChanged += OnEntryTextChanged;
        base.OnAttachedTo(bindable);
    }

    protected override void OnDetachingFrom(Entry bindable)
    {
        bindable.TextChanged -= OnEntryTextChanged;
        base.OnDetachingFrom(bindable);
    }

    void OnEntryTextChanged(object sender, TextChangedEventArgs args)
    {
        if (args == null)
            return;

        var oldString = args.OldTextValue;
        var newString = args.NewTextValue;
    }
}

【问题讨论】:

    标签: c# xamarin xamarin.forms attachedbehaviors


    【解决方案1】:

    如果您想要一个替代方案,您可以使用Xamarin.CommunityToolkit package 附带的预构建验证行为之一,例如TextValidationBehavior(通过指定正则表达式)或更具体的派生行为(例如NumericValidationBehavior),可能满足您的需求,甚至通过子类化 ValidationBehavior 创建自定义。

    它允许您为有效和无效状态定义自定义样式,但更重要的问题是有一个名为 ForceValidate() 的异步方法。

    Flags 属性也可能很有趣。

    NotEmptyEntryBehaviour 似乎更接近 TextValidationBehaviorMinimumLenght=1

    xaml

     <Entry Placeholder="Type something..." x:Name="entry">
            <Entry.Behaviors>
                <xct:TextValidationBehavior Flags="ValidateOnValueChanging"
                                            InvalidStyle="{StaticResource InvalidEntryStyle}"
                                            ValidStyle="{StaticResource ValidEntryStyle}"/>
            </Entry.Behaviors>
        </Entry>
    

    代码

    await (entry.Behaviors[0] as TextValidationBehavior)?.ForceValidate();
    

    文档

    https://docs.microsoft.com/en-us/xamarin/community-toolkit/behaviors/charactersvalidationbehavior

    回购样本

    https://github.com/xamarin/XamarinCommunityToolkit/tree/main/samples/XCT.Sample/Pages/Behaviors

    编辑

    如果您想从 ViewModel 运行验证,您需要绑定 ForceValidateCommand,如 GitHub discussion/question 中所述。

    【讨论】:

      【解决方案2】:

      我们已经为非空输入字段等设置了一些 Xamarin 行为,当用户对字段进行更改并且我们更改了输入边框颜色时会触发此行为,红色表示无效。

      您可以创建具有要获取行为的自定义条目。

      我要做的第一件事是创建一个继承自 Entry 的新控件,并将添加三个属性:IsBorderErrorVisible、BorderErrorColor、ErrorText。

      public class ExtendedEntry : Entry
      {
          public static readonly BindableProperty IsBorderErrorVisibleProperty =
              BindableProperty.Create(nameof(IsBorderErrorVisible), typeof(bool), typeof(ExtendedEntry), false, BindingMode.TwoWay);
      
          public bool IsBorderErrorVisible
          {
              get { return (bool)GetValue(IsBorderErrorVisibleProperty); }
              set
              {
                  SetValue(IsBorderErrorVisibleProperty, value);
              }
          }
      
          public static readonly BindableProperty BorderErrorColorProperty =
              BindableProperty.Create(nameof(BorderErrorColor), typeof(Xamarin.Forms.Color), typeof(ExtendedEntry), Xamarin.Forms.Color.Transparent, BindingMode.TwoWay);
      
          public Xamarin.Forms.Color BorderErrorColor
          {
              get { return (Xamarin.Forms.Color)GetValue(BorderErrorColorProperty); }
              set
              {
                  SetValue(BorderErrorColorProperty, value);
              }
          }
      
          public static readonly BindableProperty ErrorTextProperty =
          BindableProperty.Create(nameof(ErrorText), typeof(string), typeof(ExtendedEntry), string.Empty);
      
          public string ErrorText
          {
              get { return (string)GetValue(ErrorTextProperty); }
              set
              {
                  SetValue(ErrorTextProperty, value);
              }
          }
      }
      

      然后创建自定义渲染到 android 平台。

      [assembly: ExportRenderer(typeof(ExtendedEntry), typeof(ExtendedEntryRenderer))]
      namespace FormsSample.Droid
      {
      public class ExtendedEntryRenderer : EntryRenderer
      {
          public ExtendedEntryRenderer(Context context) : base(context)
          {
          }
          protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
          {
              base.OnElementChanged(e);
      
              if (Control == null || e.NewElement == null) return;
      
              UpdateBorders();
          }
      
          protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
          {
              base.OnElementPropertyChanged(sender, e);
      
              if (Control == null) return;
      
              if (e.PropertyName == ExtendedEntry.IsBorderErrorVisibleProperty.PropertyName)
                  UpdateBorders();
          }
      
          void UpdateBorders()
          {
              GradientDrawable shape = new GradientDrawable();
              shape.SetShape(ShapeType.Rectangle);
              shape.SetCornerRadius(0);
      
              if (((ExtendedEntry)this.Element).IsBorderErrorVisible)
              {
                  shape.SetStroke(3, ((ExtendedEntry)this.Element).BorderErrorColor.ToAndroid());
              }
              else
              {
                  shape.SetStroke(3, Android.Graphics.Color.LightGray);
                  this.Control.SetBackground(shape);
              }
      
              this.Control.SetBackground(shape);
          }
      
      }
      

      }

      最后,创建一个入口行为,处理错误以在验证发生时向用户提供 ui 反馈

       public class EmptyEntryValidatorBehavior : Behavior<ExtendedEntry>
      {
          ExtendedEntry control;
          string _placeHolder;
          Xamarin.Forms.Color _placeHolderColor;
      
          protected override void OnAttachedTo(ExtendedEntry bindable)
          {
              bindable.TextChanged += HandleTextChanged;
              bindable.PropertyChanged += OnPropertyChanged;
              control = bindable;
              _placeHolder = bindable.Placeholder;
              _placeHolderColor = bindable.PlaceholderColor;
          }
      
          void HandleTextChanged(object sender, TextChangedEventArgs e)
          {
              ExtendedEntry customentry = (ExtendedEntry)sender;
              if (!string.IsNullOrEmpty(customentry.Text))
              {
                  ((ExtendedEntry)sender).IsBorderErrorVisible = false;
              }
              else
              {
                  ((ExtendedEntry)sender).IsBorderErrorVisible = true;
              }
            
          }
      
          protected override void OnDetachingFrom(ExtendedEntry bindable)
          {
              bindable.TextChanged -= HandleTextChanged;
              bindable.PropertyChanged -= OnPropertyChanged;
          }
      
          void OnPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
          {
              if (e.PropertyName == ExtendedEntry.IsBorderErrorVisibleProperty.PropertyName && control != null)
              {
                  if (control.IsBorderErrorVisible)
                  {
                      control.Placeholder = control.ErrorText;
                      control.PlaceholderColor = control.BorderErrorColor;
                      control.Text = string.Empty;
                  }
      
                  else
                  {
                      control.Placeholder = _placeHolder;
                      control.PlaceholderColor = _placeHolderColor;
                  }
      
              }
          }
      }
      

      更新:

      您可以在 button.click 中更改自定义条目的 IsBorderErrorVisible,以从提交按钮调用它。

       private void btn1_Clicked(object sender, EventArgs e)
          {
             
              if(string.IsNullOrEmpty(entry1.Text))
              {
                  entry1.IsBorderErrorVisible = true;
              }
          }
      
      <customentry:ExtendedEntry
                  x:Name="entry1"
                  BorderErrorColor="Red"
                  ErrorText="please enter name!">
                  <customentry:ExtendedEntry.Behaviors>
                      <behaviors:EmptyEntryValidatorBehavior />
                  </customentry:ExtendedEntry.Behaviors>
              </customentry:ExtendedEntry>
      

      【讨论】:

      • 谢谢你,但是如果他们没有触及输入字段,我如何从提交按钮调用它?
      • 再次感谢,在对我的问题的初步评论之后,我抽象了我的验证检查并将边框颜色设置为一个新类,每次检查一个方法。然后我有一个 IsValid 扩展方法,它循环所有行为并运行我的验证检查,我在我的视图中使用它。这样,在我看来,我不必知道在控制基础上使用了什么验证。这是迄今为止我在这里看到的最好的解决方案。但我宁愿能够调用行为而不是使用验证方法。
      • @Jules 感谢您在这里分享您的解决方案,我的回复对您有帮助吗?
      猜你喜欢
      • 1970-01-01
      • 2022-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-09
      • 1970-01-01
      • 2022-11-12
      • 1970-01-01
      相关资源
      最近更新 更多