Reputation: 83
This is my first StackOverflow question! I'm trying to get data bound to a ViewModel to appear on one page, allow it to be changed on another page, then appear in its changed form on the first page.
I have a MainPage displaying a label bound to the property ContactName in the ViewModel ContactViewModel. A button on MainPage pushes the DataEntryPage. On the DataEntryPage I have an entry field also bound to the ContactName. A save button pops the page and returns to MainPage.
I want to enter a new value on DataEntryPage, press save, and have the new value display in the label on the MainPage.
If I initialize ContactName, the value appears both on the MainPage and in the entry field of the DataEntryPage. But when I enter a new value and press save, the old value is displayed on MainPage.
I can make the new value display if I add a static instantiation of the ContactViewModel, explicitly set it to the new value in the DataEntryPage save, then force a refresh by overriding the MainPage's OnAppearing and setting the label to that value. With an ObservableCollection and ListView it's super easy, but I can't make it happen with a single property. It seems like I'm missing some basic ability of MVVC.
The stripped down code is--
MainPage.xaml:
<Label Text="{Binding ContactName}">
<Label.BindingContext>
<local:ContactViewModel />
</Label.BindingContext>
</Label>
(a Button which triggers code below) W MainPage.xaml.cs: (Button clicked code)
await Navigation.PushAsync(new DataEntryPage());
DataEntryPage.xaml
<ContentPage.BindingContext>
<local:ContactViewModel />
</ContentPage.BindingContext>
(then in a StackLayout)
<Entry Text={Binding ContactName} />
(Button for save)
DataEntryPage.xaml.cs (Button clicked code)
await Navigation.PopAsync();
And finally the ContactViewModel.cs
public class ContactViewModel : INotifyPropertyChanged
{
string contactName;
public event PropertyChangedEventHandler PropertyChanged;
public ContactViewModel()
{
contactName = "OriginalName";
}
public static ContactViewModel cvm = new ContactViewModel();
public string ContactName
{
set {
if (contactName!=value)
{
contactName = value;
if (PropertyChanged!=null )
{
PropertyChanged(this, new PropertyChangedEventArgs("ContactName"));
}
}
}
get
{
return contactName;
}
}
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Is there a simple solution to this problem? I would prefer to use vanilla Xamarin.forms/C# unless it's absolutely impossible to do without. Thank you for your help!
Upvotes: 0
Views: 83
Reputation: 2064
When you declare the following in XAML
<Control.BindingContext>
<local:ContactViewModel/>
<Control.BindingContext>
a new instance is created. So the DataEntryPage
is creating its own instance of ContactViewModel
. So the instance that you are updating on the DataEntryPage
is different from the instance that you are using to bind the Text
property of Label
on the MainPage
. Using same instance for the pages should resolve your issue
Upvotes: 0