Reputation: 732
I've created a custom usercontrol in my application and I try to bind to its property (BindableProperty) to ViewModel but it doesn't work for me. Am I doing something wrong? This is the usercontrol. It is just custom stepper for the purpose of test project: "decrease" and "increase" buttons and quantity label between them. Please notice that binding inside the usercontrol works perfect (for example Commands bindings) . What I am trying to do is bind QuantityProperty to ViewModel
namespace UsercontrolBindingTest.Usercontrols
{
using System.Windows.Input;
using Xamarin.Forms;
public class CustomQuantityStepper : ContentView
{
public static readonly BindableProperty QuantityProperty =
BindableProperty.Create(nameof(Quantity), typeof(int), typeof(CustomQuantityStepper), 0, BindingMode.TwoWay);
public int Quantity
{
get
{
return (int)base.GetValue(QuantityProperty);
}
set
{
base.SetValue(QuantityProperty, value);
this.OnPropertyChanged(nameof(this.Quantity));
}
}
public ICommand DecreaseQuantityCommand { get; private set; }
public ICommand IncreaseQuantityCommand { get; private set; }
public CustomQuantityStepper()
{
this.BindingContext = this;
this.DecreaseQuantityCommand = new Command(() => this.Quantity--);
this.IncreaseQuantityCommand = new Command(() => this.Quantity++);
this.DrawControl();
}
private void DrawControl()
{
var quantityEntry = new Entry();
quantityEntry.SetBinding(Entry.TextProperty, new Binding("Quantity", BindingMode.TwoWay));
quantityEntry.WidthRequest = 50;
quantityEntry.HorizontalTextAlignment = TextAlignment.Center;
var increaseQuantityButton = new Button { Text = "+" };
increaseQuantityButton.SetBinding(Button.CommandProperty, "IncreaseQuantityCommand");
var decreaseQuantityButton = new Button { Text = "-" };
decreaseQuantityButton.SetBinding(Button.CommandProperty, "DecreaseQuantityCommand");
var ui = new StackLayout()
{
Orientation = StackOrientation.Horizontal,
Children =
{
decreaseQuantityButton,
quantityEntry,
increaseQuantityButton
}
};
this.Content = ui;
}
}
}
The view with proof that binding between View and VM is working:
namespace UsercontrolBindingTest
{
using Usercontrols;
using Xamarin.Forms;
public class App : Application
{
public App()
{
MainPage = new ContentPage
{
BindingContext = new MainPageVM(),
Content = new StackLayout
{
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.Center,
Children =
{
this.GetLabel("Title"),
this.GetCustomStepper(),
this.GetLabel("SelectedQuantity")
}
}
};
}
private Label GetLabel(string boundedPropertyName)
{
var ret = new Label();
ret.HorizontalOptions = LayoutOptions.CenterAndExpand;
ret.SetBinding(Label.TextProperty, new Binding(boundedPropertyName));
return ret;
}
private CustomQuantityStepper GetCustomStepper()
{
var ret = new CustomQuantityStepper();
var dataContext = this.BindingContext as MainPageVM;
ret.SetBinding(CustomQuantityStepper.QuantityProperty, new Binding("SelectedQuantity", BindingMode.TwoWay));
return ret;
}
}
}
And my simple ViewModel:
namespace UsercontrolBindingTest
{
using System.ComponentModel;
internal class MainPageVM : INotifyPropertyChanged
{
private int _selectedQuantity;
public int SelectedQuantity
{
get
{
return this._selectedQuantity;
}
set
{
this._selectedQuantity = value;
this.NotifyPropertyChanged(nameof(this.SelectedQuantity));
}
}
public string Title { get; set; } = "ViewModel is bound";
public MainPageVM()
{
this.SelectedQuantity = 0;
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propName)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
}
I've checked plenty of different topis and blog posts but I wasn't able to find solutions for my issue. Hope for help here... Attached sample project here: https://1drv.ms/u/s!Apu16I9kXJFtl28YBjkfwDztT9j0
Upvotes: 0
Views: 1728
Reputation: 33048
You are setting the BindingContext
of CustomQuantityStepper
to itself (this
). That's why the binding engine is looking for a public property named "SelectedQuantity" in your custom control and not in the ViewModel.
BindingContext
in the control and instead let it use the context that is currently defined and (hopefully) points to the VM.Source
property of the Binding
and let it point to the correct source (which would be the VM).Upvotes: 1