question

Grime avatar image
0 Votes"
Grime asked Grime commented

The “Selected” status of a selection from a ListView is lost between operations and I need to reinstate it

I select an "Operator" from a ListView then use Xamarin.Essentials Preferences to store the various Operator attributes, as per SelectOperatorPage.xaml.cs:

 using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
    
 using Xamarin.Forms;
 using Xamarin.Forms.Xaml;
 using HandsFreeNotes.ViewModel;
 using HandsFreeNotes.Model;
 using HandsFreeNotes.Data;
    
 using Xamarin.Essentials;
    
 namespace HandsFreeNotes.View
 {
     [XamlCompilation(XamlCompilationOptions.Compile)]
     public partial class SelectOperatorPage : ContentPage
     {
         OperatorViewModel ovm;
    
         public EventHandler<OperatorModel> ReturnValue;
    
         public SelectOperatorPage()
         {
             // add a bit of padding to cater to the "notch" on the iPhone.
             if (Device.RuntimePlatform == Device.iOS) { Padding = new Thickness(0, 40, 0, 0); }
    
             InitializeComponent();
    
         }
    
         protected override async void OnAppearing()
         {
             base.OnAppearing();
    
             HFNDatabase database = await HFNDatabase.Instance;
             OperatorListView.ItemsSource = await database.GetOperatorsAsync();
    
         }
    
         private async void BackButton_Clicked(object sender, EventArgs e)
         {
             await Navigation.PopModalAsync();
         }
    
         private async void OperatorListView_ItemSelected(object sender, SelectedItemChangedEventArgs e)
         {
             if (e.SelectedItem != null)
             {
    
                 OperatorModel operatorModel = (OperatorModel)e.SelectedItem;
    
                 EventHandler<OperatorModel> handler = ReturnValue;
                 if (handler != null)
                 {
                     handler(this, operatorModel);
    
                     // Added these lines to set Xamarin.Essentials Preferences keys GMB: 07/06/2021
                     Preferences.Clear();
                     int selOpID = operatorModel.OperatorID;
                     string selOpName = operatorModel.OperatorName;
                     string selOpPhone = operatorModel.OperatorPhone;
                     string selOpEmail = operatorModel.OperatorEmail;
                     string selOpAvatar = operatorModel.OperatorAvatar;
                     Preferences.Set("selOpID_key", selOpID.ToString());
                     Preferences.Set("selOpName_key", selOpName);
                     Preferences.Set("selOpPhone_key", selOpPhone);
                     Preferences.Set("selOpEmail_key", selOpEmail);
                     Preferences.Set("selOpAvatar_key", selOpAvatar);
    
                     // DisplayAlert("Alert", selOpID.ToString() + " - " + selOpName + " - " + selOpPhone + " - " + selOpEmail + " - " + selOpAvatar, "Continue");
                 }
    
                 await Navigation.PopModalAsync();
             }
         }
     }
 }

