binding not firing in some cases

GeorgeCookGeorgeCook PEUniversity ✭✭✭
edited March 2015 in Xamarin.Forms

I have a view model, which is set as the binding context of my view.
I have a view which binds to one of the properties of the view model, which is a complex object.

I'm finding that the bindings are not firing for one of my properties "CurrentSpace" in the code below.

for now, I have to work around this, by manually setting it, but that's not gonna fly.

What could stop my controls getting values for bindings of this type? I breakpoint the getter, and there's no actual call to get any initial value from the CurrentSpace property - only changing them after the view is shown trigger the binding to lookup the getters.

i.e

<Label Text="{Binding TestText}" /> <Label x:Name="TestLabel" Text="{Binding CurrentSpace}" />
These bind to :

`
ISubscribedSpace _currentSpace;

    public ISubscribedSpace CurrentSpace {
        get{ return _currentSpace; }
        set {
            SetProperty<ISubscribedSpace> (ref _currentSpace, value);
        }
    }

    string _testText;

    public string TestText {
        get{ return _testText; }
        set {
            SetProperty<string> (ref _testText, value);
        }
    }

`
I'm using ObservableObject (from xamarin forms labs for my viewmodels base class).

The CurrentSpace binding does nothing when the view appears. The TestText one works fine. If I update TestText, the label updates. If I update CurrentSpace, nothing happens.

