Reputation: 11931
I recently started learning Xamarin and I stumbled across the following problem. I have a single label in my XAML file which is bound to a ViewModel property. I am using the ICommand interface to bind a tap gesture to a method in my ViewModel which is supposed to update the label's text. However, it is not updating the "Please touch me once!". I am just wondering what I am doing wrong here?
MainPage xaml:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:App1"
x:Class="App1.MainPage">
<Label Text="{Binding MessageContent, Mode=TwoWay}"
VerticalOptions="Center"
HorizontalOptions="Center">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding OnLabelTouchedCmd}" />
</Label.GestureRecognizers>
</Label>
</ContentPage>
Code-behind:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
BindingContext = new MainPageViewModel();
}
}
ViewModel:
class MainPageViewModel : INotifyPropertyChanged
{
private string _messageContent;
public MainPageViewModel()
{
MessageContent = "Please touch me once!";
OnLabelTouchedCmd = new Command(() => { MessageContent = "Hey, stop toutching me!"; });
}
public ICommand OnLabelTouchedCmd { get; private set; }
public string MessageContent
{
get => _messageContent;
set
{
_messageContent = value;
OnPropertyChanged(value);
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Upvotes: 1
Views: 853
Reputation: 309
Also look at the ViewModelBase located here, have all your ViewModels inherit from it. You can call just OnPropertyChanged, in either of the two ways below. The first of which will just take the name of the calling member, in this case your public property.
OnPropertyChanged();
OnPropertyChanged("MyProperty");
Edit- this is in extension to Brandon's correct answer
Upvotes: 0
Reputation: 15420
The current code isn't working because it is passing the value
of the property into OnPropertyChanged
.
Instead, we need to pass the name of the property as a string
into OnPropertyChanged
.
We can take advantage of the CallerMemberName
attribute to make the code more concise and to avoid hard-coding strings when calling OnPropertyChanged
.
Adding [CallerMemberName]
to the parameter of OnPropertyChanged
allows you to call OnPropertyChanged()
from the setter of the property, and the property name is automatically passed into the argument.
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
class MainPageViewModel : INotifyPropertyChanged
{
private string _messageContent;
...
public string MessageContent
{
get => _messageContent;
set
{
_messageContent = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Upvotes: 1
Reputation: 7189
You're calling OnPropertyChanged with a wrong argument as seen here:
protected virtual Void OnPropertyChanged ([System.Runtime.CompilerServices.CallerMemberName] String propertyName)
It expects the name of the property instead of the value you're passing now. Try this instead:
public string MessageContent
{
get => _messageContent;
set
{
_messageContent = value;
OnPropertyChanged("MessageContent");
}
}
Upvotes: 3