I work on developing a Xamarin forms application about video games using MVVM for my pet project. I am new in Xamarin forms, I need your advice.
I had a few ViewModels with the same code in it. I decided to create one base ViewModel and inherit others from that.
I have ViewModelBase with PropertyChanged event:
public class ViewModelBase : INotifyPropertyChanged
{
private string _title;
public string Title
{
get => _title;
set => Set(ref _title, value);
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void Set<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
field = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
I also have a base GamesViewModel from which others are inherited, there is a lot of code, that is why I will show only that I inherit everything properly:
public class GamesViewModel : ViewModelBase
Below are derived ViewModels:
public class NewGamesViewModel : GamesViewModel
and
public class SearchViewModel : GamesViewModel
Problem is I have SearchGame property in the base GamesViewModel:
private string _searchGame;
public string SearchGame
{
get => _searchGame;
set => Set(ref _searchGame, value);
}
When the program is running I put the value inside SearchGame property,and in GamesViewModel I can see that value assigned, but in derived ViewModels value is null:
For example, in debugging in SearchViewModel which is inherited from the GamesViewModel I check the value and it's null.
var test = SearchGame; - value is null here
I don't create any object of GamesViewModel in the project.
In the pages Code-behind files in BindingContext I do like this:
public partial class SearchGamePage : ContentPage
{
public SearchGamePage()
{
InitializeComponent();
BindingContext = new SearchViewModel();
}
}
I tried to explain as more as I can. Maybe in Xamarin forms inheritance with ViewModels work not obviously.
Thank you in advance for the help!
Have a nice day!
I sent a message to the GamesViewModel with search game value like this:
MessagingCenter.Send(this, "search_game", titleViewModel.SearchGame);
var detailPage = (Application.Current.MainPage as MasterDetailPage)?.Detail;
await detailPage.Navigation?.PushAsync(new SearchGamePage());
I subscribe to this message in GamesViewModel constructor and assigned to SearchGame property message value like this:
MessagingCenter.Subscribe<CustomTitleView, string>(this, "search_game", (sender, message) =>
{
SearchGame = message;
});
But as you can see in the code above I create SearchGamePage instance. SearchGamePage constructor calls and I create in it new SearchViewModel instance:
public partial class SearchGamePage : ContentPage
{
public SearchGamePage()
{
InitializeComponent();
BindingContext = new SearchViewModel();
}
}
That's why GamesViewModel constructor calls again and in SearchGame property assign null.
I solved this problem using DependencyService.Register in App.xaml.cs file:
public App()
{
InitializeComponent();
DependencyService.Register<MockDataStore>();
DependencyService.Register<IGameApiClient, GameApiClient>();
DependencyService.Register<IFavoriteGameService, FavoriteGameService>();
DependencyService.Register<GamesViewModel>();
DependencyService.Register<SearchViewModel>();
DependencyService.Register<NewGamesViewModel>();
DependencyService.Register<TitleViewModel>();
MainPage = new MainPage();
}
And finally, in SearchGamePage constructor I assign to BindingContext SearchViewModel like this:
public SearchGamePage()
{
InitializeComponent();
BindingContext = DependencyService.Get<SearchViewModel>();
}
Now everything is fine when I assign value to SearchGame property in GamesViewModel using messenger I can see the same value in the SearchGame property in SearchViewModel because this ViewModel wasn't recreated.
I understand that I didn't give full info when I asked a question. But I hope that if somebody else will face the same problem this answer will be useful.