question

mrizoiwe98 avatar image
0 Votes"
mrizoiwe98 asked LeonLu-MSFT commented

Update collection view item when Preference is changed

I have a predefined list of items in CollectionView and each item includes a checkbox. The checkbox is binded to a Preference. What I want to do is automatically update the checkbox in CollectionView when the preference is updated. How can I do this?

  public class AchievementsViewModule : BaseViewModel
     {
         public ObservableCollection<Achievement> Achievements { get; set; }
    
         public AchievementsViewModule()
         {
             Achievements = new ObservableCollection<Achievement>();
             Achievements.Add(new Achievement
             {
                 Title = "first title",
                 Subtitle = "first subtitle",
                 ImageUrl = "image.png",
                 Completed = Preferences.get("item1",False),
                 CompletedDate = DateTime.Now
             }); 
    Achievements.Add(new Achievement
             {
                 Title = "second title",
                 Subtitle = "second subtitle",
                 ImageUrl = "image.png",
                 Completed = Preferences.get("item2",False),
                 CompletedDate = DateTime.Now
             }); 
    Achievements.Add(new Achievement
             {
                 Title = "third title",
                 Subtitle = "third subtitle",
                 ImageUrl = "image.png",
                 Completed = Preferences.get("item3",False),
                 CompletedDate = DateTime.Now
             }); 
         
    
     }

In a separate page, a button changes the Preference value:

 private void Button_Clicked(object sender, EventArgs e)
       {
           Preferences.Set("item2", True);
       }

And here's the Achievement module

   public class Achievement
    {
         public string Title { get; set; }
         public string Subtitle { get; set; }
    
        public DateTime CompletedDate { get; set; }
        public Boolean Completed { get; set; }
        public string ImageUrl { get; set; }
    }

The XAML for Achievements page:

 <?xml version="1.0" encoding="utf-8" ?>
 <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
              xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
              x:Class="App1.Views.AchievementsPage"
              xmlns:viewmodels="clr-namespace:App1.ViewModels"
              xmlns:model="clr-namespace:App1.Models"
              x:DataType="model:Achievement">
     <ContentPage.BindingContext>
         <viewmodels:AchievementsViewModule></viewmodels:AchievementsViewModule>
     </ContentPage.BindingContext>
    
    
     <StackLayout>
         <CollectionView x:DataType="viewmodels:AchievementsViewModule"
                         SelectionMode="Single"
             ItemsSource= "{Binding Achievements}"
             SelectionChanged="CollectionView_SelectionChanged">
                
             <CollectionView.ItemTemplate>
                 <DataTemplate>
                     <Grid Padding="10"
                       x:DataType="model:Achievement"
                      RowDefinitions="Auto, *"
                       ColumnDefinitions="Auto, *">
                         <Image Grid.RowSpan="2" BackgroundColor="Red"
                        Source="{Binding ImageUrl}"
                        Aspect="AspectFill"
                        HeightRequest="50"
                        WidthRequest="50" />
                         <Label Grid.Column="1" HorizontalOptions="StartAndExpand" BackgroundColor="Green"
                        Text="{Binding Title}"
                        FontAttributes="Bold" />
                         <Label Grid.Row="1" HorizontalOptions="Start" BackgroundColor="Yellow"
                        Grid.Column="1"
                        Text="{Binding Subtitle}"
                        VerticalOptions="End" />
                         <CheckBox Grid.RowSpan="2" 
                     "Grid.Column="3" 
                      IsChecked="{Binding Completed}"  </CheckBox>
    
                     </Grid>
                 </DataTemplate>
             </CollectionView.ItemTemplate>
         </CollectionView>
    
     </StackLayout>
 </ContentPage>











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.

1 Answer

LeonLu-MSFT avatar image
0 Votes"
LeonLu-MSFT answered LeonLu-MSFT commented

Hello,​

Welcome to our Microsoft Q&A platform!

No. I cannot find any Api to monitor Preference value changed event. You just could monitor the property of Achievement changed event, then you can update value in the sharePreference.

But you change the value of Preference in other pages, this page will disappear, when this page appears, all the value will be added again, Completed = Preferences.Get("item2", false), will be executed again, So the value will be changed. No need to mintor it.

You can delete ContentPage.BindingContext in the XAML. Here is my xaml layout

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:viewmodels="clr-namespace:App76"
             x:Class="App76.Page1">
    <!--<ContentPage.BindingContext>
        <viewmodels:AchievementsViewModule></viewmodels:AchievementsViewModule>
    </ContentPage.BindingContext>-->

    <StackLayout>
        <Button Text="navi" Clicked="Button_Clicked"></Button>
        <CollectionView x:DataType="viewmodels:AchievementsViewModule"
                         SelectionMode="Single"
             ItemsSource= "{Binding Achievements}"
             SelectionChanged="CollectionView_SelectionChanged">

            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <Grid Padding="10"
                       x:DataType="viewmodels:Achievement"
                      RowDefinitions="Auto, *"
                       ColumnDefinitions="Auto, *">
                        <Image Grid.RowSpan="2" BackgroundColor="Red"
                        Source="{Binding ImageUrl}"
                        Aspect="AspectFill"
                        HeightRequest="50"
                        WidthRequest="50" />
                        <Label Grid.Column="1" HorizontalOptions="StartAndExpand" BackgroundColor="Green"
                        Text="{Binding Title}"
                        FontAttributes="Bold" />
                        <Label Grid.Row="1" HorizontalOptions="Start" BackgroundColor="Yellow"
                        Grid.Column="1"
                        Text="{Binding Subtitle}"
                        VerticalOptions="End" />
                        <CheckBox 
                            Grid.RowSpan="2" 
                            Grid.Column="3"
                            IsChecked="{Binding Completed}">
                        </CheckBox>

                    </Grid>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>

    </StackLayout>
</ContentPage>


Here is layout's background code. add bindingContext in the OnAppearing method, remove it in the OnDisappearing method.

public partial class Page1 : ContentPage
    {
        public Page1()
        {
            InitializeComponent();
        
        }

        private void CollectionView_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {

        }
        protected override void OnAppearing()
        {
            base.OnAppearing();

            this.BindingContext = new AchievementsViewModule();
        }

        protected override void OnDisappearing()
        {
            base.OnDisappearing();

            this.BindingContext = null;
        }
        private void Button_Clicked(object sender, EventArgs e)
        {
            Navigation.PushModalAsync(new Page2());
        }
    }
}