When the app is later opened again, I reinstate the Operator Name ("selOpName") to a button name, but when I click on "Update Operator", the Operator is no longer selected. This happens in OperatorsPage.xaml.cs:

 using HandsFreeNotes.ViewModel;
 using HandsFreeNotes.Model;
 using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
    
 using Xamarin.Forms;
 using Xamarin.Forms.Xaml;
 using HandsFreeNotes.Data;
    
 namespace HandsFreeNotes.View
 {
     [XamlCompilation(XamlCompilationOptions.Compile)]
    
     public partial class OperatorsPage : ContentPage
     {
         OperatorViewModel ovm;
         OperatorModel opm;
    
         public EventHandler<OperatorModel> ReturnValue;
    
         public OperatorsPage(OperatorModel SelectModel)
    
         {
             // add a bit of padding to cater to the "notch" on the iPhone.
             if (Device.RuntimePlatform == Device.iOS) { Padding = new Thickness(0, 40, 0, 0); }
    
             InitializeComponent();
    
             if (SelectModel != null)
             {
                 opm = SelectModel;
             }
             else
             {
                 opm = new OperatorModel();
             }
    
             BindingContext = opm;
         }
    
         private async void BackButton_Clicked(object sender, EventArgs e)
         {
             if (SelectModel != null)
             {
                 EventHandler<OperatorModel> handler = ReturnValue;
                 if (handler !=null)
                 {
                     handler(this, opm);
                 }
             }
    
             await Navigation.PopModalAsync();
         }
    
         private async void AddOperatorButton_Clicked(object sender, EventArgs e)
         {
             await Navigation.PushModalAsync(new NewOperatorPage { 
               BindingContext = new OperatorModel()
             });
    
         }
    
         private async void SelectOperatorButton_Clicked(object sender, EventArgs e)
         {
             SelectOperatorPage page = new SelectOperatorPage();
             page.ReturnValue += delegate (object s, OperatorModel operatorModel)
             {
                 BackCall(s, operatorModel);
             };
    
             await Navigation.PushModalAsync(page);
         }
         OperatorModel SelectModel;
    
    
         private void BackCall(object s, OperatorModel model)
         {
             SelectModel = model;
             opm.OperatorName = model.OperatorName;
         }
    
         private async void DeleteOperatorButton_Clicked(object sender, EventArgs e)
         {
             if (SelectModel != null)
             {
                 bool answer = await DisplayAlert("Warning!", "Do you really want to delete Operator " + SelectModel.OperatorName, "Yes", "No");
    
                 if (answer == true)
                 {
                     HFNDatabase database = await HFNDatabase.Instance;
                     await database.DeleteItemAsync(SelectModel);
                     SelectModel = null;
                     SelectedOperatorEntry.Text = "";
                 }
             }
             else
             {
                 await DisplayAlert("Info", "Please select an Operator to delete", "OK");
             }
         }
         private async void UpdateOperatorButton_Clicked(object sender, EventArgs e)
         {
    
             if (SelectModel != null)
             {
                 var operatorInfoPage = new OperatorInfoPage(SelectModel);
                 operatorInfoPage.ReturnValue += delegate (object s, OperatorModel operatorModel)
                 {
                     BackCall(s, operatorModel);
                 };
                 await Navigation.PushModalAsync(operatorInfoPage);
             }
    
             else
             {
                 await DisplayAlert("Info", "Please select an Operator", "OK");
             }
         }
     }
 }

In the last method (UpdateOperatorButton_Clicked), I suspect I have to add an "else if" statement to rebuild the selection from my saved Preferences, potentially calling the BackCall method, but I'm floundering on how to do that.

dotnet-xamarin
· 2
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.

@Grime To handle the issue, there are some details need to be confirmed.
First, what does "Operator selected" mean? Item highlight in the listview? Or there is a property to save the selected Operator?
Second, what is the purpose of using Preferences? I see that you store an Operator object to Preferences, but never use it. Can you explain in detail what "the Operator is no longer selected" means?
Third, "UpdateOperatorButton_Clicked" is a method (open "OperatorInfoPage") in OperatorsPage, so how does it relate to the listview in the SelectOperatorPage?
Could you provide any more info, such as "page xaml", so that we can reproduce the issue?

0 Votes 0 ·

Thanks for responding @KyleWang-MSFT
You click on "an Operator" from a list of people in a ListView. This is then "the selected Operator".
I use Preferences to store certain stuff so I can reload that data when the app is opened at a later date. In particular, I can reload the button name of the previously selected Operator.
I will include the two XAML files calling the previously included C# files in an Answer (too big for a Reply).





0 Votes 0 ·
Grime avatar image
0 Votes"
Grime answered Grime edited

