luismts / ValidationRulesPlugin

Create and validate property rules for all your Xamarin and Windows apps and improve the quality of your data.
https://luismts.com/
MIT License
68 stars 26 forks source link

Create a xamarin view which takes a ValidatableObject #3

Closed dalton5 closed 5 years ago

dalton5 commented 5 years ago

Hi,

I try to create a xamarin view to fill a bindable property Validation which is av ValidatableObject

But it's not working. The Validation.Value object is always null. What is wrong?

Thanks,

My code is below:

Account Model

` public ValidatableObject Password { get; set; } public ValidatableObject Email { get; set; }

    public Account()
    {
        Password = new ValidatableObject<string>();
        Email = new ValidatableObject<string>();
    }

    private void AddValidations()
    {
        // Email validations
        Email.Validations.Add(new IsNotNullOrEmptyRule<string> { ValidationMessage = C.T("Email is required.") });
        Email.Validations.Add(new EmailRule<string> { ValidationMessage = C.T("Email is not valid.") });

        //Password validations
        Password.Validations.Add(new IsNotNullOrEmptyRule<string> { ValidationMessage = C.T("A password is required.") });
        Password.Validations.Add(new LengthMinRule<string> { ValidationMessage = C.T("A password is required."), MinLength = 6 });
    }`

My call in my login page <local:FormEntry Validation="{Binding AccountInfo.Email}" Grid.Row="2" />

My FormEntry Xaml

`

</ContentView.Resources>

<ContentView.Content>
    <!--<border:SfBorder  Grid.Row="2"
            Style="{DynamicResource SfBorderStyle}"
            BorderColor="{Binding Source={x:Reference emailEntry}, Path=IsFocused, Converter={StaticResource errorValidationColorConverter}, ConverterParameter={x:Reference emailEntry}}">-->

    <inputLayout:SfTextInputLayout x:Name="Input"  LeadingViewPosition="Outside" TrailingViewPosition="Outside" ContainerType="None">
        <Entry TextChanged="Entry_TextChanged" x:Name="entry"

                    Placeholder="Email">
        </Entry>
        <inputLayout:SfTextInputLayout.LeadingView>
            <Label
       Text="&#xf007;"  FontFamily="{StaticResource FontAwesomeSolid}">
            </Label>
        </inputLayout:SfTextInputLayout.LeadingView>
        <inputLayout:SfTextInputLayout.TrailingView>
            <Label
      x:Name="LabelError"
                    Text="&#xf06a;"
                    FontFamily="{StaticResource FontAwesomeSolid}"
                    TextColor="{DynamicResource ErrorColor}"
                    FontSize="22">
            </Label>
        </inputLayout:SfTextInputLayout.TrailingView>
    </inputLayout:SfTextInputLayout>
    <!--</border:SfBorder>-->
</ContentView.Content>`

My FormEntry cs

` public FormEntry() { InitializeComponent(); }

    public ICommand ValidateUserNameCommand => new Command(() => ValidateField());

    private bool ValidateField()
    {
        return Validation.Validate();
    }

    public static readonly BindableProperty ValidationProperty = BindableProperty.Create(
propertyName: "Validation",
returnType: typeof(ValidatableObject<string>),
declaringType: typeof(FormEntry),
defaultValue: default(ValidatableObject<string>));

public ValidatableObject Validation { get { return (ValidatableObject)GetValue(ValidationProperty); } set { SetValue(ValidationProperty, value); } }

    protected override void OnPropertyChanged(string propertyName = null)
    {
        base.OnPropertyChanged(propertyName);
        //if (propertyName == ErrorProperty.PropertyName)
        //{
        //    Input.ErrorText = Error;
        //}
        //else if (propertyName == IsValidProperty.PropertyName)
        //{
        //    Input.HasError = Text;
        //}

        if (propertyName == ValidationProperty.PropertyName)
        {
            Input.ErrorText = Validation.Error;
            Input.HasError = Validation.Validate();
            entry.Text = Validation.Value;
            LabelError.IsVisible = Input.HasError;
        }
    }

    private void Entry_TextChanged(object sender, TextChangedEventArgs e)
    {
        ValidateField();
    }
}`
luismts commented 5 years ago