Unsure why this is the case; but it's happening in all my view models. I wouldn't be surprised if this is another xamarin forms issue, though (I'll be ditchign it soon, some helpful stuff, but a lot of bugs I think).

Best Answers

Answers

  • GeorgeCookGeorgeCook PEUniversity ✭✭✭

    further debugging. it looks like the bindingcontext is not being set on child views. why would that be?

  • adamkempadamkemp USInsider, Developer Group Leader mod

    CurrentSpace is not a string, but you're binding it to a string property. I think we covered in a previous post that there is no automatic string conversion, and in my testing this kind of binding would be silently ignored. You can use an IValueConverter to convert the object to a string.

  • GeorgeCookGeorgeCook PEUniversity ✭✭✭

    thanks Adam; but I'm having the same thing for bindigns that match their type.
    I have a custom control which has a CurrentSpace property; which also does nothing when the viewmodel property (of the same type) changes.
    I have buttons binding their IsEnabled flag to boolean properties, they don't get fired either.

    something seems seriously screwy to me.

  • adamkempadamkemp USInsider, Developer Group Leader mod

    Could you post an example project?

  • GeorgeCookGeorgeCook PEUniversity ✭✭✭
    edited March 2015

    I think it's somehow the same problem. I can now see that my bindings are firing from the viewmodel; but it looks like I can't write a single control with a custom binding. In any case when I've tried to do this, the values don't get set on the actual target.

    Not sure what else I can do..
    Here's the code for my control that consumes the CurrentSpaces.

    `

    public class SpaceViewerLayout : AbsoluteLayout
    {
    public BindableProperty CurrentSpaceProperty = BindableProperty.Create ("CurrentSpace", typeof(ISubscribedSpace), typeof(SpaceViewerLayout), null, BindingMode.OneWay, null, null, null, null);

        public ISubscribedSpace CurrentSpace {
            get {
                return (ISubscribedSpace)base.GetValue (CurrentSpaceProperty);
            }
            set {
                DestroyPanels ();
                base.SetValue (CurrentSpaceProperty, value);
                CreatePanels ();
                InvalidateLayout ();
            }
        }
    

    `
    The CurrentSpaceProperty was static; but I made it a class level property, and now I'm back to the CurrentSpace mismatch can't convert Binding to ISubscribedSpace error - which I guess is progress, as at least it's trying to set something now.

    If you could help me resolve this, I'd be very grateful, as you can probably imagine, this is pretty fundamental and is starting to effect me as my app is growing.

    I've got total snow-blindness here : there's only so much I can keep reading the same lines of code and thinking; why does this work in other examples, but not in mine :(

  • adamkempadamkemp USInsider, Developer Group Leader mod

    The BindableProperty must be a public static field.

  • GeorgeCookGeorgeCook PEUniversity ✭✭✭

    ok - when it's a public static field , it does nothing.

  • GeorgeCookGeorgeCook PEUniversity ✭✭✭

    Is this fully documented anywhere? I find it incredible that every the bindings don't work on any single custom control I've written . I've spent maybe 6 hours this week simply debugging why bindings aren't firing, and I'm still in the same place - it's really holding me back from enjoying xamarin as much as I'd like to.

  • adamkempadamkemp USInsider, Developer Group Leader mod

    Post an example.

  • GeorgeCookGeorgeCook PEUniversity ✭✭✭

    and here's some more info.. in my view (the SpaceViewerLayout)

    `

        protected override void OnBindingContextChanged ()
        {
            base.OnBindingContextChanged ();
            ViewModel.PropertyChanged += (sender, e2) => {
                var name = e2.PropertyName;
            };
        }
    

    `

    The propertychange event is fired - every time currentspace changes. but that event is NEVER picked up by my CurrentSpaceLayout. This is the problem - I'm clearly doing something wrong - propertychange events are generated; but none of my custom controls ever pick them up in xaml - they don't even pick up initial values..

    Any ideas on how I can debug this at least? It basically renders xamarin bindings useless for me, which really sucks as I'm enjoying xmarin a ton, and want to show it to other colleauges in my company; but not having binding workign will really reduce the sell..

  • GeorgeCookGeorgeCook PEUniversity ✭✭✭

    I'll give you all of the classes involved. note, one of the bindings in the xaml, is a label - I know that won't work.. but the other one is the layout and should work.

  • adamkempadamkemp USInsider, Developer Group Leader mod

    I can't debug that. Post a working example I can just run.

  • GeorgeCookGeorgeCook PEUniversity ✭✭✭

    Ok, here's a completely new project that demonstrates the problem using the same notions I'm struggling with in my app.

  • GeorgeCookGeorgeCook PEUniversity ✭✭✭

    Ok, here's a completely new project that demonstrates the problem using the same notions I'm struggling with in my app.

  • GeorgeCookGeorgeCook PEUniversity ✭✭✭

    I also updated the code for the layout to look like

    `
    using System;

    using Xamarin.Forms;

    namespace BindingTest
    {
    public class SpaceViewerLayout : AbsoluteLayout
    {
    // public static BindableProperty CurrentSpaceProperty = BindableProperty.Create ("CurrentSpace", typeof(Space), typeof(SpaceViewerLayout), null, BindingMode.OneWay, null, null, null, null);
    public static readonly BindableProperty CurrentSpaceProperty = BindableProperty.Create<SpaceViewerLayout, Space> (p => p.CurrentSpace, null);

        public SpaceViewerLayout ()
        {
        }
    
        public Space CurrentSpace {
            get {
                return (Space)base.GetValue (CurrentSpaceProperty);
            }
            set {
                base.SetValue (CurrentSpaceProperty, value);
                BackgroundColor = value.Color;
            }
        }
    }
    

    }

    `

    that code is straight from an online tutorial.. I have no idea why this isn't working now - I've been trying to get this simple kind of binding working for 8 hours now to no avail.. I honestly can't see what I'm doing wrong. Could you possibly post me an example of working binding that you have? My xamarin studio can't currently deploy to iphone, I'm starting to wonder if there's something up with my install; because I've run out of ideas at this point.

  • GeorgeCookGeorgeCook PEUniversity ✭✭✭

    Adam,

    you're a tremendously helpful chap. I wish I could buy you a beer; but alas I live in Peru. Thanks for the explanation. I wish they would document this a bit better, as for n00bs who are having to ingest a lot of information pretty quickly this can be quite confusing.

    Thanks again!

  • GeorgeCookGeorgeCook PEUniversity ✭✭✭

    one last note on this,

    how to debug issues? because I've understoot and implemented your changes; but there's one view where I still have issues.

    I debugged, and noticed that the bindingcontext is null for one of the subviews. I suspect it's becuase this view is actually a custom page I created - in this case I have to set the bindingcontext on the controls which get skipped. but even doing that doesn't trigger their bindings. However, I've found that setting the property manually for the button does trigger the changehandler specified in the bindingproperty; so it appears that the mechanism works; but it still won't work for this button from xaml.

    <localControls:ExtendedButton x:Name ="SpaceButton" ImageRoot="Images/Main/BottomBar/iconSpace" EnabledFlag="{Binding IsSpaceViewEnabled}" Clicked="OnSpaceViewerClicked" AbsoluteLayout.LayoutFlags="PositionProportional" AbsoluteLayout.LayoutBounds="0.5,0,44,44" ImageHeightRequest="44" ImageWidthRequest="44" />

    from the ExtendedButton class:
    public static BindableProperty EnabledFlagProperty = BindableProperty.Create ( propertyName: "EnabledFlag", returnType: typeof(bool), declaringType: typeof(ExtendedButton), defaultValue: false, defaultBindingMode: BindingMode.OneWay, propertyChanged: HandleEnabledFlagChanged); public bool EnabledFlag { get { return (bool)GetValue (EnabledFlagProperty); } set {SetValue (EnabledFlagProperty, value); }

    private static void HandleEnabledFlagChanged (BindableObject bindable, object oldValue, object newValue) { var button = (ExtendedButton)bindable; button.IsEnabled = (bool)newValue; button.UpdateButtonImage (); }

  • adamkempadamkemp USInsider, Developer Group Leader mod

    As before, attach an example I can play with.

  • GeorgeCookGeorgeCook PEUniversity ✭✭✭

    I already did. I don't know where the post went.

    here it is again.

  • adamkempadamkemp USInsider, Developer Group Leader mod

    That project doesn't seem to match the code you quoted last (there is no ExtendedButton or EnabledFlag property). I don't know what I'm supposed to be looking at. Every binding I can see looks like it's working.

  • GeorgeCookGeorgeCook PEUniversity ✭✭✭

    I removed the bits that weren't important. the one that's not working is the EnabledFlag on SpaceViewerLayout.
    The property change handler is only ever invoked if I set it manually (i.e by directly setting the variable on the layout, not by changing the binding). I break point it, and I see it never get's invoked when the binding changes value.

  • adamkempadamkemp USInsider, Developer Group Leader mod

    The code you attached doesn't have an EnabledFlag property in SpaceViewerLayout. Maybe you attached the wrong code.

  • GeorgeCookGeorgeCook PEUniversity ✭✭✭

    ok. sorry I'll fix it right now and upload it.

  • GeorgeCookGeorgeCook PEUniversity ✭✭✭

    actually - I think it's the right code. it's not EnabledFlag, it's "BoolTest". Is that there?

    that's now working - it doens't correspond to the value of the binding in SpaceViewerPage.xaml

  • GeorgeCookGeorgeCook PEUniversity ✭✭✭

    right you are. Is all of this actually documented anywhere? I've seen examples about bindings; but they don't state the need for static binding properties, matching the name, state that the getter and setter become nothing more than proxies, or that values which match the default will not generate events.

    Perhaps this is common knowledge for c#/xaml developers; but all of this was news to me, and if it wasn't for your goodself I'd be absolutely non-the-wiser.

  • adamkempadamkemp USInsider, Developer Group Leader mod

    I don't know whether it's documented, but it generally works the same as other XAML-based platforms. Also, creating your own custom bindable properties is kind of an advanced feature that I think Xamarin expected that most Xamarin.Forms users would never need to do.

  • GeorgeCookGeorgeCook PEUniversity ✭✭✭

    ok. I wonder if Xamarin realize what they're doing here. I'm hitting similar "Xamarin didn't think you'd do that" responses with my nested Pages. These are all fairly standard things for enterprise levlel apps.

    I think my lack of xaml/.net expefdrience has held me back considerably here - looks like I should get myself a book on xaml, becuase Xamarin appear to borrow heavily from it.

    Thanks for all your help!

  • Darth_AaronDarth_Aaron USMember ✭✭

    I know its been a while, but the book Creating Mobile Apps With Xamarin.Forms has great examples of how to do this, and I'm sure Xamarin intended people to do this, its just an advanced concept that you'd have to be used to working with the platform at an advanced level.

Sign In or Register to comment.