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。
我知道我在提问时没有提供完整的信息。但我希望如果其他人会遇到同样的问题,这个答案会有用。
我致力于使用 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。
我知道我在提问时没有提供完整的信息。但我希望如果其他人会遇到同样的问题,这个答案会有用。