Thanks for responding @KyleWang-MSFT.
The calling XAML files are here:
SelectOperatorPage.xaml:

 <?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="HandsFreeNotes.View.SelectOperatorPage">
    
     <ContentPage.Content>
         <Grid BackgroundColor="White">
             <Grid.RowDefinitions>
                 <RowDefinition Height="40"/>
                 <RowDefinition Height="40"/>
                 <RowDefinition Height="80"/>
                 <RowDefinition Height="*"/>
                 <RowDefinition Height="50"/>
             </Grid.RowDefinitions>
    
             <Grid.ColumnDefinitions>
                 <ColumnDefinition Width="50"/>
                 <ColumnDefinition Width="*"/>
                 <ColumnDefinition Width="50"/>
             </Grid.ColumnDefinitions>
    
             <Button
                 x:Name="BackButton"
                 Text="Back"
                 Grid.Row="0"
                 Grid.Column="0"
                 Grid.ColumnSpan="3"
                 TextColor="Black"
                 FontAttributes="Bold"
                 HeightRequest="40"
                 VerticalOptions="CenterAndExpand"
                 HorizontalOptions="End"
                 Margin="0,0,20,0"
                 Clicked="BackButton_Clicked"/>
    
             <Image 
                 Source="hfn256"
                 Margin="2"
                 Grid.Row="1" 
                 Grid.Column="0"
                 Grid.ColumnSpan="3"
                 HorizontalOptions="Center"
                 BackgroundColor="Transparent"/>
    
             <Label 
                 Text="Select Operator..."
                 FontSize="Large"
                 TextColor="Black"
                 FontAttributes="Bold"
                 Grid.Row="2" 
                 Grid.Column="0"
                 Grid.ColumnSpan="3"
                 HorizontalOptions="Center"
                 VerticalOptions="Start"
                 Margin="20"
                 BackgroundColor="Transparent"/>
    
             <ListView
                 x:Name="OperatorListView"
                 Grid.Row="3"
                 Grid.Column="0"
                 Grid.ColumnSpan="3"
                 RowHeight="140"
                 ItemSelected="OperatorListView_ItemSelected">
                 <ListView.ItemTemplate>
                     <DataTemplate>
                         <ViewCell>
                             <ContentView>
                                 <Grid>
                                     <Grid.RowDefinitions>
                                         <RowDefinition Height="*"/>
                                     </Grid.RowDefinitions>
                                     <Grid.ColumnDefinitions>
                                         <ColumnDefinition Width="100"/>
                                         <ColumnDefinition Width="100"/>
                                         <ColumnDefinition Width="200"/>
                                     </Grid.ColumnDefinitions>
    
                                     <Image
                                         Source="{Binding OperatorAvatar}"
                                         Grid.Row="0"
                                         Grid.Column="0"
                                         HeightRequest="200"
                                         WidthRequest="100"/>
    
                                     <Label
                                         Text="{Binding OperatorName}"
                                         FontAttributes="Bold"
                                         HorizontalOptions="Start"
                                         VerticalOptions="Center"
                                         Grid.Row ="0"
                                         Grid.Column="1"/>
    
                                     <Label
                                         Text="{Binding OperatorEmail}"
                                         FontAttributes="Italic"
                                         FontSize="Micro"
                                         Grid.Row="0"
                                         Grid.Column="2"
                                         HeightRequest="30"
                                         HorizontalOptions="Start"
                                         VerticalOptions="Center"/>
    
                                     <Label
                                         Text="{Binding OperatorPhone}"
                                         FontAttributes="Italic"
                                         FontSize="Small"
                                         Grid.Row="0"
                                         Grid.Column="2"
                                         HeightRequest="30"
                                         HorizontalOptions="Start"
                                         VerticalOptions="End"/>
    
                                 </Grid>
                             </ContentView>
                         </ViewCell>
                     </DataTemplate>
                 </ListView.ItemTemplate>
             </ListView>
         </Grid>
     </ContentPage.Content>
 </ContentPage>

