简体   繁体   中英

Xamarin forms ViewModels Inheritance

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!

First of all, I made a ViewModelBase like following code.

    public class ViewModelBase : INotifyPropertyChanged
    {

        private string _title;
        public string Title
        {
            get => _title;
            set => SetProperty(ref _title, value);
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs((propertyName)));
        }

        protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
        {
            if (EqualityComparer<T>.Default.Equals(storage, value))
            {
                return false;
            }
            storage = value;
            OnPropertyChanged(propertyName);

            return true;
        }
    }
}

I set a text for SearchGame in the SearchViewModel .

    public class SearchViewModel : GamesViewModel
    {
        public SearchViewModel()
        {
            SearchGame = "test";
        } 
        
    }

Here is code about GamesViewModel .

    public class GamesViewModel:ViewModelBase
    {
        private string _searchGame;
        public string SearchGame
        {
            get => _searchGame;
            set => SetProperty(ref _searchGame, value);
        }
    }

Then I make a Label to binding the SearchGame property like the xaml.

   <Label Text="{Binding SearchGame}" 
           HorizontalOptions="Center"
           VerticalOptions="CenterAndExpand" />

Here is layout background code.

  public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
            this.BindingContext = new SearchViewModel();
            
        }
    }

Here is running screenshot.

在此处输入图像描述

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM