当子页面视图模型中更新时,如何刷新父级中的可观察集合?

问题描述 投票:0回答:1

我有一个带有选项卡的毛伊岛应用程序。在 DashboardMainPage 上,项目显示在 CollectionView 中。从此页面中,我可以导航到子页面(GoalsPage),其中可以更详细地查看所有项目。在GoalsPage 中,我可以导航到另一个子页面 (CreateGoalPage),其中可以将新目标保存到本地数据库。

导航流程(使用 shell 导航,Shell.Current.GoToAsync):

仪表板主页面 -> 目标页面 -> 创建目标页面

public partial class DashboardMainViewModel : BaseViewModel
{
    // The repository to handle CRUD to local db
    private readonly IUnitOfWork _unitOfWork;
    public ObservableCollection<Goal> Goals { get; } = new ObservableCollection<Goal>();

    public DashboardMainViewModel(IUnitOfWork unitOfWork, INavigationService navigationService) : base(navigationService)
    {
        _unitOfWork = unitOfWork;
    }

    // This is called from OnAppearing of DashboardMainPage
    internal async Task InitializeAsync()
    {
        if (IsInitialized)  // Prevents LoadDataAsync running multiple times when navigate on and navigate back from subpage
        {
            return;
        }

        await LoadDataAsync();
    }
    
    private async Task LoadDataAsync()
    {
        Goals.Clear();

        var goalsTask =  _unitOfWork.Goal.GetAllAsync(_ => _.Completed == false);
        Goals.AddRange(goalsTask);
    }

    [RelayCommand]
    private async Task GoToGoalsPage() => await NavigationService.GoToAsync(nameof(GoalsPage));
}

public partial class GoalsViewModel : BaseViewModel
{
    private readonly IUnitOfWork _unitOfWork;
    public ObservableCollection<Goal> OnGoingGoals { get; } = new ObservableCollection<Goal>();
    public ObservableCollection<Goal> CompletedGoals { get; } = new ObservableCollection<Goal>();

    public GoalsViewModel(IUnitOfWork unitOfWork, INavigationService navigationService) : base(navigationService)
    {
        _unitOfWork = unitOfWork;     
    }
    
    // This is called from OnAppearing of DashboardMainPage
    internal async Task InitializeAsync()
    {
        if (IsInitialized) // Prevents LoadDataAsync running multiple times when navigate on and navigate back from subpage
        {
            return;
        }

        await LoadDataAsync();
    }

    private async Task LoadDataAsync()
    {
        OnGoingGoals.Clear();
        CompletedGoals.Clear();

        var goals = await _unitOfWork.Goal.GetAllAsync();
        var completed = goals.Where(_ => _.IsCompleted).OrderByDescending(_ => _.Completed.Date);

        OnGoingGoals.AddRange(goals.Where(_ => !_.IsCompleted));
        CompletedGoals.AddRange(completed);
    }

    [RelayCommand]
    private async Task GoToGoalCreatePage()
    {
        var goal = new Goal();
        
        var parameters = new Dictionary<string, object> {
            { nameof(Goal), goal }
        };
        await NavigationService.GoToAsync(nameof(GoalCreatePage), parameters);
    }
}

[QueryProperty(nameof(Goal), nameof(Goal))]
[QueryProperty(nameof(IsEdit), nameof(IsEdit))]
public partial class GoalCreateViewModel : BaseViewModel
{
    // The repository to handle CRUD to local db
    private readonly IUnitOfWork _unitOfWork;

    [ObservableProperty]
    private Goal _goal;

    public GoalCreateViewModel(IUnitOfWork unitOfWork, INavigationService navigationService) : base(navigationService)
    {
        _unitOfWork = unitOfWork;
    }

    [RelayCommand]
    private async Task Save()
    {
        var savedGoal = await _unitOfWork.Goal.SaveAsync(Goal);
        if (savedGoal is not null)
        {
            // should I trigger here a weakreference to call item in the both parent vms?
            
            // Navigate back to GoalsPage
            await NavigationService.GoBackAsync();
        }
    }
}

问题 当子子页面中添加了新的目标时,如何更新两个父页面?

  • 我应该使用弱引用(似乎反对 mvvm)吗?
  • 事实上我使用了两次相同的列表,有没有办法可以创建一个可以在所有虚拟机中访问的可观察集合? (DashboardMainViewModel,GoalsViewModel和CreateGoalViewModel),当本地保存时,我可以添加为Goals.Add(NewGoal)?它应该是 BaseViewModel 的一部分吗?
mvvm maui
1个回答
0
投票

还有另一种选择。您可以创建一个 IDateStore 并准备其数据,然后再移动到新的内容页面并在另一个视图模型中接收它。这是示例代码供参考。

  public interface IDataStore
        {
            void AddCalender(CalendarEvent item);
            CalendarEvent GetCalendarEvent();
            
        }

//implementation 
 public class DataStore : IDataStore
    {
        private CalendarEvent calendarEvent;
        public void AddCalender(CalendarEvent item)
        {
            calendarEvent = item;
        }
       public CalendarEvent GetCalendarEvent()
        {
            return calendarEvent;
        }

//register singleton
 builder.Services.AddSingleton<IDataStore, DataStore>();

//Prepare data for another viewmodel
var dataStore = serviceProvider.GetService<IDataStore>();
                    dataStore?.AddCalender(item);
            var popup = serviceProvider.GetService<EventDetailPopup>();
                popupService.ShowPopup(popup);

//Received another viewmodel
    public partial class EventDetailsViewModel:BaseViewModel
        {
            [ObservableProperty]
            private CalendarEvent item;
     
            public EventDetailsViewModel(IDataStore dataStore)
            { 
                Item = dataStore.GetCalendarEvent();
            }
© www.soinside.com 2019 - 2024. All rights reserved.