Xamarin 表单 ViewModels 继承

Xamarin forms ViewModels Inheritance

我致力于使用 MVVM 为我的宠物项目开发有关视频游戏的 Xamarin 表单应用程序。我是 Xamarin 表单的新手,我需要你的建议。

我有几个包含相同代码的 ViewModel。我决定创建一个基础 ViewModel 并从中继承其他的。

我有带有 PropertyChanged 事件的 ViewModelBase:

 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));
    }
 
}

我还有一个基本的 GamesViewModel 继承了其他模型,有很多代码,这就是为什么我只显示我正确继承了所有内容:

public class GamesViewModel : ViewModelBase

以下是派生的 ViewModel:

public class NewGamesViewModel : GamesViewModel

public class SearchViewModel : GamesViewModel

问题是我在基础 GamesViewModel 中有 SearchGame 属性:

  private string _searchGame;
    public string SearchGame
    {
        get => _searchGame;
        set => Set(ref _searchGame, value);
    }

当程序是 运行 时,我将值放在 SearchGame 属性 中,在 GamesViewModel 中我可以看到分配的值,但在派生的 ViewModels 中值为空:

例如,在从 GamesViewModel 继承的 SearchViewModel 中进行调试时,我检查了该值并且它为 null。

var test = SearchGame; - value is null here

我没有在项目中创建任何 GamesViewModel 对象。

在 BindingContext 中的代码隐藏文件页面中,我是这样的:

public partial class SearchGamePage : ContentPage
{
    public SearchGamePage()
    {
        InitializeComponent();
        BindingContext = new SearchViewModel();
    }
}

我尽可能多地解释。也许在 Xamarin 中表单继承与 ViewModels 工作不明显。

提前感谢您的帮助!

祝你有愉快的一天!

首先,我做了一个ViewModelBase像下面的代码。

    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;
        }
    }
}

我在 SearchViewModel 中为 SearchGame 设置了文本。

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

这是关于 GamesViewModel 的代码。

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

然后我制作一个 Label 来绑定 SearchGame 属性 就像 xaml.

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

这里是布局背景代码。

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

这是运行截图。

我向 GamesViewModel 发送了一条消息,其中包含如下搜索游戏值:

  MessagingCenter.Send(this, "search_game", titleViewModel.SearchGame);
  var detailPage = (Application.Current.MainPage as MasterDetailPage)?.Detail;
  await detailPage.Navigation?.PushAsync(new SearchGamePage());

我在 GamesViewModel 构造函数中订阅此消息并分配给 SearchGame 属性 消息值如下:

 MessagingCenter.Subscribe<CustomTitleView, string>(this, "search_game", (sender, message) =>
   {
            SearchGame = message;
    });

但是正如您在上面的代码中看到的,我创建了 SearchGamePage 实例。 SearchGamePage 构造函数调用,我在其中创建新的 SearchViewModel 实例:

public partial class SearchGamePage : ContentPage
{
    public SearchGamePage()
    {
        InitializeComponent();
        BindingContext = new SearchViewModel();
    }
}

这就是 GamesViewModel 构造函数再次调用并在 SearchGame 中 属性 分配 null 的原因。

我使用 App.xaml.cs 文件中的 DependencyService.Register 解决了这个问题:

 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();
    }

最后,在 SearchGamePage 构造函数中,我像这样分配给 BindingContext SearchViewModel:

 public SearchGamePage()
 {
        InitializeComponent();
        BindingContext = DependencyService.Get<SearchViewModel>();
 }

现在,当我使用 Messenger 为 GamesViewModel 中的 SearchGame 属性 赋值时一切正常,我可以在 SearchViewModel 中的 SearchGame 属性 中看到相同的值,因为未重新创建此 ViewModel。

我知道我在提问时没有提供完整的信息。但我希望如果其他人会遇到同样的问题,这个答案会有用。