Ok, you have this:

Hi,

I try to create a xamarin view to fill a bindable property Validation which is av ValidatableObject

But it's not working. The Validation.Value object is always null. What is wrong?

Thanks,

My code is below:

Account Model

public ValidatableObject Email { get; set; }

    public Account()
    {
        Password = new ValidatableObject<string>();
        Email = new ValidatableObject<string>();
    }

    private void AddValidations()
    {
        // Email validations
        Email.Validations.Add(new IsNotNullOrEmptyRule<string> { ValidationMessage = C.T("Email is required.") });
        Email.Validations.Add(new EmailRule<string> { ValidationMessage = C.T("Email is not valid.") });

        //Password validations
        Password.Validations.Add(new IsNotNullOrEmptyRule<string> { ValidationMessage = C.T("A password is required.") });
        Password.Validations.Add(new LengthMinRule<string> { ValidationMessage = C.T("A password is required."), MinLength = 6 });
    }`

My call in my login page <local:FormEntry Validation="{Binding AccountInfo.Email}" Grid.Row="2" />

My FormEntry Xaml


<converter:ErrorValidationColorConverter x:Key="errorValidationColorConverter" />
<ResourceDictionary.MergedDictionaries>

</ResourceDictionary.MergedDictionaries>

</ContentView.Resources>

<ContentView.Content>

    <inputLayout:SfTextInputLayout x:Name="Input"  LeadingViewPosition="Outside" TrailingViewPosition="Outside" ContainerType="None">
        <Entry TextChanged="Entry_TextChanged" x:Name="entry"

                    Placeholder="Email">
        </Entry>
        <inputLayout:SfTextInputLayout.LeadingView>
            <Label
       Text="&#xf007;"  FontFamily="{StaticResource FontAwesomeSolid}">
            </Label>
        </inputLayout:SfTextInputLayout.LeadingView>
        <inputLayout:SfTextInputLayout.TrailingView>
            <Label
      x:Name="LabelError"
                    Text="&#xf06a;"
                    FontFamily="{StaticResource FontAwesomeSolid}"
                    TextColor="{DynamicResource ErrorColor}"
                    FontSize="22">
            </Label>
        </inputLayout:SfTextInputLayout.TrailingView>
    </inputLayout:SfTextInputLayout>
    <!--</border:SfBorder>-->
</ContentView.Content>`

My FormEntry cs

{
         InitializeComponent();
}

    public ICommand ValidateUserNameCommand => new Command(() => ValidateField());

    private bool ValidateField()
    {
        return Validation.Validate();
    }

    public static readonly BindableProperty ValidationProperty = BindableProperty.Create(
propertyName: "Validation",
returnType: typeof(ValidatableObject<string>),
declaringType: typeof(FormEntry),
defaultValue: default(ValidatableObject<string>));

public ValidatableObject Validation
{
        get
         {
                  return (ValidatableObject)GetValue(ValidationProperty);
         }
         set
         {
                  SetValue(ValidationProperty, value);
         }
}

    protected override void OnPropertyChanged(string propertyName = null)
    {
        base.OnPropertyChanged(propertyName);

        if (propertyName == ValidationProperty.PropertyName)
        {
            Input.ErrorText = Validation.Error;
            Input.HasError = Validation.Validate();
            entry.Text = Validation.Value;
            LabelError.IsVisible = Input.HasError;
        }
    }

    private void Entry_TextChanged(object sender, TextChangedEventArgs e)
    {
        ValidateField();
    }
}
luismts commented 5 years ago
  1. You are trying to implement PropertyChanged in your code behind when it needs to be in your ViewModel.

  2. ValidatableObject already implements PropertyChanged for you.

  3. You are implementing ICommand property in your code behind when it needs to be in your ViewModel.

  4. In your code below you never show your binding context connection.

  5. Etc, etc, etc...

I really recommend you to see the MVVM pattern to make good practice and can understand your code easily. Your problem is not the plugin, it's your implementation. So, this thread is going to be close.