我正在为我的Xamarin.Forms应用程序使用 Prism 框架。
这是一种常见的情况,但它使我头疼。
MainPage
- MainPageViewModel
- ObserveableCollection<SomePageViewModel>
public class MainPageViewModel : BaseViewModel
{
private ObservableCollection<SomePageViewModel> viewModels;
public MainPageViewModel(INavigationService navigationService) : base(navigationService)
{
SomePageSelectedCommand = DelegateCommand.FromAsyncHandler(NavigateToSomePage);
}
public ICommand SomePageSelectedCommand { get; private set; }
public ObservableCollection<SomePageViewModel> ViewModels
{
get { return viewModels; }
set { SetProperty(ref viewModels, value); }
}
private async Task NavigateToSomePage(SomePageViewModel viewModel)
{
var navParams = new NavigationParameters
{
{viewModel.typeof(SomePageViewModel).Name, viewModel}
};
await Navigation.NavigateAsync(NavigationConstants.SomePageUri, navParams, false);
}
}
public class SomePageViewModel : BaseViewModel
{
protected SomeModel someModel;
public SomePageViewModel(INavigationService navigationService) : base(navigationService)
{
someModel = new SomeModel();
EditCommand = DelegateCommand.FromAsyncHandler(Edit);
}
public ICommand EditCommand { get; private set; }
public string Name
{
get { return SomeModel.Name; }
set { SetProperty(ref SomeModel.Name, value); }
}
public string Description
{
get { return SomeModel.Description; }
set { SetProperty(ref SomeModel.Description, value); }
}
public override void OnNavigatedTo(NavigationParameters parameters)
{
if (parameters.ContainsKey(typeof(SomePageViewModel).Name))
{
var viewModel = (SomePageViewModel)parameters[typeof(SomePageViewModel).Name];
Name = viewModel.Name;
Description = viewModel.Name;
}
}
private async Task Edit()
{
var navParams = new NavigationParameters
{
{viewModel.typeof(SomePageViewModel).Name, this}
};
await Navigation.NavigateAsync(NavigationConstants.SomePageEditUri, navParams, false);
}
}
public class SomePageEditViewModel : BaseViewModel
{
public SomePageEditViewModel(INavigationService navigationService) : base(navigationService)
{
SaveCommand = DelegateCommand.FromAsyncHandler(Save);
}
public ICommand SaveCommand { get; private set; }
private async Task Save()
{
App.ContentService.Save(someModel);
await Navigation.GoBackAsync();
}
}
因此,让我们从
MainPage
导航到SomePage
。我们要对其进行编辑,因此我们随后导航至SomePageEdit
并最终保存。根据mvvm/prsim,使更改对SomePage和MainPage可见的正确方法是什么?对于第一个,我可以将更改作为NavigationParameter传递给GoBackAsync。但是MainPage呢?
最佳答案
好吧,看来您有一些设计问题。要正确构建您的应用,您需要以下方面:
模型
public class TodoItem : ObservableObject
{
private string _name;
public string Name
{
get { return _name; }
set { SetProperty(ref _name, value); }
}
private bool _done;
public bool Done
{
get { return _done; }
set { SetProperty(ref _done, value); }
}
}
模型集合页面ViewModel
public class TodoItemListPageViewModel : BaseViewModel, INavigationAware
{
private INavigationService _navigationService { get; }
public TodoItemListViewModel(INavigationService navigationService)
{
_navigationService = navigationService;
TodoItems = new ObservableRangeCollection<TodoItem>();
AddTodoItemCommand = new DelegateCommand(OnAddTodoItemCommandExecuted);
EditTodoItemCommand = new DelegateCommand<TodoItem>(OnEditTodoItemCommandExecuted);
}
public ObservableRangeCollection<TodoItem> TodoItems { get; }
public DelegateCommand AddTodoItemCommand { get; }
public DelegateCommand<TodoItem> EditTodoItemCommand { get; }
public void OnNavigatingTo(NavigationParameters parameters)
{
// Initialize your collection
}
public void OnNavigatedTo(NavigationParameters parameters)
{
if(parameters.GetValue<NavigationMode>(KnownNavigationParameters.NavigationMode) == NavigationMode.Back)
{
// Option 1
// Fetch an updated list of TodoItems from your data source
TodoItems.ReplaceRange(updatedTodoItems);
// Option 2
// Replace the updated item or add a new item
}
}
编辑模型页面ViewModel
public void OnNavigatedFrom(NavigationParameters parameters)
{
}
private async void OnAddTodoItemCommandExecuted() =>
await _navigationService.NavigateAsync("AddTodoItemPage");
private async void OnEditTodoItemCommandExecuted(TodoItem item) =>
await _navigationService.NavigateAsync("EditTodoItemPage", new NavigationParameters { { "item", item } });
}
public class EditTodoItemPageViewModel : BaseViewModel
{
private INavigationService _navigationService { get; }
public EditTodoItemPageViewModel(INavigationService navigationService)
{
_navigationService = navigationService;
SaveCommand = new DelegateCommand(OnSaveCommandExecuted, () => IsNotBusy)
.ObservesProperty(() => IsBusy);
}
private TodoItem _model;
public TodoItem Model
{
get { return _model; }
set { SetProperty(ref _model, value); }
}
public DelegateCommand SaveCommand { get; }
public void OnNavigatingTo(NavigationParameters parameters)
{
Model = parameters.GetValue<TodoItem>("item");
}
private async void OnSaveCommandExecuted()
{
IsBusy = true;
// Persist any changes
// Option 1
await _navigationService.GoBackAsync();
// Option 2
await _navigationService.GoBackAsync(new NavigationParameters { { "updatedItem", Model } });
IsBusy = false;
}
}
为什么...
您的ObservableCollection应该是
where T : TModel
而不是where T : TViewModel
。您将立即遇到的另一个问题是INavigationService
依赖于您知道要导航到/从哪个页面导航。因此,您无法按照自己的模式进行操作。现在这里有几个注意事项。
您会注意到该示例实际上正在使用MvvmHelpers库中的一些帮助器。该库中的BaseViewModel类为您提供IsBusy/IsNotBusy属性以及Title属性和ObservableRangeCollection。
ObservableRangeCollection与ObservableCollection
ObservableRangeCollection为您提供了更好的性能,尤其是在处理较大的数据集时。您可能已经注意到了选项1,在这里我们仅获取更新的数据集并替换整个数据集。在我看来,这就是ObservableRangeCollection真正发挥作用的地方,因为您可以确保拥有最新的数据集,同时将对UI的通知最小化,从而减少占用的CPU周期。
模型, View , View 模型
我的意思不是要有权威的答案,而是要至少提供思想上的帮助。从MVVM模式的高级概述中,您通常使用的是提供UX的View,提供了who/what/why/when/when/where/etc/etc的业务逻辑的ViewModel以及提供我们想要的数据的Model一起工作。在某些情况下,可能有必要引入DTO,该DTO进一步从我们要作为逻辑单元使用的模型中提取原始数据。
关于mvvm - Prism正确处理ViewModel集合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43957912/