OperatorsPage.xaml:

 <?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="HandsFreeNotes.View.OperatorsPage">
     <ContentPage.Content>
         <Grid BackgroundColor="White">
             <Grid.RowDefinitions>
                 <RowDefinition Height="40"/>
                 <RowDefinition Height="40"/>
                 <RowDefinition Height="40"/>
                 <RowDefinition Height="70"/>
                 <RowDefinition Height="*"/>
                 <RowDefinition Height="50"/>
             </Grid.RowDefinitions>
    
             <Grid.ColumnDefinitions>
                 <ColumnDefinition Width="50"/>
                 <ColumnDefinition Width="*"/>
                 <ColumnDefinition Width="50"/>
             </Grid.ColumnDefinitions>
    
             <Button
                 x:Name="BackButton"
                 Text="Back"
                 Grid.Row="0"
                 Grid.Column="0"
                 Grid.ColumnSpan="3"
                 TextColor="Black"
                 FontAttributes="Bold"
                 HeightRequest="40"
                 VerticalOptions="Center"
                 HorizontalOptions="End"
                 Margin="0,0,20,0"
                 Clicked="BackButton_Clicked"/>
    
             <Image 
                 Source="hfn256"
                 Margin="2"
                 Grid.Row="1" 
                 Grid.Column="0"
                 Grid.ColumnSpan="3"
                 HorizontalOptions="Center"
                 BackgroundColor="Transparent"/>
    
             <Label 
                 Text="Operator"
                 FontSize="Large"
                 TextColor="Black"
                 FontAttributes="Bold"
                 Margin =" 0, 0, 0, 0"
                 Grid.Row="2" 
                 Grid.Column="0"
                 Grid.ColumnSpan="3"
                 HorizontalOptions="Center"
                 VerticalOptions="End"
                 BackgroundColor="Transparent"/>
    
             <StackLayout
                 Grid.Row="3" 
                 Grid.Column="0"
                 Grid.ColumnSpan="3"
                 Orientation="Horizontal">
    
                 <Label
                     Text="Selected&#x0a;Operator: "
                     TextColor="Black"
                     FontSize="Medium"
                     FontAttributes="Bold"
                     HorizontalOptions="End"
                     VerticalOptions="Center"
                     BackgroundColor="Transparent"
                     Margin="40, 0, 0, 0"
                     WidthRequest="250"/>
    
                 <Entry 
                     x:Name="SelectedOperatorEntry"
                     Text="{Binding OperatorName}"
                     TextColor="Green"
                     IsReadOnly="True"
                     Placeholder="No Currently Selected Operator"
                     PlaceholderColor="LightGray"
                     FontSize="Medium"
                     FontAttributes="Italic"
                     Margin ="0, 0, 0, 0"
                     HorizontalOptions="Center"
                     VerticalOptions="Center"
                     BackgroundColor="Transparent"
                     WidthRequest="280"/>
    
             </StackLayout>
    
             <ScrollView 
                 Orientation="Vertical"
                 Grid.Row="4" 
                 Grid.Column="0"
                 Grid.ColumnSpan="3">
                 <Grid BackgroundColor="White" >
                     <Grid.RowDefinitions>
                         <RowDefinition Height="50"/>
                         <RowDefinition Height="50"/>
                         <RowDefinition Height="50"/>
                         <RowDefinition Height="100"/>
                         <RowDefinition Height="20"/>
                     </Grid.RowDefinitions>
    
                     <Grid.ColumnDefinitions>
                         <ColumnDefinition Width="50"/>
                         <ColumnDefinition Width="*"/>
                         <ColumnDefinition Width="50"/>
                     </Grid.ColumnDefinitions>
    
                     <Button
                         x:Name="SelectOperatorButton"
                         Text="Select Operator"
                         FontSize="Medium"
                         Grid.Row="0"
                         Grid.Column="1"
                         TextColor="Black"
                         FontAttributes="Bold"
                         BackgroundColor="White"
                         Margin="0,0,0,0"
                         HorizontalOptions="Center"
                         VerticalOptions="Start"
                         Clicked="SelectOperatorButton_Clicked"/>
    
                     <Button
                         x:Name="UpdateOperatorButton"
                         Text="Update Selected Operator"
                         FontSize="Medium"
                         Grid.Row="1"
                         Grid.Column="1"
                         TextColor="Black"
                         FontAttributes="Bold"
                         BackgroundColor="White"
                         Margin="0,0,0,0"
                         HorizontalOptions="Center"
                         VerticalOptions="Start"
                         Clicked="UpdateOperatorButton_Clicked"/>
    
                     <Button
                         x:Name="DeleteOperatorButton"
                         Text="Delete Selected Operator"
                         FontSize="Medium"
                         Grid.Row="2"
                         Grid.Column="1"
                         TextColor="Black"
                         FontAttributes="Bold"
                         BackgroundColor="White"
                         Margin="0,0,0,0"
                         HorizontalOptions="Center"
                         VerticalOptions="Start"
                         Clicked="DeleteOperatorButton_Clicked"/>
    
                     <Button
                         x:Name="AddOperatorButton"
                         Text="Add New Operator"
                         FontSize="Medium"
                         Grid.Row="3"
                         Grid.Column="1"
                         HorizontalOptions="Center"
                         VerticalOptions="End"
                         TextColor="Black"
                         FontAttributes="Bold"
                         BackgroundColor="White"
                         Margin="0,0,0,0"
                         Clicked="AddOperatorButton_Clicked"/>
    
                 </Grid>
    
             </ScrollView>
    
         </Grid>
     </ContentPage.Content>
 </ContentPage>
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.

