Alexei Malashkevich
Alexei Malashkevich

Reputation: 1645

Xamarin.Forms binding using SetBinding not working

I have base custom control:

public class TabItem : ContentView
{
    public TabItem()
    {
        SetBinding(HeaderProperty, new Binding("Header"));
    }

    public static readonly BindableProperty HeaderProperty =
        BindableProperty.Create("Header", typeof(string), typeof(TabItem), default(string));

    public string Header
    {
        get { return (string)GetValue(TabItem.HeaderProperty); }
        set { SetValue(TabItem.HeaderProperty, value); }
    }
}

I derive from this class and set Binding context:

public partial class FeedbackView : TabItem
{
   public FeedbackView(FeedbackViewModel viewModel)
   {
       InitializeComponent();    
       Content.BindingContext = viewModel;    
   }
}

This is view model:

 public class FeedbackViewModel : BaseViewModel
 {
     private string header;

     public FeedbackViewModel()
     {
         Header = "Test Header";
     }

     public string Header
     {
         get { return header; }
         set
         {
             header = value;
             OnPropertyChanged("Header");
         }
      }

When I run it - header not binds to viewmodel's property. Is there something obvious that I forgot? Or I'm doing something wrong?

Upvotes: 3

Views: 6551

Answers (2)

Stephane Delcroix
Stephane Delcroix

Reputation: 16222

As you do not share the XAML part of FeedbackView, one can only guess, but let's try nonetheless:

you say:

header not binds to viewmodel's property

I'm quite sure (from the code you've shared) the Header property of TabItem is set, even if your way of doing binding is unconventional. Is this the issue ? or your issue is that you don't have anything displayed on screen ?

Solving the "nothing displayed" issue require some changes to your code. First, set the propertyChanged arg on BindableProperty.Create

public static readonly BindableProperty HeaderProperty =
    BindableProperty.Create("Header", typeof(string), typeof(TabItem), default(string),
    propertyChanged: OnHeaderChanged);

implements it, and create a virtual method so you can override it in your subviews

static void OnHeaderChanged (BindableObject bindable, object oldValue, object newvalue)
{
    ((TabItem)bindable).OnHeaderChanged ((string)oldValue, (string)newValue);
}

protected virtual void OnHeaderChanged (string oldValue, string newValue)
{
}

Now, in your derived FeedbackView, you can override OnHeaderChanged and set the label according to the Header

protected override void OnHeaderChanged (string oldValue, string newValue)
{
    //headerLabel is defined in Xaml, and has a x:Name="headerLabel"
    headerLabel.Text = newValue;
}

This should get you started.

As a last note, I'd say that setting the Binding in the TabItem ctor is, well, unconventional. It breaks the MVVM pattern as the View (TabItem) makes some assumption about the structure of the ViewModel (and the existence of an Header property).

That binding is normally set on the TabItem inherited instance.

var feedback = new FeedbackView (myVm);
feedback.SetBinding (TabItem.HeaderProperty, "Header");

or, as passing the VM as ctor parameter already breaks MVVM, you could eventually do that in FeedbackView ctor.

This last part is my humble opinion. Don't start a heated discussion about it, or do it without me involved :)

Upvotes: 1

Wosi
Wosi

Reputation: 45163

Your implementation of BindableProperty is wrong. Look here how to do it right: https://blog.xamarin.com/using-custom-controls-in-xamarin.forms-on-android/

The Binding to the property is usually done inside Page. There you bind the property of your ViewModel to the control's BindableProperty. You don't do it inside the control itself.

Upvotes: 0

Related Questions