A two-way entry that supports base types and zero-value types

I am trying to achieve perfect MVVM in Xamarin.Forms with a record.

My model contains properties whose type includes a string, int ?, decimal ?, bool ?, etc. Whenever I bind to a string type, two-way binding works because the text property has a string type (they match). But as soon as you try to bind yourself to the model, and the property is int or int ?, it does not update the value of the model property.

During my research and using Xamarin support, this was a very useful question on how to handle NULL types:

Nullable type in x: TypeArguments

XAML Code:

<controls:NullableIntEntry Grid.Column="1" Grid.Row="14" NumericText="{Binding BusinessOwnership, Mode=TwoWay}" x:Name="lblBusinessOwnership"></controls:NullableIntEntry>
Run codeHide result

BindableEntry (extension code):

using System;
using System.Collections;
using System.Collections.Specialized;
using System.Reflection;
using Xamarin.Forms;

namespace CreditBuilderApp.Controls
{
    public class BindableEntry<T> : Entry
    {
        static bool firstLoad;

        public static readonly BindableProperty NumericTextProperty =
            BindableProperty.Create("NumericText", typeof(T), typeof(BindableEntry<T>),
                null, BindingMode.TwoWay, propertyChanged: OnNumericTextChanged);

        static void OnNumericTextChanged(BindableObject bindable, object oldValue, object newValue)
        {
            var boundEntry = (BindableEntry<T>)bindable;
            if (firstLoad && newValue != null)
            {
                firstLoad = false;
                boundEntry.Text = newValue.ToString();
            }
        }

        public T NumericText
        {
            get { return (T)GetValue(NumericTextProperty); }
            set { SetValue(NumericTextProperty, value); }
        }

        public BindableEntry()
        {
            firstLoad = true;
            this.TextChanged += BindableEntry_TextChanged;
        }

        private void BindableEntry_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (!String.IsNullOrEmpty(e.NewTextValue))
            {
                this.NumericText = (T)Convert.ChangeType(e.NewTextValue, typeof(T));
            }
            else
            {
                this.NumericText = default(T);
            }
        }
    }
}
Run codeHide result

NullableIntEntry and NullableDecimalEntry (Bindable Entry extension indicating the type):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CreditBuilderApp.Controls
{
    public class NullableIntEntry : BindableEntry<Int32?>
    {

    }

    public class NullableDecimalEntry : BindableEntry<Decimal?>
    {

    }
}
Run codeHide result

Model:

      private int? _businessOwnership { get; set; }
        public int? BusinessOwnership
        {
            get { return _businessOwnership; }
            set
            {
                if (_businessOwnership != value)
                {
                    _businessOwnership = value;
                    RaisePropertyChanged();
                }
            }
        }
Run codeHide result

, , , , , . , BindableEntry , . ( T int?, T .. ALONG, , e.NewTextValue.

: .

this.NumericText = (T)Convert.ChangeType(e.NewTextValue, typeof(T));
Hide result

(), this.NumericText T .

, , , T int? AS WELL AS :

Convert.ToInt32(e.NewTextValue)
Hide result

, , Convert.ChangeType T, . , , .

ConvertType

, - . !

+4
2

, , , . , :

BindableEntry ( ):

BindableEntry_TextChanged ( , TextChangedEventArgs e)

    private void BindableEntry_TextChanged(object sender, TextChangedEventArgs e)
    {
        if (!string.IsNullOrEmpty(e.NewTextValue))
        {
            var t = typeof(T);
            t = Nullable.GetUnderlyingType(t);

            if (typeof(T) == typeof(decimal?))
            {
                var results = decimal.TryParse(e.NewTextValue, out var tmpValue) ?
                    tmpValue : (decimal?) null;

                if (results != null)
                    NumericText = (T)Convert.ChangeType(results, t);
                else
                    NumericText = default(T);
            }
            else if (typeof(T) == typeof(double?))
            {
                var results = double.TryParse(e.NewTextValue, out var tmpValue) ?
                    tmpValue : (double?)null;

                if (results != null)
                    NumericText = (T)Convert.ChangeType(results, t);
                else
                    NumericText = default(T);
            }
            else if (typeof(T) == typeof(int?))
            {
                var results = int.TryParse(e.NewTextValue, out var tmpValue) ?
                    tmpValue : (int?)null;

                if (results != null)
                    NumericText = (T)Convert.ChangeType(results, t);
                else
                    NumericText = default(T);
            }
        }
        else
        {
            NumericText = default(T);
        }
    }

, . , ...

0

Source: https://habr.com/ru/post/1658270/


All Articles