每次打开页面时都使用新的 ViewModel
Using new ViewModel each time I open a page
我不知道如何更好地表达标题,所以我采用了我想到的解决方案。
问题来了。我有一个包含列表的页面,列表中的每个项目都会打开一个详细信息页面(单击时)。但是 VM 被重用,这给我带来了几个问题。
打开详情页可以瞬间看到之前的数据
我需要在页面打开时将某些属性设置为特定值,但由于 VM 被重复使用,它保留了之前细节中的所有值,这打乱了我的逻辑。
这个 UWP 应用程序。我正在使用 Template10 框架的 NavigationService 在页面之间移动。
主页视图模型
public class MainPageViewModel : ViewModelBase {
private List<MangaItem> _mangaList;
public List<MangaItem> mangaList {
get { return _mangaList; }
set { Set(ref _mangaList, value); }
}
private string _mainSearchText;
public string mainSearchText {
get { return _mainSearchText; }
set { Set(ref _mainSearchText, value); }
}
public MainPageViewModel() {
_mangaList = new List<MangaItem>();
mangaList = new List<MangaItem>();
Initialize();
}
private async void Initialize() {
mangaList = await MangaListGet.GetListAsync();
}
public async void MainSearchSubmitted() {
mangaList = await MangaListGet.GetListAsync(_mainSearchText);
}
public void MangaSelected(object sender, ItemClickEventArgs e) {
var mangaItem = (MangaItem)e.ClickedItem;
NavigationService.Navigate(typeof(Views.MangaDetail), mangaItem.id);
}
}
和详细信息页面 ViewModel
class MangaDetailViewModel : ViewModelBase {
private MangaItem _mangaDetail;
public MangaItem mangaDetail {
get { return _mangaDetail; }
set { Set(ref _mangaDetail, value); }
}
private string _mangaId;
public override async Task OnNavigatedToAsync(object parameter, NavigationMode mode, IDictionary<string, object> suspensionState) {
_mangaId = parameter as string;
Initialize();
await Task.CompletedTask;
}
private async void Initialize() {
mangaDetail = await MangaDetailGet.GetAsync(_mangaId);
}
public void ChapterSelected(object sender, ItemClickEventArgs e) {
var _chapterId = (ChapterListItem)e.ClickedItem;
NavigationService.Navigate(typeof(Views.ChapterPage), _chapterId.id);
}
}
此代码仅显示第一个问题是瞬间显示先前加载的数据。如果需要,我将添加代码来展示其他问题,但我不确定它现在是否真的相关。我在想,也许我的整个逻辑都有缺陷或者什么的。
编辑:
<Page.DataContext>
<vm:ChapterPageViewModel x:Name="ViewModel" />
</Page.DataContext>
其中 vm 是 xmlns:vm="using:MangaReader.ViewModels"
.
虽然 Template10 文档声明 NavigationCacheMode
默认情况下处于禁用状态,但在其示例模板中并非如此(截至撰写本文时)。这是在查看 C# 代码(.xaml.cs 文件)中设置的。
.xaml.cs 文件
namespace MangaReader.Views {
public sealed partial class MangaDetail : Page {
public MangaDetail() {
InitializeComponent();
//NavigationCacheMode = Windows.UI.Xaml.Navigation.NavigationCacheMode.Enabled; //this was set by default
NavigationCacheMode = Windows.UI.Xaml.Navigation.NavigationCacheMode.Disabled;
}
}
}
现在,每次访问此页面时都会创建新的 ViewModel。
另一种解决方案是使用 Bootstrapper.ResolveforPage() ,它旨在处理依赖注入,但很容易满足您的需求。像这样:
[Bindable]
sealed partial class App : BootStrapper
{
static ViewModels.DetailPageViewModel _reusedDetailPageViewModel;
public override INavigable ResolveForPage(Page page, NavigationService navigationService)
{
if (page.GetType() == typeof(Views.DetailPage))
{
if (_reusedDetailPageViewModel == null)
{
_reusedDetailPageViewModel = new ViewModels.DetailPageViewModel();
}
return _reusedDetailPageViewModel;
}
else
{
return null;
}
}
}
NavigationService 会将此视为与任何其他视图模型相同。这意味着它将调用 OnNavTo() 和您包含的其他导航覆盖。
祝你好运。
我不知道如何更好地表达标题,所以我采用了我想到的解决方案。
问题来了。我有一个包含列表的页面,列表中的每个项目都会打开一个详细信息页面(单击时)。但是 VM 被重用,这给我带来了几个问题。
打开详情页可以瞬间看到之前的数据
我需要在页面打开时将某些属性设置为特定值,但由于 VM 被重复使用,它保留了之前细节中的所有值,这打乱了我的逻辑。
这个 UWP 应用程序。我正在使用 Template10 框架的 NavigationService 在页面之间移动。
主页视图模型
public class MainPageViewModel : ViewModelBase {
private List<MangaItem> _mangaList;
public List<MangaItem> mangaList {
get { return _mangaList; }
set { Set(ref _mangaList, value); }
}
private string _mainSearchText;
public string mainSearchText {
get { return _mainSearchText; }
set { Set(ref _mainSearchText, value); }
}
public MainPageViewModel() {
_mangaList = new List<MangaItem>();
mangaList = new List<MangaItem>();
Initialize();
}
private async void Initialize() {
mangaList = await MangaListGet.GetListAsync();
}
public async void MainSearchSubmitted() {
mangaList = await MangaListGet.GetListAsync(_mainSearchText);
}
public void MangaSelected(object sender, ItemClickEventArgs e) {
var mangaItem = (MangaItem)e.ClickedItem;
NavigationService.Navigate(typeof(Views.MangaDetail), mangaItem.id);
}
}
和详细信息页面 ViewModel
class MangaDetailViewModel : ViewModelBase {
private MangaItem _mangaDetail;
public MangaItem mangaDetail {
get { return _mangaDetail; }
set { Set(ref _mangaDetail, value); }
}
private string _mangaId;
public override async Task OnNavigatedToAsync(object parameter, NavigationMode mode, IDictionary<string, object> suspensionState) {
_mangaId = parameter as string;
Initialize();
await Task.CompletedTask;
}
private async void Initialize() {
mangaDetail = await MangaDetailGet.GetAsync(_mangaId);
}
public void ChapterSelected(object sender, ItemClickEventArgs e) {
var _chapterId = (ChapterListItem)e.ClickedItem;
NavigationService.Navigate(typeof(Views.ChapterPage), _chapterId.id);
}
}
此代码仅显示第一个问题是瞬间显示先前加载的数据。如果需要,我将添加代码来展示其他问题,但我不确定它现在是否真的相关。我在想,也许我的整个逻辑都有缺陷或者什么的。
编辑:
<Page.DataContext>
<vm:ChapterPageViewModel x:Name="ViewModel" />
</Page.DataContext>
其中 vm 是 xmlns:vm="using:MangaReader.ViewModels"
.
虽然 Template10 文档声明 NavigationCacheMode
默认情况下处于禁用状态,但在其示例模板中并非如此(截至撰写本文时)。这是在查看 C# 代码(.xaml.cs 文件)中设置的。
.xaml.cs 文件
namespace MangaReader.Views {
public sealed partial class MangaDetail : Page {
public MangaDetail() {
InitializeComponent();
//NavigationCacheMode = Windows.UI.Xaml.Navigation.NavigationCacheMode.Enabled; //this was set by default
NavigationCacheMode = Windows.UI.Xaml.Navigation.NavigationCacheMode.Disabled;
}
}
}
现在,每次访问此页面时都会创建新的 ViewModel。
另一种解决方案是使用 Bootstrapper.ResolveforPage() ,它旨在处理依赖注入,但很容易满足您的需求。像这样:
[Bindable]
sealed partial class App : BootStrapper
{
static ViewModels.DetailPageViewModel _reusedDetailPageViewModel;
public override INavigable ResolveForPage(Page page, NavigationService navigationService)
{
if (page.GetType() == typeof(Views.DetailPage))
{
if (_reusedDetailPageViewModel == null)
{
_reusedDetailPageViewModel = new ViewModels.DetailPageViewModel();
}
return _reusedDetailPageViewModel;
}
else
{
return null;
}
}
}
NavigationService 会将此视为与任何其他视图模型相同。这意味着它将调用 OnNavTo() 和您包含的其他导航覆盖。
祝你好运。