I am new both to MVVM pattern and Xamarin platform. Im trying to crate a bindable interface by using a view model. I started with a very simple task: Take the Entry input from the user, and send it to the label text after clicking the button.
ViewModel ---> Commands ---> EntryCommand.cs
namespace HelloWorld.ViewModel.Commands
{
public class EntryCommand : ICommand
{
public ViewModel VM { get; set; }
public EntryCommand( ViewModel vm)
{
VM = vm;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
VM.ChangeLabelText();
}
}
}
ViewModel.cs
namespace HelloWorld.ViewModel
{
public class ViewModel: INotifyPropertyChanged
{
public EntryCommand EntryCommand { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
public ViewModel()
{
EntryCommand = new EntryCommand(this);
}
private void OnPropertyChanged(string PropertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
public string LabelText { get; set; }
public string Name
{
get { return Name; }
set
{
Name = value;
OnPropertyChanged("Name");
}
}
public void ChangeLabelText()
{
if(Name!=null)
{
LabelText = Name;
}
}
}
}
Bindable Xaml file:
MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="HelloWorld.MainPage"
xmlns:ViewModel="clr-namespace:HelloWorld.ViewModel" x:DataType="ViewModel:ViewModel">
<ContentPage.Resources>
<ViewModel:ViewModel x:Key="vm"/>
</ContentPage.Resources>
<StackLayout BindingContext="{StaticResource vm}" BackgroundColor="AliceBlue"
Margin="15">
<Label Text="{Binding Name, Mode=TwoWay}"/>
<Entry Placeholder="Enter Your Name" Text="{Binding Name, Mode=TwoWay}"/>
<Button Text="Enter" Command="{Binding EntryCommand}"/>
</StackLayout>
</ContentPage>
Now, I don't get any errors but emulator keeps stopping before building the UI:
CodePudding user response:
I think you're using the ViewModel incorrectly.
Depending on your needs,there is no need to create EntryCommand: ICommand
.
You can do like this:
public ICommand EntryCommand => new Command(DoSomething);
public void DoSomething() {
// do some thing here
}
Besides, the use of Name
is also incorrect, you need to create another variable (e.g. private string _name;
)
private string _name;
public string Name
{
set { SetProperty(ref _name, value); }
get { return _name; }
}
You can refer to the full sample code here:
public class MyViewModel: INotifyPropertyChanged
{
public ICommand EntryCommand => new Command(DoSomething);
public MyViewModel() {
Name = "abc123";
}
public void DoSomething() {
// do some thing here
}
public string LabelText { get; set; }
private string _name;
public string Name
{
set { SetProperty(ref _name, value); }
get { return _name; }
}
public void ChangeLabelText()
{
if (Name != null)
{
LabelText = Name;
}
}
bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (Object.Equals(storage, value))
return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string PropertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
}
When using it in xaml, you can set the BindingContext
as follows:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:testapp0211="clr-namespace:TestApp0211"
x:Class="TestApp0211.MainPage">
<ContentPage.BindingContext>
<testapp0211:MyViewModel />
</ContentPage.BindingContext>
<StackLayout BackgroundColor="AliceBlue"
Margin="15">
<Label Text="{Binding Name, Mode=TwoWay}"/>
<Entry Placeholder="Enter Your Name" Text="{Binding Name, Mode=TwoWay}"/>
<Button Text="Enter" Command="{Binding EntryCommand}"/>
</StackLayout>
</ContentPage>
Note:
It is recommended that you rename the class ViewModel
(e.g. MyViewModel
)to better distinguish between different viewModels.