MAUI页面ObservableCollection数据变更时未正确刷新问题求助
MAUI MVVM课表切换场地后旧数据残留问题
问题描述
我使用MAUI结合MVVM模式开发校园场地/教室课表展示应用,采用ObservableCollection存储每周各天的时段数据。首次选择场地时课表显示正常,但切换Picker中的场地后,新场地信息展示的同时仍保留旧数据,我已执行ObservableCollection的清空与重新添加操作。
ViewModel代码
namespace SchoolTime.Maui.ViewModels { public partial class TimeTableViewModel : ObservableObject, INotifyPropertyChanged { private readonly IViewVenuesUseCase viewVenuesUseCase; private readonly IViewTimeTableUseCase viewTimeTableUseCase; private readonly ICalculateTimeTableUseCase calculateTimeTable; private readonly IViewTeacherUseCase viewTeacherUseCase; private readonly ISchoolTimeRepository schoolTimeRepository; public ObservableCollection<Venue> Venues { get; set; } public ObservableCollection<TimeSlot> TimeSlots { get; set; } public ObservableCollection<Period> MondayPeriods { get; } // Collection of enum names for the Picker's ItemsSource public List<string> RosterViews { get; } = Enum.GetNames(typeof(Enum_RosterViews)).ToList(); // Property to bind to the Picker's SelectedItem [ObservableProperty] private string _selectedRosterView; // Property to bind to the Label [ObservableProperty] private string _selectedObjectDetail; // Property to bind to the Label [ObservableProperty] private string _periodCount; // Property to hold the selected item [ObservableProperty] private Venue _selectedVenue; private int displayItemCount = 0; public TimeTableViewModel(IViewVenuesUseCase viewVenuesUseCase, IViewTimeTableUseCase viewTimeTableUseCase, ICalculateTimeTableUseCase calculateTimeTable, IViewTeacherUseCase viewTeacherUseCase, ISchoolTimeRepository schoolTimeRepository) { Venues = new ObservableCollection<Venue>(); TimeSlots = new ObservableCollection<TimeSlot>(); MondayPeriods = new ObservableCollection<Period>(); this.viewVenuesUseCase = viewVenuesUseCase; this.viewTimeTableUseCase = viewTimeTableUseCase; this.calculateTimeTable = calculateTimeTable; this.viewTeacherUseCase = viewTeacherUseCase; this.schoolTimeRepository = schoolTimeRepository; LoadTimeSlotsAsync(); } partial void OnSelectedRosterViewChanged(string value) { displayItemCount = 0; if (_selectedRosterView == "Venue") { LoadVenuesAsync(); if (Venues != null && Venues.Count > 0) { SelectedVenue = Venues[displayItemCount]; SelectedObjectDetail = SelectedVenue.Name; GetRosterByVenue(); } } } public async Task LoadVenuesAsync() { this.Venues.Clear(); var venues = await this.viewVenuesUseCase.GetVenuesAsync(); if (venues != null && venues.Count > 0) { foreach (var venue in venues) { this.Venues.Add(venue); } } } [RelayCommand] public async Task GoToMainPage() { await Shell.Current.GoToAsync($"{nameof(SchoolTimePage)}"); } [RelayCommand] public async Task PreviousItem() { displayItemCount--; if (SelectedRosterView == "Venue") { if (Venues != null && Venues.Count > 0) { if (displayItemCount < 0) { displayItemCount = Venues.Count - 1; } SelectedVenue = Venues[displayItemCount]; if (SelectedVenue.Name == "Class 25") { int k = 0; } SelectedObjectDetail = SelectedVenue.Name; await GetRosterByVenue(); } } } [RelayCommand] public async Task NextItem() { displayItemCount++; if (SelectedRosterView == "Venue") { if (Venues != null && Venues.Count > 0) { if (displayItemCount >= Venues.Count) { displayItemCount = 0; } SelectedVenue = Venues[displayItemCount]; SelectedObjectDetail = SelectedVenue.Name; await GetRosterByVenue(); } } } public async Task LoadTimeSlotsAsync() { this.TimeSlots.Clear(); var slots = await this.viewTimeTableUseCase.GetTimeSlotsAsync(); if (slots != null && slots.Count > 0) { foreach (var slot in slots) { this.TimeSlots.Add(slot); } } } [RelayCommand] public async Task CalculateRosters() { bool result = await Application.Current.MainPage.DisplayAlert( "MESSAGE", "This will override existing rosters. Do you want to continue?", "OK", "Cancel"); if (result) { await Application.Current.MainPage.DisplayAlert( "MESSAGE", "Calculating Rosters", "OK"); await calculateTimeTable.CalculateRostersBySubject(); } } [RelayCommand] public async Task GetRosterByVenue() { MondayPeriods.Clear(); if (SelectedVenue != null) { List<Period> periods = await this.viewTimeTableUseCase.GetPeriodsByVenueAsync(_selectedVenue.Id); PeriodCount = "Periods: " + periods.Count; await OrganisePeriods(periods); } else { return; } } private async Task OrganisePeriods(List<Period> periods) { DayOfTheWeek day = null; SubjectClass subjectClass = null; Teacher teacher = null; Subject subject = null; List<Period> MondayRoster = new List<Period>(); await PrepareRoster(MondayRoster); if (periods != null) { foreach (Period period in periods) { day = await this.viewTimeTableUseCase.GetDayOfWeekByIdAsync(period.DayOfWeekId); subjectClass = await this.schoolTimeRepository.GetSubjectClassByIdAsync(period.SubjectClassId); teacher = await this.viewTeacherUseCase.GetTeacherByIdAsync(subjectClass.TeacherId); subject = await this.viewTimeTableUseCase.GetSubjectByIdAsync(subjectClass.SubjectId); period.Teacher = teacher; period.Subject = subject; // Get Index of TimeSlot for this period // TODO Improve on this int slotId = period.TimeSlotId; // For this the first Id of list is 1 int slotIndex = slotId - 1; switch (day.Day) { case DayOfWeek.Monday: MondayRoster[slotIndex] = period; break; } } } await CopyRoster(MondayPeriods, MondayRoster); } private async Task PrepareRoster(List<Period> dayPeriods) { dayPeriods.Clear(); for (int i = 0; i < TimeSlots.Count; i++) { dayPeriods.Add(null); } } private async Task CopyRoster(ObservableCollection<Period> periods, List<Period> roster) { periods.Clear(); foreach (var period in roster) { periods.Add(period); } } } }
ContentPage代码
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:vm="clr-namespace:SchoolTime.Maui.ViewModels" xmlns:m="clr-namespace:SchoolTime.CoreBusiness;assembly=SchoolTime.CoreBusiness" xmlns:controls="clr-namespace:SchoolTime.Maui.Views.Controls" x:DataType="vm:TimeTableViewModel" x:Class="SchoolTime.Maui.Views.TimeTablePage" Title="Time Table Page"> <Grid RowDefinitions="70, 50, *, 50"> <HorizontalStackLayout Grid.Row="0" Spacing="20" Margin="20,0,20,10"> <Picker ItemsSource="{Binding RosterViews}" SelectedItem="{Binding SelectedRosterView, Mode=TwoWay}" Title="View roster by" > </Picker> <Button Text="Previous" Command="{Binding PreviousItemCommand}"> </Button> <Label Text="{Binding SelectedObjectDetail}" VerticalTextAlignment="Center"> </Label> <Button Text="Next" Command="{Binding NextItemCommand}"> </Button> <Label Text="{Binding PeriodCount}" VerticalTextAlignment="Center"> </Label> </HorizontalStackLayout> <Grid Grid.Row="2" ColumnDefinitions="0.5*, *, *, *, *, *" Margin="10,0,10,0"> <CollectionView Grid.Column="1" ItemsSource="{Binding MondayPeriods}"> <CollectionView.ItemsLayout> <GridItemsLayout Orientation="Vertical"/> </CollectionView.ItemsLayout> <CollectionView.ItemTemplate> <DataTemplate x:DataType="m:Period"> <Grid Padding="0,0,0,0" RowDefinitions="{Binding Periods.Count}"> <Border> <controls:PeriodControl BindingContext="{Binding .}"> </controls:PeriodControl> </Border> </Grid> </DataTemplate> </CollectionView.ItemTemplate> </CollectionView> </Grid> <Button Grid.Row="3" Grid.Column="0" Text="Home" Command="{Binding GoToMainPageCommand}" ></Button> <Button Grid.Row="3" Grid.Column="1" Text="Calculate Rosters" HorizontalOptions="End" Command="{Binding CalculateRostersCommand}"></Button> </Grid> </ContentPage>
内容的提问来源于stack exchange,提问作者Sabre
相关产品推荐
相关产品推荐

