1
votes

I try to realize my first MVVM-Project. First I created model called "person.cs". Then I created a modelview "AddPerson.cs", which should dynamically creates the data, which is stored in person.cs. In my view (completely created with xaml) I have a button which should call a method "CreatePerson()" from my "AddPerson.cs". I like to bind the method.

Additionally I have created a label which should be bound to the class "person.cs" for example to the public string "Name".

How can I set the BindingContext of the Button to the "AddPerson.cs"-class and the BindingContext of the Label to the "person.cs"-class?

2
Not possible what you are looking to do, but why don't you create a PersonViewModel and use it as your BindingContext ? Here you can have the AddPerson method and a property with the Person. ViewModels are perfect for this.pinedax

2 Answers

1
votes

Yes this is possible. Most of the Elements inherit BindablObject. Each BindableObjaect has a BindingContext Property. See: https://docs.microsoft.com/en-us/xamarin/xamarin-forms/xaml/xaml-basics/data-binding-basics

MainViewModel

The Viewmodel for your entire page, that holds every sub-viewmodel.

public class MainViewModel
{
    public AddPersonViewModel AddPersonViewModel { get; }
    public PersonViewModel PersonViewModel { get; }

    public MainViewModel()
    {
        // the passed action is just a fake action to simulate adding a person
        AddPersonViewModel = new AddPersonViewModel(value => PersonViewModel.Name = value);
        PersonViewModel = new PersonViewModel();
    }
}

AddPersonViewModel

Contains your add logic.

public class AddPersonViewModel : INotifyPropertyChanged
{ 
    public AddPersonViewModel(Action<string> onAction)
    {
        AddPerson = new Command(() => 
        {
            onAction(NewName); // call your update logic
            NewName = ""; // reset name
        });
    }

    public Command AddPerson { get; }
    private string _name;

    public string NewName
    {
        get => _name;
        set
        {
            _name = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(NewName)));
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
}

PersonViewModel

Contains your "new" Person.

public class PersonViewModel : INotifyPropertyChanged
{
    private string _name;

    public string Name
    {
        get => _name;
        set
        {
            _name = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name)));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

MainPage

Create and set your MainViewModel.

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
        BindingContext = new MainViewModel();
    }
}

MainPage.xaml

Here we bind the BindingContext of Entry and Button to the AddPersonViewModel property of our ContentPage's BindingContext which is the MainViewModel. And then we bind the Text of the Label and the Command of the Button to NewName and AddPerson properties of the local BindingContext, which is AddPersonViewModel

Same for Label.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:App5"
             x:Class="App5.MainPage">

    <StackLayout>
        <Entry BindingContext="{Binding AddPersonViewModel}" Text="{Binding NewName}" 
           HorizontalOptions="FillAndExpand" />
        <Button BindingContext="{Binding AddPersonViewModel}" Text="Click me!" Command="{Binding AddPerson}" 
           HorizontalOptions="Center" />
        <Label Text="Added Person:" FontAttributes="Bold" 
           HorizontalOptions="Center"/>
        <Label BindingContext="{Binding PersonViewModel}" Text="{Binding Name}" 
           HorizontalOptions="Center"/>
    </StackLayout>

</ContentPage>

The example is very hacky, but I think you get the point. The key is the already mentioned property BindingContext

1
votes

You are missing some essential concepts which result in your requests being strange.

You don't data bind to the class definition, but to the instance of the class. As one ViewModel is a class it may contain instances of other classes that you data bind to, and everything except that is in 99% of cases a wrong thing to do and your example is not one of those 1% of cases.

So basically your ViewModel should be something like:

public class PersonViewModel
{
   public Person Person {get; set}
   public ICommand AddPersonCommand {get; set}
}

Your BindingContext is then an instance of PersonViewModel and then on Label you bind to Person while on the button you would bind to AddPersonCommand.