Hello everyone,
I have a small problem, I explain myself:
here's what I did, I have a page with buttons (with different values) and a picker (see xaml code), when the user clicks on a button, normally the picker selection list proposes things that are linked to the value of my button through lists (see my view model code). Except it doesn't work!
In my opinion it is because of the static type that is on some of my lists and methods. So my picker which has a binding on one of my lists does not display my selection because it cannot access my list because it is in static and not a constructor (in which I call the element of my binding).
Do you have a solution for me?
If you can't understand me, don't hesitate to ask me questions?
you will find the different files with my code below.
Sincerely
Camille
xaml code :
<?xml version="1.0" encoding="utf-8" ?> <ContentPage x:Class="PolQual.Views.StatementReferencielPage" xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:PolQual.Views" xmlns:viewModels="clr-namespace:PolQual.ViewModels;assembly=PolQual" Title="Accueil"> <ContentPage.BindingContext> <viewModels:StatementReferencielPageModel /> </ContentPage.BindingContext> <ContentPage.Content> <StackLayout> <Grid> <Grid.RowDefinitions> <RowDefinition Height="10*" /> <RowDefinition Height="15*" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="100*" /> </Grid.ColumnDefinitions> <Label Grid.Row="0" Grid.Column="0" FontSize="25" HorizontalOptions="Center" Text="Information sur le relevé référenciel" /> </Grid> <ScrollView> <Grid x:Name="gridLayout" /> </ScrollView> <Grid> <Grid.RowDefinitions> <RowDefinition Height="2*" /> <RowDefinition Height="3*" /> <RowDefinition Height="8*" /> <RowDefinition Height="2*" /> <RowDefinition Height="3*" /> <RowDefinition Height="6*" /> <RowDefinition Height="3*" /> <RowDefinition Height="6*" /> <RowDefinition Height="3*" /> <RowDefinition Height="6*" /> <RowDefinition Height="5*" /> <RowDefinition Height="6*" /> <RowDefinition Height="1*" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="25*" /> <ColumnDefinition Width="50*" /> <ColumnDefinition Width="25*" /> </Grid.ColumnDefinitions> <Label Grid.Row="1" Grid.Column="1" FontSize="15" Text="Veuillez sélectioner le secteur :" /> <Picker x:Name="PickerSectorsLists" Title="Sélectionner votre secteur" Grid.Row="2" Grid.Column="1" ItemDisplayBinding="{Binding Value}" ItemsSource="{Binding SectorsFindLists}" SelectedItem="{Binding SelectedSector}" /> <Label Grid.Row="4" Grid.Column="1" FontSize="15" Text="{Binding ShowHouseholdTrash}" /> <Switch x:Name="SwitchHousehodTrash" Grid.Row="5" Grid.Column="1" HorizontalOptions="Start" IsToggled="{Binding HouseholdTrash}" /> <Label Grid.Row="6" Grid.Column="1" FontSize="15" Text="{Binding ShowBoxboard}" /> <Switch x:Name="SwitchBoxboard" Grid.Row="7" Grid.Column="1" HorizontalOptions="Start" IsToggled="{Binding Boxboard}" /> <Label Grid.Row="8" Grid.Column="1" FontSize="15" Text="{Binding ShowGlass}" /> <Switch x:Name="SwitchGlass" Grid.Row="9" Grid.Column="1" HorizontalOptions="Start" IsToggled="{Binding Glass}" /> <Button Grid.Row="11" Grid.Column="1" BackgroundColor="#2196f3" Clicked="GoToAssesmentGrid" FontSize="20" Text="Valider les informations" TextColor="White" /> </Grid> </StackLayout> </ContentPage.Content> </ContentPage>
Behind code :
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Xamarin.Forms; using Xamarin.Forms.Xaml; using PolQual.ViewModels; namespace PolQual.Views { [XamlCompilation(XamlCompilationOptions.Compile)] public partial class StatementReferencielPage : ContentPage { public StatementReferencielPage() { InitializeComponent (); BindingContext = new StatementReferencielPageModel(); gridLayout.RowDefinitions.Add(new RowDefinition { Height = new GridLength(40) }); gridLayout.RowDefinitions.Add(new RowDefinition { Height = new GridLength(40) }); gridLayout.RowDefinitions.Add(new RowDefinition { Height = new GridLength(40) }); gridLayout.RowDefinitions.Add(new RowDefinition { Height = new GridLength(40) }); gridLayout.RowDefinitions.Add(new RowDefinition { Height = new GridLength(40) }); gridLayout.RowDefinitions.Add(new RowDefinition { Height = new GridLength(40) }); gridLayout.RowDefinitions.Add(new RowDefinition { Height = new GridLength(40) }); //collmun gridLayout.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(25, GridUnitType.Star) }); gridLayout.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(50, GridUnitType.Star) }); gridLayout.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(25, GridUnitType.Star) }); var PolesListsIndex = 0; for (int columnIndex = 1; columnIndex < 2; columnIndex++) { for (int rowIndex = 0; rowIndex < 7; rowIndex++) { if (PolesListsIndex >= StatementReferencielPageModel.PolesLists.Count<Pole>()) { return; } var poles = StatementReferencielPageModel.PolesLists[PolesListsIndex]; PolesListsIndex += 1; var button = new Button() { Text = poles.Name, BackgroundColor = Color.FromHex(poles.Color), HorizontalOptions = LayoutOptions.Center, VerticalOptions = LayoutOptions.Center, WidthRequest = 280, }; string request = StatementReferencielPageModel.PolesLists[rowIndex].Name; button.Clicked += delegate { MaFunction(request); };// anonymous method gridLayout.Children.Add(button, columnIndex, rowIndex); } } } public static void MaFunction(string polename) { StatementReferencielPageModel.FindPoleName(polename); } public void GoToAssesmentGrid(object sender, System.EventArgs e) { if (PickerSectorsLists.SelectedIndex == -1) { DisplayAlert("Erreur de saisie", "Veuillez séléctioner un secteur svp! ", "D'accord"); } else { var page = new AssesmentGridPage(); Navigation.PushAsync(page); } } } }
view Model code :
using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using Xamarin.Forms; using PolQual.Views; namespace PolQual.ViewModels { public class StatementReferencielPageModel : INotifyPropertyChanged { private static List<Sector> _sectorsLists; public static List<Sector> SectorsLists { get => _sectorsLists; set => _sectorsLists = value; } private readonly List<Sector> sectorsFindLists; private static List<Sector> _sectorsFindLists; public static List<Sector> SectorsFindLists { get => _sectorsFindLists; set => _sectorsFindLists = value; } private static List<Pole> _polesLists; public static List<Pole> PolesLists { get => _polesLists; set => _polesLists = value; } public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged([CallerMemberName] string propertyname = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname)); } private bool _boxboard { get; set; } public bool Boxboard { get { return _boxboard; } set { _boxboard = value; OnPropertyChanged(); OnPropertyChanged(nameof(ShowBoxboard)); } } private bool _glass { get; set; } public bool Glass { get { return _glass; } set { _glass = value; OnPropertyChanged(); OnPropertyChanged(nameof(ShowGlass)); } } private bool _householdTrash { get; set; } public bool HouseholdTrash { get { return _householdTrash; } set { _householdTrash = value; OnPropertyChanged(); OnPropertyChanged(nameof(ShowHouseholdTrash)); } } private Sector _selectedSector { get; set; } public Sector SelectedSector { get { return _selectedSector; } set { if (_selectedSector != value) { _selectedSector = value; // que faire quand l'élèment est sélectionné ! } } } public StatementReferencielPageModel() { SectorsLists = GetSectors().OrderBy(t => t.Key).ToList(); SectorsFindLists = GetSectors().OrderBy(t => t.Key).ToList(); PolesLists = GetPoles().OrderBy(t => t.Key).ToList(); } public List<Sector> GetSectors() { var Sectors = new List<Sector>() { //Erdre et cens new Sector() { Key = 0, Value = "Sautron", PoleName="Erdre et cens" }, new Sector() { Key = 1, Value = "Orvault", PoleName="Erdre et cens" }, new Sector() { Key = 2, Value = "Nantes Nord", PoleName="Erdre et cens" }, new Sector() { Key = 3, Value = "La-Chapelle-Sur-Erdre", PoleName="Erdre et cens" }, // Erdre et Loire new Sector() { Key = 4, Value = "Mauves-Sur-Loire", PoleName="Erdre et Loire" }, new Sector() { Key = 5, Value = "Carquefou", PoleName="Erdre et Loire" }, new Sector() { Key = 6, Value = "Thouré sur Loire", PoleName="Erdre et Loire" }, new Sector() { Key = 7, Value = "Sainte Luce sur Loire", PoleName="Erdre et Loire" }, new Sector() { Key = 8, Value = "Nantes Erdre", PoleName="Erdre et Loire" }, new Sector() { Key = 9, Value = "Doulon", PoleName="Erdre et Loire" }, //Loire-Sèvre et Vignoble new Sector() { Key = 10, Value = "Rezé", PoleName="Loire-Sèvre et Vignoble" }, new Sector() { Key = 11, Value = "Les Sornières", PoleName="Loire-Sèvre et Vignoble" }, new Sector() { Key = 12, Value = "Vertou", PoleName="Loire-Sèvre et Vignoble" }, new Sector() { Key = 13, Value = "Saint Sébastien sur Loire", PoleName="Loire-Sèvre et Vignoble" }, new Sector() { Key = 14, Value = "Base Goulaine", PoleName="Loire-Sèvre et Vignoble" }, new Sector() { Key = 15, Value = "Nantes sud", PoleName="Loire-Sèvre et Vignoble" }, //Sud-Ouest new Sector() { Key = 16, Value = "Bouchenais", PoleName="Sud-Ouest" }, new Sector() { Key = 17, Value = "Saint-Aignan-Grandlieu", PoleName="Sud-Ouest" }, new Sector() { Key = 18, Value = "Bouaye", PoleName="Sud-Ouest" }, new Sector() { Key = 19, Value = "Saint-Leger-Les-Vignes", PoleName="Sud-Ouest" }, new Sector() { Key = 20, Value = "Brains", PoleName="Sud-Ouest" }, new Sector() { Key = 21, Value = "La-Montagne", PoleName="Sud-Ouest" }, new Sector() { Key = 22, Value = "Saint-Jean-De-Boiseau", PoleName="Sud-Ouest" }, new Sector() { Key = 23, Value = "Le Pellerin", PoleName="Sud-Ouest" }, //Loire-Chézine new Sector() { Key = 24, Value = "Couëron", PoleName="Loire-Chézine" }, new Sector() { Key = 25, Value = "Saint-Herblain", PoleName="Loire-Chézine" }, new Sector() { Key = 26, Value = "Indre", PoleName="Loire-Chézine" }, //Nantes-Ouest new Sector() { Key = 27, Value = "Bellevue-Chantenay-Sainte-Anne", PoleName="Nantes-Ouest" }, new Sector() { Key = 28, Value = "Dervallière-Zola", PoleName="Nantes-Ouest" }, new Sector() { Key = 29, Value = "Breil-Barberie", PoleName="Nantes-Ouest" }, new Sector() { Key = 30, Value = "Hauts Pavés Saint Félix", PoleName="Nantes-Ouest" }, //Nantes-Loire new Sector() { Key = 31, Value = "Malakof-Saint-Donatien", PoleName="Nantes-Loire" }, new Sector() { Key = 32, Value = "Centre Ville", PoleName="Nantes-Loire" }, new Sector() { Key = 33, Value = "île de Nantes", PoleName="Nantes-Loire" }, }; return Sectors; } public List<Pole> GetPoles() { var Poles = new List<Pole>() { new Pole { Key = 1, Name = "Erdre et Cens", Color = "ffccd5"}, new Pole { Key = 2, Name = "Erdre et Loire", Color = "ff4d4d"}, new Pole { Key = 3, Name = "Loire-Sèvre et vignoble", Color = "ff9933"}, new Pole { Key = 4, Name = "Sud-Ouest", Color = "bfbfbf"}, new Pole { Key = 5, Name = "Loire-chézine", Color = "ffff4d"}, new Pole { Key = 6, Name = "Nantes-Ouest", Color = "3385ff"}, new Pole { Key = 7, Name = "Nantes-Loire", Color = "53c653"}, }; return Poles; } public static void FindPoleName(string polename) { for (int search = 0; search < SectorsLists.Count(); search++) { if (SectorsLists[search].PoleName == polename) { SectorsFindLists.Add(new Sector() {Key = search, Value = SectorsLists[search].Value, PoleName = polename }); } } } public string ShowBoxboard { get { return $"{(_boxboard ? "Jour de collecte des cartons : oui " : "Jour de collecte des cartons : non")}"; } } public string ShowGlass { get { return $"{(_glass ? "Jour de collecte du verre : oui " : "Jour de collecte du verre : non")}"; } } public string ShowHouseholdTrash { get { return $"{(_householdTrash ? "Jour de collecte des Ordure ménagère : oui " : "Jour de collecte des Ordure ménagère : non")}"; } } } public class Sector { private int _key; public int Key { get => _key; set => _key = value; } private string _value; public string Value { get => _value; set => _value = value; } private string _poleName; public string PoleName { get => _poleName; set => _poleName = value; } } public class Pole { private int _key; public int Key { get => _key; set => _key = value; } private string _color; public string Color { get => _color; set => _color = value; } private string _name; public string Name { get => _name; set => _name = value; } } }
Posts
Your UI's
BindingContext
is set to the view model correctly but you are modifying your static properties and lists. A UI can't binding to static members. UI's can only bind to public instance properties. I suggest changing yourViewModel
to have non static properties. Also change them toObservableCollections
as well to allow the UI to automatically get notified of the updated lists.ViewModel (OLD)
ViewModel (NEW)
Then modify PolesCollection when adding and finding poles in your VM. Also,
FindPoles
will need to not be static as well.Your UI will need to keep a reference to your VM that you set as your
BindingContext
.View.cs (OLD)
View.cs (NEW)
Hopefully this helps you!
first of all thank you for your answer
but I don't see how I can do anything wrong to call my function "My Function" and the observableCollection "PolesCollection" which is in my view model from the behind file without putting them in static.
Because if as you say I remove the static property I can no longer access my attributes or functions from my behind code
I have one last question concerning the ObservablesCollection, is it considered as a list or not at all because I confess to having already looked at the Microsoft site without really understanding how it works.
You are able to call and reference those methods and collections in your
StatementReferencielPageModel
when you save the reference to it like I showed in the View.cs (NEW) code. When you set yourBindingContext
you must save that reference to be able to call the appropriate view model method in yourMaFunction
.To be able to
Bind
your lists properly, they cannot be static.An
ObservableCollection
is a type of collection that provides all the functionality that aList
does, but whenObservableCollection
's are binded to your view correctly, allows the UI to automatically be updated when an object (orPole
in your case) is added or removed from that collection.Thank you once again for your explanations and the time you are taking to help me.
I changed my code before the compilation my ide does not indicate any problem but during the compilation here is the error that appears:
the error appears on the behind page on line 42
Do you have any idea where this came from?
code behind :
code viewModel :
When you set your
BindingContext
, you forgot to add the line below before you set it. You need to create an instance of yourStatementReferencielPageModel
in order to use it.pfff yes indeed in addition to being a beginner I am blind it will not help me much
than she's making a mistake of inattention!
but then with me I have another question that I hope will be the last one
the list I get from my picker doesn't display the right elements it displays all the elements of my list Sectors of the group is better to store the new sectors of my find function in a new list?
I would suggest at the beginning of your
FindPoleName
function in your StatementReferencielPageModel, callSectorsFindLists.Clear()
before your loop. Then when you add new elements, you will only have theSector
's for that polename.Yes, I had thought about it, but the same error as five minutes ago appears.
You need to set your
SectorsFindLists
to a new list in your view model.StatementReferencielPageModel.cs
Or you can initialize it in the
Constructor
where you initialize your other lists.I tried to fix my problem but in vain, unfortunately I still have my entire sector list which is displayed yet I empty it at the beginning of my function
here is the part of the code I modified:
I would suggest looking at
foreach
loops when looping through a list. I'm not sure where the next issue is, but I'm guessing there is some logic that's wrong either in that loop or where some of the other lists are created with their items.Only the items that are getting added to your
SectorsFindLists
will be shown in the UI if the logic in the loop and such is set up correctly. Do some debugging with breakpoints and see which objects get added to your lists, and see if there is some wrong logic somewhere.Also, this line will create a big confusion to yourself and other readers of the code due to having the same variable name. It can cause unintended consequences also.
While you need to initialize your list, don't create a new variable local to that function. Do it above your initial list declaration like I specified in the previous comment towards the top of your class.
Hello TaylorD,
so since the last message I posted I paused and later came back to my code and realized that there were some errors so I decided to review my code and change it.
Now I can display my list well ( like what to take a break and go elsewhere can be useful).
However I have a new problem that arises, when I want to scrub the selected item of my list it returns the object of my list but not its content (its variable).
and about foreach, to be honest I never use it I always use the for loop is there really a big difference to what I use foreach?
this is what it returns to me :
and this is my code 2.0
: PolQual.ViewModel.Sector
my vue : (only the picker to change)
my code behind :
at last my viewModel :
I have found a way to recover the value of the selected sector using this method:
I want to know if it's okay to do it like this or not?
In any case, I thank you for your help. You have been very useful to me
Xamarin.Forms
Picker
has a SelectedItem property and you should use that. That should return your specified object if your Picker is binded to the appropriate listSectorsFindLists
from your ViewModelOR
Since your
Picker
is binded to the SelectedSector in your ViewModel, that will update when a value is selected in yourPickerSectorsLists
. Then in the setter of the property in you ViewModel, do you logic for your selected item there.All right, it works, so I replaced my previous function with this in my behind code:
then in my view model I created a method that will store the result and then transmit it in the data base (but for the moment I don't care about it)