question

MartinWhitman-9960 avatar image
0 Votes"
MartinWhitman-9960 asked MartinWhitman-9960 answered

Adding to ObservableCollection does not refresh bound view

I have an ObservableCollection bound to a view. Adding to the collection from another ViewModel doesn't change the view after addition. Closing the app and reopening does, though.

Here's the View:

 <CollectionView Grid.Row="2" x:Name="ProjectsCollectionView" x:DataType="vm:LandingViewModel"
                 ItemsSource="{Binding Projects}"
                 SelectionMode="None">
                 <CollectionView.ItemTemplate>
                     <DataTemplate>
                     <Frame BorderColor="Black" CornerRadius="10" HasShadow="False" Padding="5">
                         <StackLayout Orientation="Vertical" Padding="5" x:DataType="model:MProject">
                             <Label Text="{Binding projectname}" 
                             LineBreakMode="NoWrap" 
                             Style="{DynamicResource ListItemTextStyle}" 
                             FontSize="16" />
                             <Label Text="{Binding facilityname}" 
                             LineBreakMode="NoWrap"
                             Style="{DynamicResource ListItemDetailTextStyle}"
                             FontSize="13" />
                             <StackLayout.GestureRecognizers>
                                 <TapGestureRecognizer 
                                 NumberOfTapsRequired="1"
                                 Command="{Binding Source={RelativeSource AncestorType={x:Type vm:LandingViewModel}}, Path=ItemTapped}"        
                                 CommandParameter="{Binding .}">
                                 </TapGestureRecognizer>
                             </StackLayout.GestureRecognizers>
                         </StackLayout>
                     </Frame>
                 </DataTemplate>
                 </CollectionView.ItemTemplate>
             </CollectionView>
dotnet-xamarin
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

MartinWhitman-9960 avatar image
0 Votes"
MartinWhitman-9960 answered

I "solved" it by doing the following: switching the BindingContext declaration from XAML to code behind, and overriding the OnAppearing method to LoadProjects(). I still feel like I'm missing something.

 private LandingViewModel _viewModel = new LandingViewModel();
         public LandingPage()
         {
             InitializeComponent();
             BindingContext = _viewModel;
         }
    
         protected async override void OnAppearing()
         {
             base.OnAppearing();
             _viewModel.LoadProjects();
         }


5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

MartinWhitman-9960 avatar image
0 Votes"
MartinWhitman-9960 answered

Here's the ViewModel for that view:

 public class LandingViewModel : BaseViewModel
     {
         private static LandingViewModel _instance = new LandingViewModel();
         public static LandingViewModel Instance { get { return _instance; } }
         private MProject _selectedMProject;
         //private ObservableCollection<MProject> _projects;
         public Command<MProject> ProjectTapped { get; }
    
         public ObservableCollection<MProject> Projects { get; set; }
    
         public ICommand OpenWebCommand { get; }
         public Command AddProjectCommand { get; set; }
         public LandingViewModel()
         {
             Projects = new ObservableCollection<MProject>();
             Title = "Landing";
             OpenWebCommand = new Command(async () => await Browser.OpenAsync("https://aka.ms/xamarin-quickstart"));
             ProjectTapped = new Command<MProject>(OnProjectSelected);
             AddProjectCommand = new Command(OnAddProject);
             LoadProjects();
         }
    
         public async void LoadProjects()
         {
             LocalDB localDB = await LocalDB.Instance;
             var list = await localDB.GetProjectsAsync();
             Projects.Clear();
             foreach(var k in list)
             {
                 Projects.Add(k);
             }
         }
    
         public void OnAppearing()
         {
             IsBusy = true;
             SelectedMProject = null;
         }        }
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

MartinWhitman-9960 avatar image
0 Votes"
MartinWhitman-9960 answered

Here's the code from the other viewmodel that adds the new item to the ObservableCollection but doesn't trigger a view refresh:

 private async void OnSave()
         {
             MProject newProject = new MProject()
             {
                 ///assignments here
             };
    
             //await DataStore.AddProjectAsync(newProject);
             LocalDB localDB = await LocalDB.Instance;
             await localDB.SaveProjectAsync(newProject,true);
             //LandingViewModel landingViewModel = new LandingViewModel();
             //landingViewModel.Projects.Clear();
             //foreach(var k in await localDB.GetProjectsAsync())
             //{
             //    landingViewModel.Projects.Add(k);
             //}
    
             LandingViewModel.Instance.Projects.Add(newProject);
             // This will pop the current page off the navigation stack
             await Shell.Current.GoToAsync("..");}


I feel like I'm missing something obvious. Should I create my observablecollection in the BaseViewModel, instead of using the instance variable to access it from the other ViewModel?

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.