Как измениться, когда привязка данных (обратно к источнику) происходит в формах Xamarin? - PullRequest
1 голос
/ 03 апреля 2020

У меня есть несколько Entry представлений на моей странице, подключающихся к модели представления с использованием привязки данных. Все работает, как задумано, за исключением того, что мне нужно вычислять значения, когда пользователь вводит их.

    public decimal DownPayment
    {
        get => this.loanValues.DownPayment;
        set
        {
            this.loanValues.DownPayment = value;
            this.CalculateValues();
        }
    }

    public decimal TradeInPrice
    {
        get => this.loanValues.TradeInPrice;
        set
        {
            this.loanValues.TradeInPrice = value;
            this.CalculateValues();
        }
    }

    // Other properties

Теперь проблема в том, что свойство устанавливается всякий раз, когда пользователь вводит значение. Есть ли способ изменить событие, в котором происходит привязка данных (т. Е. На Completed вместо TextChanged)?

Я вижу, что в привязке XAML есть свойство UpdateSourceEventName, но я не знаю, почему это не работает:

<Entry Placeholder="Down Payment ($)" Text="{Binding DownPayment, UpdateSourceEventName=Completed}" />

ОБНОВЛЕНИЕ: документация UpdateSourceEventName гласит, что это Для внутреннего использования платформой Xamarin.Forms

1 Ответ

1 голос
/ 03 апреля 2020

Вы можете использовать EventToCommandBehavior для преобразования события, завершенного ввода в команду, и обработки логи c в ViewModel.

using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;

namespace App18
{
    public class BehaviorBase<T> : Behavior<T> where T : BindableObject
    {
        public T AssociatedObject { get; private set; }

        protected override void OnAttachedTo(T bindable)
        {
            base.OnAttachedTo(bindable);
            AssociatedObject = bindable;

            if (bindable.BindingContext != null)
            {
                BindingContext = bindable.BindingContext;
            }

            bindable.BindingContextChanged += OnBindingContextChanged;
        }

        protected override void OnDetachingFrom(T bindable)
        {
            base.OnDetachingFrom(bindable);
            bindable.BindingContextChanged -= OnBindingContextChanged;
            AssociatedObject = null;
        }

        void OnBindingContextChanged(object sender, EventArgs e)
        {
            OnBindingContextChanged();
        }

        protected override void OnBindingContextChanged()
        {
            base.OnBindingContextChanged();
            BindingContext = AssociatedObject.BindingContext;
        }
    }
}

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Windows.Input;
using Xamarin.Forms;

namespace App18
{
    public class EventToCommandBehavior : BehaviorBase<View>
    {
        Delegate eventHandler;

        public static readonly BindableProperty EventNameProperty = BindableProperty.Create("EventName", typeof(string), typeof(EventToCommandBehavior), null, propertyChanged: OnEventNameChanged);
        public static readonly BindableProperty CommandProperty = BindableProperty.Create("Command", typeof(ICommand), typeof(EventToCommandBehavior), null);
        public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create("CommandParameter", typeof(object), typeof(EventToCommandBehavior), null);
        public static readonly BindableProperty InputConverterProperty = BindableProperty.Create("Converter", typeof(IValueConverter), typeof(EventToCommandBehavior), null);

        public string EventName
        {
            get { return (string)GetValue(EventNameProperty); }
            set { SetValue(EventNameProperty, value); }
        }

        public ICommand Command
        {
            get { return (ICommand)GetValue(CommandProperty); }
            set { SetValue(CommandProperty, value); }
        }

        public object CommandParameter
        {
            get { return GetValue(CommandParameterProperty); }
            set { SetValue(CommandParameterProperty, value); }
        }

        public IValueConverter Converter
        {
            get { return (IValueConverter)GetValue(InputConverterProperty); }
            set { SetValue(InputConverterProperty, value); }
        }

        protected override void OnAttachedTo(View bindable)
        {
            base.OnAttachedTo(bindable);
            RegisterEvent(EventName);
        }

