This project has moved. For the latest updates, please go here.
1

Closed

Bindings not working in iOS

description

Hi,

I have a very simple set of bindings in an iOS Controller, and I can't figure out why some are working and some aren't.

in my viewmodel, I have the following properties:
public BankAccountDetailsDto AccountDetails
        {
            get { return _accountDetails; }
            set
            {
                if (Set(() => AccountDetails, ref _accountDetails, value))
                {
                    RaisePropertyChanged(() => FormattedOperation);
                    UpdateCommands();
                }
            }
        }

        public Decimal Amount
        {
            get { return _amount; }
            set
            {
                if (Set(() => Amount, ref _amount, value))
                {
                    RaisePropertyChanged(() => IsRequestOk);
                    RaisePropertyChanged(() => FormattedOperation);
                    UpdateCommands();
                }
            }
        }

        public string FormattedOperation
        {
            get
            {
                return AccountDetails == null
                    ? String.Empty
                    : String.Format(OperationFormat, AccountDetails.Balance, Amount, (AccountDetails.Balance + Amount));
            }
        }
In my Controller, I have the following bindings:
private void CreateBindings()
        {
            _bindings = new List<Binding>()
            {
                this.SetBinding(() => VM.FormattedOperation, () => this.Operation.Text, BindingMode.OneWay),
                this.SetBinding(() => VM.AccountDetails.ChildName, () => this.ChildName.Text, BindingMode.OneWay)
                    .ConvertSourceToTarget(c => (c ?? String.Empty).ToUpper())
            };
        }
I'm aware of the problem with the iOS GC being too aggressive, so I store my bindings in a list.

My problem is that the 2nd binding is working perfectly as expected, the "ChildName" UILabel is always updated, but the "Operation" UILabel Text is set initially and never updated again.

While debugging my viewmodel, I find that the AccountDetails property is set, which triggers the
RaisePropertyChanged(() => FormattedOperation);
but the getter of "FormattedOperation" is never called afterwards, the UILabel Text never updated, etc.

By debugging through you code, I found out that in the "PropertyChangedEventManager", the method:
private void PropertyChanged(object sender, PropertyChangedEventArgs args)
        {
            if (!_list.ContainsKey(args.PropertyName))
            {
                return;
            }

            var list = _list[args.PropertyName];
            if (list != null)
            {
                var recipients =
                    list.Where(
                        i => i.InstanceReference != null 
                         && i.InstanceReference.IsAlive
                         && i.InstanceReference.Target == sender
                         && i.Listener != null)
                    .ToList();

                // We have the listeners. Deal with them
                foreach (var item in recipients)
                {
                    item.Listener.ReceiveWeakEvent(GetType(), sender, args);
                }
            }
        }
is called with args.PropertyName = "AccountDetails", but never with args.PropertyName = "FormattedOperation", even just after the breakpoint in my vm on the line:
RaisePropertyChanged(() => FormattedOperation);
Any insight? am I doing something wrong?

The big mystery is that other bindings are working!
Closed Jul 20, 2016 at 8:03 AM by lbugnion
Fixed in V5.3.0

comments

remiguittaut wrote Mar 18, 2015 at 2:19 PM

I should add that I was debugging through your code using that latest source here (commit 675e81070a0f).

remiguittaut wrote Mar 18, 2015 at 5:36 PM

Also, to give a little more details, it seems that the problem appeared since I migrated to Unified API, the same bindings were working in Classic API.

lbugnion wrote Mar 23, 2015 at 1:14 PM

Hey,

Sorry for the delay as I was in Vegas for VS Live last week. Checking this now.

Will report back when I find something,.
Cheers
Laurent

lbugnion wrote Mar 23, 2015 at 2:14 PM

OK first investigation: Your code seems fine, there is a problem with the second binding (the one to Vm.AccountDetails.ChildName). I think that this causes an inner exception to occur, which prevents the binding code to continue, and explains why other binding never gets updated.

I need to dig into the binding code to see what's going on. In the mean time, you can use a workaround by subscribing "manually" to the Vm's PropertyChanged event and handling that.

I'll report back as soon as I find out what's going on with the binding.

Cheers and thanks for reporting.
Laurent

remiguittaut wrote Mar 24, 2015 at 1:05 PM

Hi, thanks for your answer.

I used that workaround already, I have an IObservable<string> stream of propertyChanged events on my vm which allows me to do that, the only thing is that it's a bit unelegant to have 2 different ways of handling bindings in Controllers, the code looks a bit messy.

About the problem, I have the feeling that the problems arises when u have bindings at different levels in the same Controller ->
this.SetBinding(() => VM.FormattedOperation, () => this.Operation.Text, BindingMode.OneWay);

this.SetBinding(() => VM.AccountDetails.ChildName, () => this.ChildName.Text, BindingMode.OneWay);
The first one is at the root of the vm while the 2nd one is under an object at the root of the vm.

I found out that I have actually other bindings at the root of the vm not working, while the bindings to properties inside of this BankAccountDetailsDto object are working fine.

The other working bindings across my project are all in a situation where all the bindings for a given Controller are on properties on VM root, or all under a complex object held by a vm property.

Hope this will help,

Best regards, Remi.

lbugnion wrote Jan 29, 2016 at 6:56 PM

Well that was a tough one but I found the bug. There was an issue where the PropertyChanged event handler was unregistered too early in the exact scenario that you showed here. The issue is fixed now and the new source is in the repo, including unit tests. It will be part of V5.3 which is due in a few weeks, but you can already get latest and build if you need an earlier fix.

Thank you so much for the detailed description which allowed me to reproduce the issue and debug it.