Xamarin.Forms条目 - 自定义行为和MVVM

时间:2017-03-23 14:48:43

标签: c# validation mvvm xamarin.forms

我想为我的Xamarin Forms项目添加一些验证。这些是一些非常基本的,如:

  • 最小/最大字符串长度
  • 电子邮件格式
  • 密码确认

我在我的项目中使用MVVM Light,因此,我没有在我的页面中使用代码。

我正在使用下面的代码,尝试将行为的值绑定到我的ViewModel中的属性。

EmailValidatorBehavior.cs:

public class EmailValidatorBehavior : Behavior<Entry>
    {
        const string emailRegex = @"^(?("")("".+?(?<!\\)""@)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-z])@))" +
            @"(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-\w]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9]))$";

        public static readonly BindablePropertyKey IsValidPropertyKey = BindableProperty.CreateReadOnly("IsValid", typeof(bool), typeof(EmailValidatorBehavior), false);

        public static readonly BindableProperty IsValidProperty = IsValidPropertyKey.BindableProperty;

        public bool IsValid
        {
            get { return (bool)base.GetValue(IsValidProperty); }
            private set { base.SetValue(IsValidPropertyKey, value); }
        }

        protected override void OnAttachedTo(Entry bindable)
        {
            bindable.TextChanged += HandleTextChanged;
        }

        void HandleTextChanged(object sender, TextChangedEventArgs e)
        {
            IsValid = (Regex.IsMatch(e.NewTextValue, emailRegex, RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(250)));
            ((Entry)sender).TextColor = IsValid ? Color.Default : Color.Red;
        }

        protected override void OnDetachingFrom(Entry bindable)
        {
            bindable.TextChanged -= HandleTextChanged;

        }
    }

View.xaml:

<Entry 
    Placeholder="E-mail"
    Text="{Binding Path=User.email, Mode=TwoWay}"
    Keyboard="Email">

    <Entry.Behaviors>
        <EmailValidatorBehavior x:Name="emailValidator" IsValid="{Binding Path=IsEmailValid, Mode=TwoWay}" />
    </Entry.Behaviors>
</Entry>

ViewModel.cs:

private bool _IsEmailValid = false;
public bool IsEmailValid
{
    get
    {
        return _IsEmailValid;
    }
    set
    {
        _IsEmailValid = value;
        RaisePropertyChanged("IsEmailValid");
    }
}

即使电子邮件正确且行为的IsValid属性变为true,IsEmailValid的值也不会更改。可能有什么不对?

提前致谢。

2 个答案:

答案 0 :(得分:3)

除了您的xaml本地行为附件之外,您似乎已正确设置了所有内容。您需要更改以下内容:

原始示例

<EmailValidatorBehavior x:Name="emailValidator" IsValid="{Binding Path=IsEmailValid, Mode=TwoWay}" />

更新代码

  <Entry Placeholder="testing">
      <Entry.Behaviors>
          <local:EmailValidatorBehavior></local:EmailValidatorBehavior>
      </Entry.Behaviors>
  </Entry>

<强>输出
我在本例中使用了您的自定义行为,一切正常。左侧显示IsValid = false,右侧显示IsValid = true

Example output

如果您对此有任何疑问,请告诉我。干杯!

答案 1 :(得分:1)

我也遇到了这个问题而且我找不到令人满意的答案,但似乎行为中的BindingContext未设置为页面BindingContext

由于我不是这方面的专家,我认为会有更优雅的方式,但是;这似乎有效:

首先,将您的页面命名为以后用作参考:

<ContentPage x:Name="Root" etc, etc>

然后,在您的行为中:将路径和来源设置为页面的绑定上下文:

<Entry Text="{Binding RegistrationEmail}">
    <Entry.Behaviors>
         <connector:EmailValidatorBehavior 
            IsValid="{Binding Source={x:Reference Root}, 
                      Path=BindingContext.IsRegistrationEmailValid, Mode=OneWayToSource}"/>
    </Entry.Behaviors>        
</Entry>

顺便说一句,我认为使用Mode=OneWayToSource更合适,因为您的可绑定属性是只读的。

在viewmodel中设置断点时,您将看到布尔值已更新。