        protected override void OnDetachingFrom(View bindable)
        {
            DeregisterEvent(EventName);
            base.OnDetachingFrom(bindable);
        }

        void RegisterEvent(string name)
        {
            if (string.IsNullOrWhiteSpace(name))
            {
                return;
            }

            EventInfo eventInfo = AssociatedObject.GetType().GetRuntimeEvent(name);
            if (eventInfo == null)
            {
                throw new ArgumentException(string.Format("EventToCommandBehavior: Can't register the '{0}' event.", EventName));
            }
            MethodInfo methodInfo = typeof(EventToCommandBehavior).GetTypeInfo().GetDeclaredMethod("OnEvent");
            eventHandler = methodInfo.CreateDelegate(eventInfo.EventHandlerType, this);
            eventInfo.AddEventHandler(AssociatedObject, eventHandler);
        }

        void DeregisterEvent(string name)
        {
            if (string.IsNullOrWhiteSpace(name))
            {
                return;
            }

            if (eventHandler == null)
            {
                return;
            }
            EventInfo eventInfo = AssociatedObject.GetType().GetRuntimeEvent(name);
            if (eventInfo == null)
            {
                throw new ArgumentException(string.Format("EventToCommandBehavior: Can't de-register the '{0}' event.", EventName));
            }
            eventInfo.RemoveEventHandler(AssociatedObject, eventHandler);
            eventHandler = null;
        }

        void OnEvent(object sender, object eventArgs)
        {
            if (Command == null)
            {
                return;
            }

            object resolvedParameter;
            if (CommandParameter != null)
            {
                resolvedParameter = CommandParameter;
            }
            else if (Converter != null)
            {
                resolvedParameter = Converter.Convert(eventArgs, typeof(object), null, null);
            }
            else
            {
                resolvedParameter = eventArgs;
            }

            if (Command.CanExecute(resolvedParameter))
            {
                Command.Execute(resolvedParameter);
            }
        }

        static void OnEventNameChanged(BindableObject bindable, object oldValue, object newValue)
        {
            var behavior = (EventToCommandBehavior)bindable;
            if (behavior.AssociatedObject == null)
            {
                return;
            }

            string oldEventName = (string)oldValue;
            string newEventName = (string)newValue;

            behavior.DeregisterEvent(oldEventName);
            behavior.RegisterEvent(newEventName);
        }
    }
}

в xaml

</StackLayout>

  <Entry WidthRequest="100" Text="{Binding Value1,Mode=OneWayToSource}"  Keyboard="Numeric"  >
        <Entry.Behaviors>
            <local:EventToCommandBehavior EventName="Unfocused" Command="{Binding CompletedCommand}"  />

        </Entry.Behaviors>

    </Entry>


    <Entry WidthRequest="100" Text="{Binding Value2,Mode=OneWayToSource}" Keyboard="Numeric">
        <Entry.Behaviors>
            <local:EventToCommandBehavior EventName="Unfocused" Command="{Binding CompletedCommand}"  />

        </Entry.Behaviors>

    </Entry>


    <Label WidthRequest="100" Text="{Binding Sum}"  TextColor="Black" />

</StackLayout>

в ViewModel

public class MyViewModel : INotifyPropertyChanged
{


    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    double value1;

    public double Value1
    {
        get
        {
            return value1;
        }

        set
        {
            if (value1 != value)
            {
                value1 = value;
                NotifyPropertyChanged("Value1");
            }
        }
    }

    double value2;

    public double Value2
    {
        get
        {
            return value2;
        }

        set
        {
            if (value2 != value)
            {
                value2 = value;
                NotifyPropertyChanged("Value2");
            }
        }
    }




    private string sum;
    public string Sum
    {
        get { return sum; }
        set
        {
            if (sum != value)
            {
                sum = value;
                NotifyPropertyChanged("Sum");
            }
        }
    }

    public ICommand CompletedCommand { get; set; }

    public MyViewModel()
    {

        CompletedCommand = new Command(()=> {

            Sum = (Value1 + Value2).ToString();


        });
    }



}
...