===================Update=========================

If you want to use MessageCenter, that is Ok, that is the same achievment.


When you click the Button set the new value for Preference in other pages. Send a message.

private void Button_Clicked(object sender, EventArgs e)
        {
            var res=Preferences.Get("item2", false);

            Preferences.Set("item2", !res);

            MessagingCenter.Send<App, string>((App)App.Current, "OneMessage", "");
        }



In the AchievementsViewModule.cs code, you can remove all data from ObservableCollection, then re-add it in the MessagingCenter.Subscribe.

public class AchievementsViewModule : BaseViewModel
    {
        public ObservableCollection<Achievement> Achievements { get; set; }

        public AchievementsViewModule()
        {
            Achievements = new ObservableCollection<Achievement>();



            Achievements.Add(new Achievement
            {
                Title = "first title",
                Subtitle = "first subtitle",
                ImageUrl = "image.png",
                Completed = Preferences.Get("item1", false),
                CompletedDate = DateTime.Now
            });
            Achievements.Add(new Achievement
            {
                Title = "second title",
                Subtitle = "second subtitle",
                ImageUrl = "image.png",
                Completed = Preferences.Get("item2", false),
                CompletedDate = DateTime.Now
            });
            Achievements.Add(new Achievement
            {
                Title = "third title",
                Subtitle = "third subtitle",
                ImageUrl = "image.png",
                Completed = Preferences.Get("item3", false),
                CompletedDate = DateTime.Now
            });

            MessagingCenter.Subscribe<App, string>(App.Current, "OneMessage", (snd, arg) =>
            {
                Device.BeginInvokeOnMainThread(() => {
                    Achievements.Clear();

                    Achievements.Add(new Achievement
                    {
                        Title = "first title",
                        Subtitle = "first subtitle",
                        ImageUrl = "image.png",
                        Completed = Preferences.Get("item1", false),
                        CompletedDate = DateTime.Now
                    });
                    Achievements.Add(new Achievement
                    {
                        Title = "second title",
                        Subtitle = "second subtitle",
                        ImageUrl = "image.png",
                        Completed = Preferences.Get("item2", false),
                        CompletedDate = DateTime.Now
                    });
                    Achievements.Add(new Achievement
                    {
                        Title = "third title",
                        Subtitle = "third subtitle",
                        ImageUrl = "image.png",
                        Completed = Preferences.Get("item3", false),
                        CompletedDate = DateTime.Now
                    });
                });
            });
        }
    }

    public class Achievement
    {
        public string Title { get; set; }
        public string Subtitle { get; set; }

        public DateTime CompletedDate { get; set; }
        public Boolean Completed { get; set; }
        public string ImageUrl { get; set; }
    }
}


Best Regards,

Leon Lu



If the response is helpful, please click "Accept Answer" and upvote it.

Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.




· 4
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.

Would MessagingCenter also work? I am using tabs in my app so I wouldn't need the OnAppearing,Dissappearing methods. Would that still change anything?

0 Votes 0 ·

@mrizoiwe98 Please see my updated answer.

0 Votes 0 ·

I added the Subscribe event to the constructor like you said, but nothing is happening when I press the button.

0 Votes 0 ·
Show more comments