none
Besoin d'aide pour structurer une application

    Question

  • Bonjour à tous,

    J'essaie de créer ma première application après plusieurs mois d'apprentissage du C# et de Xamarin.Forms.

    Mon application consiste à afficher des listes de biens Patrimoniaux dans des pages différentes (Page1, Page2 etc) et lors du clic sur un des éléments d'une liste, ça ouvre une DetailPage qui donne des détails sur le bien concerné avec une carte censée présenter un Pin pour la position géographique.

    Les propriétés d'un bien patrimonial sont définies dans la classe Patrimoine (Nom, Longitude, Latitude...).

    Je n'ai aucun mal à afficher les données en usant du Binding sur la DetailPage Xaml.

    Mais je bute sur un problème auquel je n'avais pas pensé auparavant : la DetailPage contient une méthode pour créer un Pin sur la carte. Comment faire pour récupérer la longitude et la latitude des biens patrimoniaux instanciés dans la Page1 par exemple pour fournir à la DetailPage les coordonnées ?

    On m'a conseillé de me tourner vers le MVVM mais ça me semble compliqué et j'ai un peu de mal à adapter cette solution à mon cas.

    Quelqu'un pourrait-il m'expliquer comment intégrer les notions de MVVM dans mon application ?

    Notez que mon application ne propose que de l'affichage, il ne s'agit que de consultation de contenus.

    Voici le code de la page1 :

    public partial class Page1 : ContentPage
        {
            public static ObservableCollection<Patrimoine> ListePatrimoine = new ObservableCollection<Patrimoine>();
            
            public Page1()
            {
                InitializeComponent();
                // Setting our list to be ItemSource for ListView in MainPage.xaml
                listePatrimoine.ItemsSource = ListePatrimoine;
    
                var Eglise = new Patrimoine() { Titre = "Eglise" };
                var Mairie = new Patrimoine() { Titre = "Mairie", latitude = 48.8584, longitude = 2.2945
                 
                };
                ListePatrimoine.Add(Eglise);
                ListePatrimoine.Add(Mairie);
                
            }
    
            private async void listePatrimoine_ItemSelectedAsync(object sender, SelectedItemChangedEventArgs e)
            {
                if (listePatrimoine.SelectedItem != null)
                {
                    var detailpage = new DetailPage();
                    detailpage.BindingContext = e.SelectedItem as Patrimoine;
                    listePatrimoine.SelectedItem = null;
                    await Navigation.PushModalAsync(detailpage);
                }
            }

    La classe Patrimoine :

    public class Patrimoine
        {
            public string Titre { get; set; }
            public double latitude { get; set; }
            public double longitude { get; set; }
            public Position position { get; set; }
        }

    Enfin le code de la méthode pour ajouter un Pin (au sein de la DetailPage) :

    private void ajouterPin()
            {
                var Xposition = new Position(_Latitude, _Longitude); 
    
                var pin = new Pin
                {
                    Type = PinType.Place,
                    Position = Xposition,
                    Label = "my pin"
                };
                map.Pins.Add(pin);
            }



    • Modifié Bernardlf vendredi 30 juin 2017 20:58
    vendredi 30 juin 2017 20:45

Réponses

  • Bonjour Bernard,

    Tout d'abord désolé pour le retard mais j'étais très chargé ces derniers jours.

    Alors voici une solution qui fonctionne chez moi :

    MainPage.xaml 

    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 xmlns:local="clr-namespace:App9"
                 x:Class="App9.MainPage">
    
        <ListView x:Name="listePatrimoine"
                  ItemSelected="listePatrimoine_ItemSelectedAsync">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <TextCell Text="{Binding Titre}" />
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </ContentPage>


    MainPage.xaml.cs

    	public partial class MainPage : ContentPage
    	{
            ObservableCollection<Patrimoine> ListePatrimoine = new ObservableCollection<Patrimoine>();
    
            public MainPage()
    		{
    			InitializeComponent();
    
                ListePatrimoine.Add(new Patrimoine { Titre = "Eglise" });
                ListePatrimoine.Add(new Patrimoine {  Titre = "Mairie", Latitude = 48.8584, Longitude = 2.2945 });
                listePatrimoine.ItemsSource = ListePatrimoine;
                
            }
    
            private async void listePatrimoine_ItemSelectedAsync(object sender, SelectedItemChangedEventArgs e)
            {
                if (listePatrimoine.SelectedItem != null)
                {
                    Patrimoine patrimoine = e.SelectedItem as Patrimoine;
    
                    App.NavigationService.NavigateTo("DetailPage", patrimoine);
                }
            }
        }
    

    Création de la classe NavigationService dans le projet en commun Xamarin.Forms

        public class NavigationService
        {
            private Dictionary<string, Type> pages { get; }
                = new Dictionary<string, Type>();
    
            public Page MainPage => Application.Current.MainPage;
    
            public void Configure(string key, Type pageType) => pages[key] = pageType;
    
            public void GoBack() => MainPage.Navigation.PopAsync();
    
            public void NavigateTo(string pageKey, object parameter = null,
                HistoryBehavior historyBehavior = HistoryBehavior.Default)
            {
                Type pageType;
                if (pages.TryGetValue(pageKey, out pageType))
                {
                    var displayPage = (Page)Activator.CreateInstance(pageType);
                    displayPage.SetNavigationArgs(parameter);
    
                    if (historyBehavior == HistoryBehavior.ClearHistory)
                    {
                        MainPage.Navigation.InsertPageBefore(displayPage,
                            MainPage.Navigation.NavigationStack[0]);
    
                        var existingPages = MainPage.Navigation.NavigationStack;
                        for (int i = 1; i < existingPages.Count; i++)
                            MainPage.Navigation.RemovePage(existingPages[i]);
                    }
                    else
                    {
                        MainPage.Navigation.PushAsync(displayPage);
                    }
                }
                else
                {
                    throw new ArgumentException($"No such page: {pageKey}.",
                        nameof(pageKey));
                }
            }
        }
    
        public enum HistoryBehavior
        {
            Default,
            ClearHistory
        }
    
        public static class NavigationExtensions
        {
            private static ConditionalWeakTable<Page, object> arguments
                = new ConditionalWeakTable<Page, object>();
    
            public static object GetNavigationArgs(this Page page)
            {
                object argument = null;
                arguments.TryGetValue(page, out argument);
    
                return argument;
            }
    
            public static void SetNavigationArgs(this Page page, object args)
                => arguments.Add(page, args);
        }
    

    Code de la page DetailPage.xaml.cs

    	[XamlCompilation(XamlCompilationOptions.Compile)]
    	public partial class DetailPage : ContentPage
    	{
            Patrimoine patrimoine = new Patrimoine();
    		public DetailPage ()
    		{
    			InitializeComponent ();
               
            }
    
            protected override void OnAppearing()
            {
                var args = this.GetNavigationArgs();
                patrimoine = args as Patrimoine;
                base.OnAppearing();
            }
        }

    Comme vous pouvez le constater je récupère toutes les valeurs du patrimoine : 

    J'espère que j'ai bien répondu à votre question.


    Si c'est le cas, n'hésitez pas à mettre ma réponse en réponse à votre post

    Vous pouvez me suivre sur Twitter : https://twitter.com/NordineMhoumadi


    Download my NEW FREE application MCP PREPARATION in the Windows 10 Store for preparing your Microsoft Certification or test your skills in Microsoft Technologies;

    • Marqué comme réponse Bernardlf dimanche 9 juillet 2017 08:26
    mercredi 5 juillet 2017 09:48

Toutes les réponses

  • Bonsoir Bernard,

    Comment faire pour récupérer la longitude et la latitude des biens patrimoniaux instanciés dans la Page1 par exemple pour fournir à la DetailPage les coordonnées ?

     ==> Vous pouvez passer l’objet Patrimoine en paramètre de la navigation. Voici un lien qui explique comment passer des paramètres lors de la navigation : https://developer.xamarin.com/samples/xamarin-forms/Navigation/PassingData/

    Quelqu'un pourrait-il m'expliquer comment intégrer les notions de MVVM dans mon application ?
     ==> Pour utiliser MVVM vous pouvez utiliser des frameworks tels que MVVM Light ou Prism. L'utilisation d'un framework vous permettra d'intégrer plus facilement le MVVM dans votre application. 

    J'espère que j'ai bien répondu à votre question.


    Si c'est le cas, n'hésitez pas à mettre ma réponse en réponse à votre post

    Vous pouvez me suivre sur Twitter : https://twitter.com/NordineMhoumadi



    Download my NEW FREE application MCP PREPARATION in the Windows 10 Store for preparing your Microsoft Certification or test your skills in Microsoft Technologies;

    vendredi 30 juin 2017 22:07
  • Bonsoir Bernard,

    Comment faire pour récupérer la longitude et la latitude des biens patrimoniaux instanciés dans la Page1 par exemple pour fournir à la DetailPage les coordonnées ?

     ==> Vous pouvez passer l’objet Patrimoine en paramètre de la navigation. Voici un lien qui explique comment passer des paramètres lors de la navigation :


    Bonjour,

    Je vous remercie pour votre réponse.

    Concernant le MVVM, j'aimerai bien apprendre à le faire avant d'utiliser des choses toutes faites, je vais m'entrainer un peu à ce sujet.

    Par contre, pouvez-vous être plus précis au sujet de l'objet Patrimoine à passer en paramètre svp ?

    samedi 1 juillet 2017 07:28
  • Bonjour,

    Pour le MVVM sans l'utilisation d'un framework, vous avez ce tuto Xamarin.Forms avec MVVM sur ce lien qui pourra vous aider : https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/data_bindings_to_mvvm/

    Pour l'objet Patrimoine, voici le code à utiliser. En fait le principe consiste à binder sur la page détail les l'objet Patrimoine sélectionner : 

    public partial class Page1 : ContentPage
        {
            public static ObservableCollection<Patrimoine> ListePatrimoine = new ObservableCollection<Patrimoine>();
            
            public Page1()
            {
                InitializeComponent();
                // Setting our list to be ItemSource for ListView in MainPage.xaml
    
    	    ListPatrimoine.Add(new Patrimoine { Titre = "Eglise" });
     	    ListPatrimoine.Add(new Patrimoine { { Titre = "Mairie", latitude = 48.8584, longitude = 2.2945});
                listePatrimoine.ItemsSource = ListePatrimoine;
                
            }
    
            private async void listePatrimoine_ItemSelectedAsync(object sender, SelectedItemChangedEventArgs e)
            {
                if (listePatrimoine.SelectedItem != null)
                {
    		Patrimoine patrimoine=e.SelectedItem as Patrimoine;
                    DetailPage detailpage = new DetailPage();
                    detailpage.BindingContext = patrimoine;
                    await Navigation.PushAsync(detailpage);
                }
            }
    }


    Pour récupérer l'objet Patrimoine dans DetailPage vous pouvez mettre ce code dans DetailPage : 

    public DetailPage ()
            {
                InitializeComponent();
                
               Patrimoine patrimoine= (Patrimoine)this.BindingContext;
     	   Position Xposition = new Position(patrimoine.latitude, patrimoine.longitude); 
    
                Pin pin = new Pin
                {
                    Type = PinType.Place,
                    Position = Xposition,
                    Label = patrimoine.Titre
                };
                map.Pins.Add(pin);
                
            }

    J'espère que j'ai bien répondu à votre question.


    Si c'est le cas, n'hésitez pas à mettre ma réponse en réponse à votre post

    Vous pouvez me suivre sur Twitter : https://twitter.com/NordineMhoumadi


    Download my NEW FREE application MCP PREPARATION in the Windows 10 Store for preparing your Microsoft Certification or test your skills in Microsoft Technologies;

    samedi 1 juillet 2017 11:48
  • Pour l'objet Patrimoine, voici le code à utiliser. En fait le principe consiste à binder sur la page détail les l'objet Patrimoine sélectionner : 

    public partial class Page1 : ContentPage
        {
            public static ObservableCollection<Patrimoine> ListePatrimoine = new ObservableCollection<Patrimoine>();
            
            public Page1()
            {
                InitializeComponent();
                // Setting our list to be ItemSource for ListView in MainPage.xaml
    
    	    ListPatrimoine.Add(new Patrimoine { Titre = "Eglise" });
     	    ListPatrimoine.Add(new Patrimoine { { Titre = "Mairie", latitude = 48.8584, longitude = 2.2945});
                listePatrimoine.ItemsSource = ListePatrimoine;
                
            }
    
            private async void listePatrimoine_ItemSelectedAsync(object sender, SelectedItemChangedEventArgs e)
            {
                if (listePatrimoine.SelectedItem != null)
                {
    		Patrimoine patrimoine=e.SelectedItem as Patrimoine;
                    DetailPage detailpage = new DetailPage();
                    detailpage.BindingContext = patrimoine;
                    await Navigation.PushAsync(detailpage);
                }
            }
    }


    Pour récupérer l'objet Patrimoine dans DetailPage vous pouvez mettre ce code dans DetailPage : 

    public DetailPage ()
            {
                InitializeComponent();
                
               Patrimoine patrimoine= (Patrimoine)this.BindingContext;
     	   Position Xposition = new Position(patrimoine.latitude, patrimoine.longitude); 
    
                Pin pin = new Pin
                {
                    Type = PinType.Place,
                    Position = Xposition,
                    Label = patrimoine.Titre
                };
                map.Pins.Add(pin);
                
            }

    J'espère que j'ai bien répondu à votre question.

    Merci de vous intéresser à mon problème.

    Hélas il semble que cette ligne cause une erreur : 

    Position Xposition = new Position(patrimoine.latitude, patrimoine.longitude);

    L'erreur est la suivante : 

    System.NullReferenceException : 'Object reference not set to an instance of an object.'

    Que puis-je faire pour corriger cela svp ?

    Merci par avance.

    samedi 1 juillet 2017 12:22
  • Mettez un point d'arrêt sur la ligne :

      Patrimoine patrimoine= (Patrimoine)this.BindingContext;

    Pouvez-vous me communiquer la valeur de l'objet patrimoine?


    Download my NEW FREE application MCP PREPARATION in the Windows 10 Store for preparing your Microsoft Certification or test your skills in Microsoft Technologies;

    samedi 1 juillet 2017 12:47
  • Mettez un point d'arrêt sur la ligne :

      Patrimoine patrimoine= (Patrimoine)this.BindingContext;

    Pouvez-vous me communiquer la valeur de l'objet patrimoine?

    Oui bien sûr.

    Il est indiqué que patrimoine vaut null.

    Latitude 0

    Longitude 0

    samedi 1 juillet 2017 12:56
  • Bonjour Bernard,

    Tout d'abord désolé pour le retard mais j'étais très chargé ces derniers jours.

    Alors voici une solution qui fonctionne chez moi :

    MainPage.xaml 

    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 xmlns:local="clr-namespace:App9"
                 x:Class="App9.MainPage">
    
        <ListView x:Name="listePatrimoine"
                  ItemSelected="listePatrimoine_ItemSelectedAsync">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <TextCell Text="{Binding Titre}" />
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </ContentPage>


    MainPage.xaml.cs

    	public partial class MainPage : ContentPage
    	{
            ObservableCollection<Patrimoine> ListePatrimoine = new ObservableCollection<Patrimoine>();
    
            public MainPage()
    		{
    			InitializeComponent();
    
                ListePatrimoine.Add(new Patrimoine { Titre = "Eglise" });
                ListePatrimoine.Add(new Patrimoine {  Titre = "Mairie", Latitude = 48.8584, Longitude = 2.2945 });
                listePatrimoine.ItemsSource = ListePatrimoine;
                
            }
    
            private async void listePatrimoine_ItemSelectedAsync(object sender, SelectedItemChangedEventArgs e)
            {
                if (listePatrimoine.SelectedItem != null)
                {
                    Patrimoine patrimoine = e.SelectedItem as Patrimoine;
    
                    App.NavigationService.NavigateTo("DetailPage", patrimoine);
                }
            }
        }
    

    Création de la classe NavigationService dans le projet en commun Xamarin.Forms

        public class NavigationService
        {
            private Dictionary<string, Type> pages { get; }
                = new Dictionary<string, Type>();
    
            public Page MainPage => Application.Current.MainPage;
    
            public void Configure(string key, Type pageType) => pages[key] = pageType;
    
            public void GoBack() => MainPage.Navigation.PopAsync();
    
            public void NavigateTo(string pageKey, object parameter = null,
                HistoryBehavior historyBehavior = HistoryBehavior.Default)
            {
                Type pageType;
                if (pages.TryGetValue(pageKey, out pageType))
                {
                    var displayPage = (Page)Activator.CreateInstance(pageType);
                    displayPage.SetNavigationArgs(parameter);
    
                    if (historyBehavior == HistoryBehavior.ClearHistory)
                    {
                        MainPage.Navigation.InsertPageBefore(displayPage,
                            MainPage.Navigation.NavigationStack[0]);
    
                        var existingPages = MainPage.Navigation.NavigationStack;
                        for (int i = 1; i < existingPages.Count; i++)
                            MainPage.Navigation.RemovePage(existingPages[i]);
                    }
                    else
                    {
                        MainPage.Navigation.PushAsync(displayPage);
                    }
                }
                else
                {
                    throw new ArgumentException($"No such page: {pageKey}.",
                        nameof(pageKey));
                }
            }
        }
    
        public enum HistoryBehavior
        {
            Default,
            ClearHistory
        }
    
        public static class NavigationExtensions
        {
            private static ConditionalWeakTable<Page, object> arguments
                = new ConditionalWeakTable<Page, object>();
    
            public static object GetNavigationArgs(this Page page)
            {
                object argument = null;
                arguments.TryGetValue(page, out argument);
    
                return argument;
            }
    
            public static void SetNavigationArgs(this Page page, object args)
                => arguments.Add(page, args);
        }
    

    Code de la page DetailPage.xaml.cs

    	[XamlCompilation(XamlCompilationOptions.Compile)]
    	public partial class DetailPage : ContentPage
    	{
            Patrimoine patrimoine = new Patrimoine();
    		public DetailPage ()
    		{
    			InitializeComponent ();
               
            }
    
            protected override void OnAppearing()
            {
                var args = this.GetNavigationArgs();
                patrimoine = args as Patrimoine;
                base.OnAppearing();
            }
        }

    Comme vous pouvez le constater je récupère toutes les valeurs du patrimoine : 

    J'espère que j'ai bien répondu à votre question.


    Si c'est le cas, n'hésitez pas à mettre ma réponse en réponse à votre post

    Vous pouvez me suivre sur Twitter : https://twitter.com/NordineMhoumadi


    Download my NEW FREE application MCP PREPARATION in the Windows 10 Store for preparing your Microsoft Certification or test your skills in Microsoft Technologies;

    • Marqué comme réponse Bernardlf dimanche 9 juillet 2017 08:26
    mercredi 5 juillet 2017 09:48
  • Bonjour Bernard,

    Tout d'abord désolé pour le retard mais j'étais très chargé ces derniers jours.

    Alors voici une solution qui fonctionne chez moi :


    Bonjour Nourdine,

    Je vous remercie d'avoir pris le temps de chercher une solution qui fonctionne.

    Je vous donne à mon tour une autre façon de répondre au problème qu'un professeur m'a fournie.

    La méthode qui crée la page de Detail :

    private async void listePatrimoine_ItemSelectedAsync(object sender, SelectedItemChangedEventArgs e)
            {
                if (listePatrimoine.SelectedItem != null)
                {
                    var detailpage = new DetailPage(e.SelectedItem as Patrimoine);
                    detailpage.BindingContext = e.SelectedItem as Patrimoine;
                    listePatrimoine.SelectedItem = null;
                    await Navigation.PushModalAsync(detailpage);
                }
            }

    Et la DetailPage prend ensuite ces paramètres :

    public DetailPage(Patrimoine patrimoine)
            {
                InitializeComponent(); etc
    Merci encore pour votre aide.

    dimanche 9 juillet 2017 08:32