Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/xamarin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Xaml 在Xamarin表单中发生数据绑定(回源)时如何更改?_Xaml_Xamarin_Events_Xamarin.forms_Data Binding - Fatal编程技术网

Xaml 在Xamarin表单中发生数据绑定(回源)时如何更改?

Xaml 在Xamarin表单中发生数据绑定(回源)时如何更改?,xaml,xamarin,events,xamarin.forms,data-binding,Xaml,Xamarin,Events,Xamarin.forms,Data Binding,我的页面中有多个条目视图使用数据绑定连接到视图模型。除了我需要在用户输入时计算一个值外,其他一切都按预期工作 public decimal DownPayment { get => this.loanValues.DownPayment; set { this.loanValues.DownPayment = value; this.CalculateValues();

我的页面中有多个
条目
视图使用数据绑定连接到视图模型。除了我需要在用户输入时计算一个值外,其他一切都按预期工作

    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}" />


更新:的文档说明它是供Xamarin.Forms平台内部使用的

您可以使用EventToCommandBehavior将条目的事件转换为命令并处理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;
        }
    }
}


不要调用集合中的CalculateValue,而是从完成的event@Jason谢谢,虽然这一个应该很快解决我目前的情况,我仍然对一个“适当”的方式解决它感兴趣。但是,是的,这是一个很好的解决方案。很抱歉,我没有说这是无效的答案,但是当我可以简单地将事件处理程序附加到我所有的
条目
控件时,为什么还要经历这样的麻烦呢?与从我的页面调用
CalculateValues
来处理
Completed
事件相比,这样做有什么好处?因为您已经使用了数据绑定,所以最好处理ViewModel中的所有逻辑。
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);
        }
    }
}

</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>
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();


        });
    }



}