KyleWang-MSFT avatar image
0 Votes"
KyleWang-MSFT answered Grime commented

Hi Grime,

Welcome to our Microsoft Q&A platform!

So you want to access the previously selected item even after reopening the app, then you just need to read the data through Preferences in the constructor of the OperatorsPage and instantiate the SelectModel.

The following example also contains code to pass the SelectModel from the SelectOperatorPage to the OperatorsPage.

SelectOperatorPage.xaml.cs

 public partial class SelectOperatorPage : ContentPage
 {
     public List<OperatorModel> Operators { get; private set; }
    
     public event TransfDelegate TransfEvent;
    
     public SelectOperatorPage()
     {
         InitializeComponent();
    
         // set itemsource
         Operators = new List<OperatorModel>();
         for (int i = 0; i < 10; i++)
         {
             Operators.Add(new OperatorModel { OperatorID = $"ID{i}", OperatorName = $"Name{i}" });
         }
    
         this.BindingContext = this;
     }
    
     private void OperatorListView_ItemSelected(object sender, SelectedItemChangedEventArgs e)
     {
         OperatorModel selectedItem = e.SelectedItem as OperatorModel;
    
         TransfEvent(selectedItem);
    
         Preferences.Set("OperatorID", selectedItem.OperatorID);
         Preferences.Set("OperatorName", selectedItem.OperatorName);
     }
 }
    
 public delegate void TransfDelegate(OperatorModel operatorModel);

OperatorsPage.xaml.cs

 public OperatorsPage()
 {
     InitializeComponent();
    
     SelectModel = new OperatorModel
     {
         OperatorID = Preferences.Get("OperatorID", "default_value"),
         OperatorName = Preferences.Get("OperatorName", "default_value")
     };
 }
    
 private async void SelectOperatorButton_Clicked(object sender, EventArgs e)
 {
     SelectOperatorPage page = new SelectOperatorPage();
    
     page.TransfEvent += Page_TransfEvent;
    
     await Navigation.PushModalAsync(page);
 }
    
 OperatorModel SelectModel;
    
 private void Page_TransfEvent(OperatorModel operatorModel)
 {
     SelectModel = operatorModel;
 }
    
 private void UpdateOperatorButton_Clicked(object sender, EventArgs e)
 {
     Console.WriteLine("SelectModel.OperatorID + "\n" + SelectModel.OperatorName + "\n");
 }

Regards,
Kyle


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.

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

Hi @Grime , If you want to reselect the previous selection, after closing your application and re-opening the application. Based on my research, use Xamarin.Essentials: Preferences is a simple solution, because when close your application, all of the variables(store the previous selection) will be removed from memory, we want to store the variables, we have to store it to local storage. Use Xamarin.Essentials: Preferences is simple and quick way, we can store these variables to local file or DB as well, but it is more complexed, am I right?


0 Votes 0 ·

I totally agree.

0 Votes 0 ·