Interagir entre deux Class
Résolu/Fermé
robunccm
Messages postés
52
Date d'inscription
jeudi 7 février 2019
Statut
Membre
Dernière intervention
9 mars 2024
-
20 févr. 2019 à 17:29
robunccm Messages postés 52 Date d'inscription jeudi 7 février 2019 Statut Membre Dernière intervention 9 mars 2024 - 24 févr. 2019 à 10:59
robunccm Messages postés 52 Date d'inscription jeudi 7 février 2019 Statut Membre Dernière intervention 9 mars 2024 - 24 févr. 2019 à 10:59
A voir également:
- Interagir entre deux Class
- Itinéraire google map entre deux adresses - Guide
- Deux comptes whatsapp - Guide
- Deux ecran pc - Guide
- Faire deux colonnes sur word - Guide
- Tableau croisé dynamique différence entre deux colonnes ✓ - Forum Excel
6 réponses
Utilisateur anonyme
20 févr. 2019 à 17:44
20 févr. 2019 à 17:44
Bonjour
Sans les messages d’erreur, je ne fais que supposer.
Tu ne les a pas seulement déclaré public, mais static aussi.
Ce mot clé n’a pas la même signification qu’en VBA.
Si le message est un truc du style
Sans les messages d’erreur, je ne fais que supposer.
Tu ne les a pas seulement déclaré public, mais static aussi.
Ce mot clé n’a pas la même signification qu’en VBA.
Si le message est un truc du style
Un champ d’instance ne peut pas être appelé dans une méthode statiquealors cela vient de là.
Utilisateur anonyme
20 févr. 2019 à 23:20
20 févr. 2019 à 23:20
Une chose après l'autre.
Un élément static (propriété, méthode ou évènement) est "hors d'atteinte" d'une élément d'une instance.
Parce ce que ce qui est static n'est pas instancié.
Si tu as besoin de données venant d'une instance, il faut les passer en paramètre.
Un exemple, on imagine des objets à gérer avec un ID unique.
nombreObjet est "en dehors" de la classe, chaque instance peut accéder à sa valeur.
Quand je l'incrémente, j'obtiens à la fois le nombre d'instances crées et un nouvel ID.
nombreObjet existe même s'in n'y aucune instance.
Imaginons maintenant, que les objets soient sérialisé dans un fichier csv.
Quand on lance le programme, il faut donc désérialiser. On va donc à partir du fichier générer une collection de MonObjet.
On peut écrire une classe dédiée.
On peut aussi, utiliser une méthode statique, puisqu'elle existe même s'il n'y a pas d'instance.
Et ailleurs
J'ai tapé de tête, il peut y avoir de petites erreurs.
Un élément static (propriété, méthode ou évènement) est "hors d'atteinte" d'une élément d'une instance.
Parce ce que ce qui est static n'est pas instancié.
Si tu as besoin de données venant d'une instance, il faut les passer en paramètre.
Un exemple, on imagine des objets à gérer avec un ID unique.
public class MonObjet { private static nombreObjet; public MonObjet() { ID = ++MonObjet.nombreObjet;//On ne peut pas utiliser directement nombreObjet } public int ID {get; private set} }
nombreObjet est "en dehors" de la classe, chaque instance peut accéder à sa valeur.
Quand je l'incrémente, j'obtiens à la fois le nombre d'instances crées et un nouvel ID.
nombreObjet existe même s'in n'y aucune instance.
Imaginons maintenant, que les objets soient sérialisé dans un fichier csv.
Quand on lance le programme, il faut donc désérialiser. On va donc à partir du fichier générer une collection de MonObjet.
On peut écrire une classe dédiée.
On peut aussi, utiliser une méthode statique, puisqu'elle existe même s'il n'y a pas d'instance.
public static List<MonObjet> Deserialise(string Fichier) { return (from ligne in File.ReadAllLines(Fichier) from donnee in ligne.Split(';') select new MonObjet { ID = Convert.ToInt(donnee[0]), //etc }).ToList(); }
Et ailleurs
string filename = "mesObjets.csv";//la donnée instanciée filename est passée en paramètre List<MonObjet> mesObjets = MonObjet. Deserialise(filename);
J'ai tapé de tête, il peut y avoir de petites erreurs.
Utilisateur anonyme
20 févr. 2019 à 23:54
20 févr. 2019 à 23:54
Pour l'interaction, tu pourrais avoir une propriété de Locomotive de type C30Arduino et quand la locomotive doit envoyer quelque chose elle se sert de sont composant.
Cependant, un objet modélise un vrai objet, concept, etc... Il y a plein de chose qui pourraient justifier des objets dans les composants d'une locomotive (des roues, un moteur, etc....) mais la communication Tcp bof....
Pour moi, le mieux est de créer un évènement dans la classe Locomotive.
Cet évènement doit avoir en paramètre tout ce qui est nécessaire à la communication:
Au moment où tu crées une loco, tu abonnes cet évènement à une méthode (toujours la même).
Dans cette méthode, tu identifies grâce au paramètre qui va bien quelle instance de C30Arduino utiliser, tu lui donnes le message et tu l'envoie.
Tu peux rendre cet évènement static, comme ça tu t'y abonnes dès l'initialisation de ton programme, que tu aies des locomotives ou pas. Et quand il y en aura il sera prêt.
Je t'invite à lire ce tuto https://tlevesque.developpez.com/tutoriels/csharp/delegues-et-evenements/ sur les délégués et les évènements.
Cependant, un objet modélise un vrai objet, concept, etc... Il y a plein de chose qui pourraient justifier des objets dans les composants d'une locomotive (des roues, un moteur, etc....) mais la communication Tcp bof....
Pour moi, le mieux est de créer un évènement dans la classe Locomotive.
Cet évènement doit avoir en paramètre tout ce qui est nécessaire à la communication:
- l'adresse IP, et le message
- le numéro/nom de la locomotive et le message
- l'instance de la locomotive
Au moment où tu crées une loco, tu abonnes cet évènement à une méthode (toujours la même).
Dans cette méthode, tu identifies grâce au paramètre qui va bien quelle instance de C30Arduino utiliser, tu lui donnes le message et tu l'envoie.
Tu peux rendre cet évènement static, comme ça tu t'y abonnes dès l'initialisation de ton programme, que tu aies des locomotives ou pas. Et quand il y en aura il sera prêt.
Je t'invite à lire ce tuto https://tlevesque.developpez.com/tutoriels/csharp/delegues-et-evenements/ sur les délégués et les évènements.
robunccm
Messages postés
52
Date d'inscription
jeudi 7 février 2019
Statut
Membre
Dernière intervention
9 mars 2024
1
21 févr. 2019 à 00:19
21 févr. 2019 à 00:19
Merci de ta réponse
Je vais la décortiquer
Mais je te soumets ceci qui fonctionne, pour le moment, très bien qu'en penses-tu ?
Les deux premières lignes ne servent qu'à mettre la valeur du Slider dans le Bargraph sur le pupitre
la troisième ligne me permet de récupérer l'Arduino qui m'intéresse dans ard
dés lors je peux atteindre la méthode Send et lui passer la valeur de vitesse
et puis lancer la réception pour contrôle
les premiers test sont encourageants
Je vais la décortiquer
Mais je te soumets ceci qui fonctionne, pour le moment, très bien qu'en penses-tu ?
private void SliVitesse_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
C20Locomotive loco = (C20Locomotive)((Slider)sender).DataContext;
loco.Vitesse = loco.Vitesse;
C30Arduino ard = arduinos.Find(x => x.NumARD == "172");
ard.Send(loco.Vitesse.ToString());
int ret = ard.Receive(i);
}
Les deux premières lignes ne servent qu'à mettre la valeur du Slider dans le Bargraph sur le pupitre
la troisième ligne me permet de récupérer l'Arduino qui m'intéresse dans ard
dés lors je peux atteindre la méthode Send et lui passer la valeur de vitesse
et puis lancer la réception pour contrôle
les premiers test sont encourageants
robunccm
Messages postés
52
Date d'inscription
jeudi 7 février 2019
Statut
Membre
Dernière intervention
9 mars 2024
1
21 févr. 2019 à 00:20
21 févr. 2019 à 00:20
petite précision le code est dans le behind
Les deux premières lignes ne servent qu'à mettre la valeur du Slider dans le Bargraph sur le pupitre
Tu n’en a pas besoin, il te suffit de binder le slider et le baregraphe sur la propriété Vitesse.
Pour la suite, c’est une option, mais que se passe t il si le message est incomplet? Si j’ai bien compris, tu sélectionnes ta loco, tu règles la vitesse et tu appuies sur avant ou arrière. Donc à ce moment là tu envoies un messages partiel.
robunccm
Messages postés
52
Date d'inscription
jeudi 7 février 2019
Statut
Membre
Dernière intervention
9 mars 2024
1
21 févr. 2019 à 08:33
21 févr. 2019 à 08:33
Dans la pratique c'est l'inverse on choisit un sens de marche et ensuite on agit sur la vitesse. Chaque variation du Slider est transmise. D'ailleurs le Slider est inhibé si aucun sens de marche n'est choisi.
Merci de ton aide je vais attaquer le tuto sur les délégués et événements cela s'impose
Merci de ton aide je vais attaquer le tuto sur les délégués et événements cela s'impose
Utilisateur anonyme
22 févr. 2019 à 18:00
22 févr. 2019 à 18:00
Bonsoir
Je ne comprends pas pourquoi la window est une propriété static de ta class GD.
Je ne voie pas non plus où cette windows obtient l'instance de binding.
Je ne comprends pas pourquoi la window est une propriété static de ta class GD.
Je ne voie pas non plus où cette windows obtient l'instance de binding.
robunccm
Messages postés
52
Date d'inscription
jeudi 7 février 2019
Statut
Membre
Dernière intervention
9 mars 2024
1
22 févr. 2019 à 18:55
22 févr. 2019 à 18:55
Je ne comprends pas pourquoi la window est une propriété static de ta class GD.
Parce que j'ai ce message d'erreur
mais effectivement si je déclare la window dans MainWindow je n'ai pas d'errreur mais cela ne règle pas mon soucis
Je ne voie pas non plus où cette windows obtient l'instance de binding
pour être honnête je ne suis même pas sûr de bien comprendre ta question
En tout cas dans XAML il manquait (par rapport à MainWindow) 2 Binding dans Title et Grid
J'ai corrigé comme suit mais sans progrès
voici le code behind de la fenêtre il y a des lignes inutiles car normalement il n'y aura pas deux collections d'aiguillages, c'était juste pour les testes
En tout cas merci de tes conseils. J'espère ne pas abuser de ta générosité, je cherche également beaucoup sur internet mais comme tu me l'avais écrit il y a beaucoup à découvrir...
Parce que j'ai ce message d'erreur
mais effectivement si je déclare la window dans MainWindow je n'ai pas d'errreur mais cela ne règle pas mon soucis
Je ne voie pas non plus où cette windows obtient l'instance de binding
pour être honnête je ne suis même pas sûr de bien comprendre ta question
En tout cas dans XAML il manquait (par rapport à MainWindow) 2 Binding dans Title et Grid
J'ai corrigé comme suit mais sans progrès
<Window x:Class="RobTrainV0.W10GareSecrete1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:RobTrainV0" mc:Ignorable="d" Title="W10GareSecrete1" DataContext="{Binding}" Height="800" Width="1470" Background="MintCream" Topmost="True"> <Grid DataContext="{Binding .}" > <Button Content="Button" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Margin="10,10,0,0"/> <!--la listbox est bindée sur la propriété 'AigsChoisies'--> <ListBox x:Name="listLocomotive" DataContext="{Binding .}" ItemsSource="{Binding AigsChoisies}" VerticalAlignment="Top" HorizontalAlignment="Left" Height="800" Width="434" Margin="0,188,0,0" BorderThickness="0,0"> <ListBox.ItemTemplate> <DataTemplate> <!--son template est composé d'un stackpanel, qui empile les controles, verticalement par défaut (on peut demander horizontalement)--> <StackPanel VerticalAlignment="Top" HorizontalAlignment="Left" Height="36" Width="78" Margin="0,0,0,0" > <!--le nom est affiché en rouge, l'image en fond et un slider est bindé sur la propriété 'Pourcentage'--> <StackPanel.Background> <ImageBrush ImageSource="E:/5-Train/300-appWPF/RobTrainV0/RobTrainV0/Resources/Ai000DrDeviee.png"/> </StackPanel.Background> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </Grid> </Window>
voici le code behind de la fenêtre il y a des lignes inutiles car normalement il n'y aura pas deux collections d'aiguillages, c'était juste pour les testes
namespace RobTrainV0 { /// <summary> /// Logique d'interaction pour W10GareSecrete1.xaml /// </summary> public partial class W10GareSecrete1 : Window { List<C41Aiguillage> aigs = new List<C41Aiguillage> { }; //Ce type de collection signale au binding quand un item est ajouté ou supprimé public ObservableCollection<C41Aiguillage> AigDisponibles { get; set; } public ObservableCollection<C41Aiguillage> AigChoisies { get; set; } public W10GareSecrete1() { InitializeComponent(); /*********************************************************************************************************************************************/ // Création des objets Aiguillages int nbAig =10; int iAig = 0; while (iAig < nbAig) { aigs.Add(new C41Aiguillage(123 + iAig, "toto", true)); iAig = iAig + 1; } AigChoisies = new ObservableCollection<C41Aiguillage>(aigs.Where(l => l.NumAIG>126));//on crée la collection de locos choisies AigDisponibles = new ObservableCollection<C41Aiguillage>(aigs.Where(l => !(l.NumAIG>126)));//on crée la collection de locos disponibles } } }
En tout cas merci de tes conseils. J'espère ne pas abuser de ta générosité, je cherche également beaucoup sur internet mais comme tu me l'avais écrit il y a beaucoup à découvrir...
mais effectivement si je déclare la window dans MainWindow je n'ai pas d'errreur mais cela ne règle pas mon soucisben oui, une windows n'a pas vocation a être une variable statique.
pour être honnête je ne suis même pas sûr de bien comprendre ta question
tu y a répondu en montrant le code du constructeur de ta windows.
Il manque
this.DataContext = this;
Mais comme je l'avais mis en commentaire précédemment c'est pas le top.
Là, tu génères tes collections dans le code behind de la fenêtre.
Mais le rôle d'une fenêtre est d'afficher ou de permettre la saisie manuelle des données.
Ça n'est pas à elle de gérer la base de données.
Il faudrait écrire une classe qui lit Access et crée les collections.
Tu passes ensuite l'instance de cette classe en paramètres aux autres fenêtres et c'est elle qui devient le datacontext de chaque fenêtre.
robunccm
Messages postés
52
Date d'inscription
jeudi 7 février 2019
Statut
Membre
Dernière intervention
9 mars 2024
1
23 févr. 2019 à 00:14
23 févr. 2019 à 00:14
Merci beaucoup, mais il faut que je me rende à l'évidence il me manque beaucoup trop de bases pour avancer dans mon projet.
Je veux malgré persister dans l'apprentissage de WPF et je vais donc entreprendre une démarche plus progressive d'acquisition de ce langage avec des tutos et des exemples.
Il faut qu'en j'en assimile davantage les concepts sachant qu'en plus mon besoin n'est pas réellement un traitement séquentiel de données c'est plus une application d'automatisme avec de nombreuses interactions entre les différents organes.
Dans l'absolu je ne suis pas sûr que ce langage soit le mieux adapté j'ai un passé d'automaticien et nous traitions les applications industrielles avec des produits et des logiciels dédiés.
Je vais donc libérer un peu de ta bande passante mais nul doute que je chercherai encore ton soutien A+ Merci
Je veux malgré persister dans l'apprentissage de WPF et je vais donc entreprendre une démarche plus progressive d'acquisition de ce langage avec des tutos et des exemples.
Il faut qu'en j'en assimile davantage les concepts sachant qu'en plus mon besoin n'est pas réellement un traitement séquentiel de données c'est plus une application d'automatisme avec de nombreuses interactions entre les différents organes.
Dans l'absolu je ne suis pas sûr que ce langage soit le mieux adapté j'ai un passé d'automaticien et nous traitions les applications industrielles avec des produits et des logiciels dédiés.
Je vais donc libérer un peu de ta bande passante mais nul doute que je chercherai encore ton soutien A+ Merci
Il faut qu'en j'en assimile davantage les concepts sachant qu'en plus mon besoin n'est pas réellement un traitement séquentiel de données c'est plus une application d'automatisme avec de nombreuses interactions entre les différents organes.
L’objet est parfaitement adapté, il faut « juste » bien les concevoir.
Je vais te faire un exemple le plus simple possible avec un carnet de contacts.
robunccm
Messages postés
52
Date d'inscription
jeudi 7 février 2019
Statut
Membre
Dernière intervention
9 mars 2024
1
23 févr. 2019 à 11:38
23 févr. 2019 à 11:38
Je te remercie de ta patience, mais comme exemple pourrais-tu faire très simplement
un MainWindow avec un TextBox1 bindé sur une Casse C1 et qui lorsqu'il évolue met à jour un autre TextBox2 bindé sur une Classe C2
dans le MainWindow un Bouton qui ouvre une Window avec un TextbBox ou Listbox bindé sur une Classe C3 et que lorsque celui-ci évolue le TextBox2 de C2 soit actualisé
mais bien sûr ce n'est qu'un souhait mais qui illustre bien mon besoin et devrait me permettre d'avancer
un MainWindow avec un TextBox1 bindé sur une Casse C1 et qui lorsqu'il évolue met à jour un autre TextBox2 bindé sur une Classe C2
dans le MainWindow un Bouton qui ouvre une Window avec un TextbBox ou Listbox bindé sur une Classe C3 et que lorsque celui-ci évolue le TextBox2 de C2 soit actualisé
mais bien sûr ce n'est qu'un souhait mais qui illustre bien mon besoin et devrait me permettre d'avancer
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question
Utilisateur anonyme
23 févr. 2019 à 12:10
23 févr. 2019 à 12:10
J'ai un carnet de contact stocké dans un fichier xml, parce que
Question souplesse, mon premier contact a 3 numéros et 2 adresses, alors que le second n'en a qu'1 de chaque.
J'ai donc une classe qui va contenir ces informations
J'ai une classe qui sait lire et écrire le fichier.
Elle aurait pu être static, en effet, y'a pas besoin de plusieurs instances, mais je ne veux pas que tout le monde trifouille le fichier.
J'ai utilisé LinqToXml, comme tu fais de l'Access ne te prends pas la tête sur ce code, il marche.
Cependant, je n'ai pas géré le cas (tout à fait possible en xml) ou un élément ou un attribut serait absent.
Dans MainWindow je veux afficher une liste non modifiable avec les infos principales.
Si je double clique, ça doit afficher une autre windows avec tous les éléments éditables (c'est pas tout à fait vrai, en effet KeyValuePair n'est pas adapté, mais je voulais faire un exemple simple et rapide, donc adresses et numéros ne sont pas éditables).
Enfin quand cette fenêtre se ferme ça enregistre les données dans le xml (ne se pose pas la question s'il y a eu modification ou pas et ne permet pas l'annulation -> on fait simple).
Je vais créer un "chef d'orchestre", c'est lui qui va dire à la classe FichierXml, où est le fichier, quand lire ou quand sauvegarder. C'est aussi lui qui contient les données dans la collection qui lui convient.
La deuxième fenêtre n'a pas à connaitre tous mes contacts, juste celui à afficher.
et mes 2 fenêtres
En faisant ainsi,
Le jour où tu veux en faire un site ASP.Net, tu conserves tout le code "métier", tu n'as qu'à adapter l'interface.
Le jour où tu veux passer tes données sur Access. Tu crées une classe pour lire et écrire Access, tu modifies un peu la classe Carnet, mais pour l'interface Carnet s'utilise pareil, et pour Contact c'est complètement transparent.
PS: j'ai mis une option dans le binding d'Identite (mainWindow) et Nom et Prenom (wdwContact) dés qu'on tape un truc dans Nom ou Premon l'affichage d'identité et mis à jour. Pour Naissance, il faut "terminer" la saisie, c'est à dire quitter le TextBox.
PS2: J'ai choisi de faire gérer à l'interface de mainWindow la récupération du contact à transférer à la 2eme fenêtre
PS3: Si j'avais mis la seconde fenêtre comme propriété (statique ou non) de Contact:
- c'est facile à fournir dans un forum
- contrairement à un csv c'est souple au niveau des champs
<?xml version="1.0" encoding="utf-8"?> <CarnetDeContacts> <Contact Nom="Di" Prenom="Alain" Naissance="2000-01-02T00:00:00"> <Notes>Ce contact est bidon</Notes> <Telephones> <Telephone Numero="01 23 45 67 89" Type="Domicile" /> <Telephone Numero="06 23 45 67 89" Type="Portable Perso" /> <Telephone Numero="07 23 45 67 89" Type="Portable Pro" /> </Telephones> <Ardesses> <Adresse Adresse="1 allée du week-end 11 111 Semaine Les Bains" Type="Domicile" /> <Adresse Adresse="7 avenue du mardi 11 111 Semaine Les Bains" Type="Bureau" /> </Ardesses> </Contact> <Contact Nom="Zètofrais" Prenom="Mélanie" Naissance="2010-03-04T00:00:00"> <Notes>Ce contact est goutu</Notes> <Telephones> <Telephone Numero="07 89 67 45 23" Type="Portable Pro" /> </Telephones> <Ardesses> <Adresse Adresse="51 rue du pastaga, 51 515 Cigales Plage" Type="Bureau" /> </Ardesses> </Contact> </CarnetDeContacts>
Question souplesse, mon premier contact a 3 numéros et 2 adresses, alors que le second n'en a qu'1 de chaque.
J'ai donc une classe qui va contenir ces informations
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; namespace CarnetContacts { public class Contact : INotifyPropertyChanged { private string nom; /// <summary> /// Nom du contact /// </summary> public string Nom { get { return nom; } set { if (nom != value) { nom = value; GenerePropertyChanged("Nom"); GenerePropertyChanged("Identite"); } } } private string prenom; /// <summary> /// Prénom du contact /// </summary> public string Prenom { get { return prenom; } set { if (prenom != value) { prenom = value; GenerePropertyChanged("Prenom"); GenerePropertyChanged("Identite"); } } } private DateTime naissance; /// <summary> /// Date de naissance du contact /// </summary> public DateTime Naissance { get { return naissance; } set { if (naissance != value) { naissance = value; GenerePropertyChanged("Naissance"); } } } /// <summary> /// Collection de numéros de téléphone /// </summary> /// <remarks>le type KeyValuePair est le type de base d'un dictionnaire, il associe une clé à une valeur, là je m'en sert pour dire si le numéro est le domicile, le bureau etc...</remarks> public ObservableCollection<KeyValuePair<string, string>> Telephones { get; set; } /// <summary> /// Collection d'adresses /// </summary> public ObservableCollection<KeyValuePair<string, string>> Adresses { get; set; } private string notes; /// <summary> /// Informations diverses /// </summary> public string Notes { get { return notes; } set { if (notes != value) { notes = value; GenerePropertyChanged("Notes"); } } } public string Identite { get { return Prenom + " " + Nom; } } #region INotifyPropertyChanged public event PropertyChangedEventHandler PropertyChanged; private void GenerePropertyChanged(string Propriete) { if (this.PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(Propriete)); } #endregion } }
J'ai une classe qui sait lire et écrire le fichier.
Elle aurait pu être static, en effet, y'a pas besoin de plusieurs instances, mais je ne veux pas que tout le monde trifouille le fichier.
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Xml.Linq; namespace CarnetContacts { public class FichierXML { private string chemin; public FichierXML(string Chemin) { chemin = Chemin; } public IEnumerable<Contact> LireFichier() { XDocument xdoc = XDocument.Load(chemin); return (from c in xdoc.Descendants("Contact") select new Contact { Nom = c.Attribute("Nom").Value, Prenom = c.Attribute("Prenom").Value, Naissance = Convert.ToDateTime(c.Attribute("Naissance").Value), Notes = c.Element("Notes").Value, Telephones = new ObservableCollection<KeyValuePair<string, string>>( from t in c.Descendants("Telephone") select new KeyValuePair<string,string>(t.Attribute("Numero").Value, t.Attribute("Type").Value)), Adresses = new ObservableCollection<KeyValuePair<string, string>>( from a in c.Descendants("Adresse") select new KeyValuePair<string, string>(a.Attribute("Adresse").Value, a.Attribute("Type").Value)), } ); } public void EcrireFichier(IEnumerable<Contact> Contacts) { XDocument xdoc = new XDocument ( new XElement("CarnetDeContacts", from c in Contacts select new XElement("Contact", new XAttribute("Nom", c.Nom), new XAttribute("Prenom", c.Prenom), new XAttribute("Naissance", c.Naissance), new XElement("Notes", c.Notes), new XElement("Telephones", from t in c.Telephones select new XElement("Telephone", new XAttribute("Numero", t.Key), new XAttribute("Type", t.Value))), new XElement("Ardesses", from a in c.Adresses select new XElement("Adresse", new XAttribute("Adresse", a.Key), new XAttribute("Type", a.Value))) )) ); xdoc.Save(chemin); } } }
J'ai utilisé LinqToXml, comme tu fais de l'Access ne te prends pas la tête sur ce code, il marche.
Cependant, je n'ai pas géré le cas (tout à fait possible en xml) ou un élément ou un attribut serait absent.
Dans MainWindow je veux afficher une liste non modifiable avec les infos principales.
Si je double clique, ça doit afficher une autre windows avec tous les éléments éditables (c'est pas tout à fait vrai, en effet KeyValuePair n'est pas adapté, mais je voulais faire un exemple simple et rapide, donc adresses et numéros ne sont pas éditables).
Enfin quand cette fenêtre se ferme ça enregistre les données dans le xml (ne se pose pas la question s'il y a eu modification ou pas et ne permet pas l'annulation -> on fait simple).
Je vais créer un "chef d'orchestre", c'est lui qui va dire à la classe FichierXml, où est le fichier, quand lire ou quand sauvegarder. C'est aussi lui qui contient les données dans la collection qui lui convient.
La deuxième fenêtre n'a pas à connaitre tous mes contacts, juste celui à afficher.
using System.Collections.ObjectModel; namespace CarnetContacts { public class Carnet { FichierXML xml; public Carnet() { xml = new FichierXML("mesContacts.xml"); Contacts = new ObservableCollection<Contact>(xml.LireFichier()); } public ObservableCollection<Contact> Contacts { get; set; } public void Enregistrer() { xml.EcrireFichier(Contacts); } } }
et mes 2 fenêtres
<Window x:Class="CarnetContacts.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:CarnetContacts" mc:Ignorable="d" Title="MainWindow" Height="350" Width="900" DataContext="{Binding}"> <Grid DataContext="{Binding .}"> <ListBox DataContext="{Binding .}" ItemsSource="{Binding Contacts}" MouseDoubleClick="ListBox_MouseDoubleClick"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Identite, UpdateSourceTrigger=PropertyChanged}" Width="150"/> <TextBlock Text="{Binding Naissance, StringFormat='Anniversaire {0:dd/MM}'}" Width="150"/> <ListBox DataContext="{Binding .}" ItemsSource="{Binding Telephones}"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Value}" Width="100"/> <TextBlock Text="{Binding Key}" Width="100"/> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox> <ListBox DataContext="{Binding .}" ItemsSource="{Binding Adresses}"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Value}" Width="100"/> <TextBlock Text="{Binding Key}" Width="230"/> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </Grid> </Window>
using System; using System.Windows; using System.Windows.Controls; using System.Windows.Input; namespace CarnetContacts { /// <summary> /// Logique d'interaction pour MainWindow.xaml /// </summary> public partial class MainWindow : Window { Carnet carnet; public MainWindow() { InitializeComponent(); carnet = new Carnet(); this.DataContext = carnet; } private void ListBox_MouseDoubleClick(object sender, MouseButtonEventArgs e) { Contact contact = (Contact)((ListBox)sender).SelectedItem; wdwContact wdw = new wdwContact(contact); wdw.Closed += Wdw_Closed; wdw.Show(); } private void Wdw_Closed(object sender, EventArgs e) { carnet.Enregistrer(); } } }
<Window x:Class="CarnetContacts.wdwContact" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:CarnetContacts" mc:Ignorable="d" Title="wdwContact" Height="300" Width="600" DataContext="{Binding}"> <Grid DataContext="{Binding .}"> <TextBox Text="{Binding Prenom, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Height="23" Margin="37,34,0,0" VerticalAlignment="Top" Width="120"/> <TextBox Text="{Binding Nom, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Height="23" Margin="162,34,0,0" VerticalAlignment="Top" Width="120"/> <TextBox Text="{Binding Naissance}" HorizontalAlignment="Left" Height="23" Margin="162,74,0,0" VerticalAlignment="Top" Width="120"/> <TextBox Text="{Binding Notes}" HorizontalAlignment="Left" Height="84" Margin="37,142,0,0" VerticalAlignment="Top" Width="223"/> <Label Content="Prénom" HorizontalAlignment="Left" Height="29" Margin="56,0,0,0" VerticalAlignment="Top" Width="72"/> <Label Content="Nom" HorizontalAlignment="Left" Height="29" Margin="188,0,0,0" VerticalAlignment="Top" Width="72"/> <Label Content="Date de naissance" HorizontalAlignment="Left" Height="23" Margin="37,74,0,0" VerticalAlignment="Top" Width="120"/> <Label Content="Notes" HorizontalAlignment="Left" Height="26" Margin="85,111,0,0" VerticalAlignment="Top" Width="110"/> <ListBox HorizontalAlignment="Left" Height="100" Margin="322,34,0,0" VerticalAlignment="Top" Width="260" DataContext="{Binding .}" ItemsSource="{Binding Telephones}"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Value}"/> <TextBlock Text="{Binding Key}"/> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox> <ListBox HorizontalAlignment="Left" Height="100" Margin="322,144,0,0" VerticalAlignment="Top" Width="260" DataContext="{Binding .}" ItemsSource="{Binding Adresses}"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Value}"/> <TextBlock Text="{Binding Key}"/> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </Grid> </Window>
using System.Windows; namespace CarnetContacts { /// <summary> /// Logique d'interaction pour wdwContact.xaml /// </summary> public partial class wdwContact : Window { public wdwContact(Contact Contact) { InitializeComponent(); this.DataContext = Contact; } } }
En faisant ainsi,
- les fenêtres ne savent pas d'où viennent les données ni comment on les enregistre.
- la classe contact vie sa vie, peut importe que les données viennent d'Access ou d'un xml, et peut importe qui est affiché où.
Le jour où tu veux en faire un site ASP.Net, tu conserves tout le code "métier", tu n'as qu'à adapter l'interface.
Le jour où tu veux passer tes données sur Access. Tu crées une classe pour lire et écrire Access, tu modifies un peu la classe Carnet, mais pour l'interface Carnet s'utilise pareil, et pour Contact c'est complètement transparent.
PS: j'ai mis une option dans le binding d'Identite (mainWindow) et Nom et Prenom (wdwContact) dés qu'on tape un truc dans Nom ou Premon l'affichage d'identité et mis à jour. Pour Naissance, il faut "terminer" la saisie, c'est à dire quitter le TextBox.
PS2: J'ai choisi de faire gérer à l'interface de mainWindow la récupération du contact à transférer à la 2eme fenêtre
Contact contact = (Contact)((ListBox)sender).SelectedItem;. Mais j'aurais pu avoir une propriété ContactSelectionne dans Carnet, bindé sur la listBox et c'est cette propriété qui aurait été donnée en paramètre à la seconde fenêtre. Je ne voulais pas t'en mettre trop d'un coup dans le xml.
PS3: Si j'avais mis la seconde fenêtre comme propriété (statique ou non) de Contact:
- option 1, j'en fais autant que j'ai de contact -> pas modulaire non
- option 2, je fais en sorte de lui passer le contact autrement que par le constructeur, modulaire ok. Mais quand je la ferme elle n'est plus instanciée, il faut donc la réinstancier à chaque fois (pas de gain par rapport à l'instancier dans mainWindows) et le jour où tu passes en ASP.Net, tu disposes d'une instance de windows qui n'existent pas en ASP. Bref, une window c'est de l'interface, ça ne va pas dans une classe métier.
robunccm
Messages postés
52
Date d'inscription
jeudi 7 février 2019
Statut
Membre
Dernière intervention
9 mars 2024
1
24 févr. 2019 à 10:32
24 févr. 2019 à 10:32
Merci Whismeril parfait cet exemple
il illustre bien les relations entre les diverses entités
et j'ai ma réponse avec
je commence à entrevoir une solution pour mes Window réseau j'ai transformé un StackPanel par un Canvas
dans ton exemple juste pour tester
Là j'ai de quoi œuvrer quelques jours et te laisser souffler un peu, enfin j'espère ...
il illustre bien les relations entre les diverses entités
et j'ai ma réponse avec
UpdateSourceTrigger=PropertyChanged}"
je commence à entrevoir une solution pour mes Window réseau j'ai transformé un StackPanel par un Canvas
dans ton exemple juste pour tester
</ListBox> <ListBox DataContext="{Binding .}" ItemsSource="{Binding Adresses}" Canvas.Left="500"> <ListBox.ItemTemplate> <DataTemplate> <Canvas Width="300" Height="50" Background="YellowGreen"> <TextBlock Text="{Binding Value}" Width="100" Canvas.Top="5" Canvas.Left="10"/> <TextBlock Text="{Binding Key}" Width="230" Canvas.Top="20" Canvas.Left="30"/> </Canvas> </DataTemplate> </ListBox.ItemTemplate> </ListBox>
Là j'ai de quoi œuvrer quelques jours et te laisser souffler un peu, enfin j'espère ...
Bonjour
comme je te l'ai dit, c'était un exemple simple et rapide, donc je n'ai pas peaufiné la présentation, le stackPanel a l'avantage de mettre ses enfants à la suite sans s'embêter c'était donc un gain de temps pour moi
Je n'avais pas réactualisé la page quand j'ai posté l'exemple, je viens juste de découvrir ta question...
je commence à entrevoir une solution pour mes Window réseau j'ai transformé un StackPanel par un Canvas
dans ton exemple juste pour tester
comme je te l'ai dit, c'était un exemple simple et rapide, donc je n'ai pas peaufiné la présentation, le stackPanel a l'avantage de mettre ses enfants à la suite sans s'embêter c'était donc un gain de temps pour moi
et j'ai ma réponse avecUpdateSourceTrigger=PropertyChanged}"
Je n'avais pas réactualisé la page quand j'ai posté l'exemple, je viens juste de découvrir ta question...
robunccm
Messages postés
52
Date d'inscription
jeudi 7 février 2019
Statut
Membre
Dernière intervention
9 mars 2024
1
24 févr. 2019 à 10:59
24 févr. 2019 à 10:59
Question devenue inutile car ton exemple est déjà très productif
robunccm
Messages postés
52
Date d'inscription
jeudi 7 février 2019
Statut
Membre
Dernière intervention
9 mars 2024
1
22 févr. 2019 à 14:35
22 févr. 2019 à 14:35
Bonjour Whismeril
J'attaque un nouvel épisode de La Vie du Rail et commence à travailler sur la représentation du réseau ferré. Idéalement j'aimerasi implémenter plusieurs fenêtres chacune contenant une partie du réseau comme par exemple une gare.
J'imagine
créer une Class Aiguillage contenant Droit et contenant Gauche
Dans un premier temps j'ai transposé l'exemple des Locomotives aux Aiguillages
mais sans la partie boutons de choix car par définition tous les aiguillages créés sont Choisis
Ne prête pas attention à la Class aiguillage elle est volontairement rudimentaire pour les testes.
En pratique un aiguillage est assez complexe mais ce sera pour plus tard.
Mon soucis c'est qu'ils ne s'affichent pas dans ma nouvelle fenêtre alors qu'avec un programme identique ils s'affichent dans MainWindow
Voici le code XAML de la fenêtre W10GareSecrete1 que j'affiche avec dans le behind de MainWindow
et sa déclaration dans une Class
on remarquera que le bouton "Button" hors listbox lui est bien créer
j'essaie cette solution pour pouvoir tester Canvas dont j'ai cru comprendre qu'il permettait de positionner chaque Control
Mais peut être que je me fourvoie dans mes choix et qu'il existe une meilleure solution
En réalité je voudrait que chaque fenêtre se construise dynamiquement à partir d'une table Access qui décrirait tous les éléments du réseau de cette fenêtre, cela me permettrait de concevoir une autre application qui serais comme un éditeur de vue graphique disposant d'une bibliothèque de symboles (Aiguillages, ...) et que l'on positionnerais à son gré pour créer la vue.
Charge à cet éditeur de remplir la table Access qui serait ensuite utilisé par l'application de pilotage du réseau.
Quand je saurai faire tout cela je pense que je maîtriserai au moins 1% de WPF
J'attaque un nouvel épisode de La Vie du Rail et commence à travailler sur la représentation du réseau ferré. Idéalement j'aimerasi implémenter plusieurs fenêtres chacune contenant une partie du réseau comme par exemple une gare.
J'imagine
créer une Class Aiguillage contenant Droit et contenant Gauche
Dans un premier temps j'ai transposé l'exemple des Locomotives aux Aiguillages
mais sans la partie boutons de choix car par définition tous les aiguillages créés sont Choisis
Ne prête pas attention à la Class aiguillage elle est volontairement rudimentaire pour les testes.
En pratique un aiguillage est assez complexe mais ce sera pour plus tard.
Mon soucis c'est qu'ils ne s'affichent pas dans ma nouvelle fenêtre alors qu'avec un programme identique ils s'affichent dans MainWindow
Voici le code XAML de la fenêtre W10GareSecrete1 que j'affiche avec dans le behind de MainWindow
GD.W10GS1.Show();
et sa déclaration dans une Class
namespace RobTrainV0 { class C90GlobalData { } class GD { public static String NamePC = " NamePC?"; public static String DbAccess = "DbAccess ?"; public static String DataPictures = "DataPictures ?"; public static W10GareSecrete1 W10GS1 = new W10GareSecrete1(); }
on remarquera que le bouton "Button" hors listbox lui est bien créer
<Window x:Class="RobTrainV0.W10GareSecrete1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:RobTrainV0" mc:Ignorable="d" Title="W10GareSecrete1" Height="800" Width="1470" Background="MintCream" Topmost="True"> <Grid> <Button Content="Button" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Margin="10,10,0,0"/> <!--la listbox est bindée sur la propriété 'AigsChoisies'--> <ListBox x:Name="listLocomotive" DataContext="{Binding .}" ItemsSource="{Binding AigsChoisies}" VerticalAlignment="Top" HorizontalAlignment="Left" Height="800" Width="434" Margin="0,188,0,0" BorderThickness="0,0"> <ListBox.ItemTemplate> <DataTemplate> <!--son template est composé d'un stackpanel, qui empile les controles, verticalement par défaut (on peut demander horizontalement)--> <StackPanel VerticalAlignment="Top" HorizontalAlignment="Left" Height="36" Width="78" Margin="0,0,0,0" > <!--le nom est affiché en rouge, l'image en fond et un slider est bindé sur la propriété 'Pourcentage'--> <StackPanel.Background> <ImageBrush ImageSource="E:/5-Train/300-appWPF/RobTrainV0/RobTrainV0/Resources/Ai000DrDeviee.png"/> </StackPanel.Background> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </Grid> </Window>
j'essaie cette solution pour pouvoir tester Canvas dont j'ai cru comprendre qu'il permettait de positionner chaque Control
Mais peut être que je me fourvoie dans mes choix et qu'il existe une meilleure solution
En réalité je voudrait que chaque fenêtre se construise dynamiquement à partir d'une table Access qui décrirait tous les éléments du réseau de cette fenêtre, cela me permettrait de concevoir une autre application qui serais comme un éditeur de vue graphique disposant d'une bibliothèque de symboles (Aiguillages, ...) et que l'on positionnerais à son gré pour créer la vue.
Charge à cet éditeur de remplir la table Access qui serait ensuite utilisé par l'application de pilotage du réseau.
Quand je saurai faire tout cela je pense que je maîtriserai au moins 1% de WPF
20 févr. 2019 à 20:49
sans static il n'y a pas de message d'erreur
mais dans les deux je n'arrive pas à comprendre comment je peux, sur un changement de valeur d'un TextBlok
dans C20Locomotive, sollicité la méthode Send dans C30Arduino ?
dans le behind j'ai bien un événement lorsque la vitesse évolue
Peux-t-on dans C30Arduino surveiller un événement externe ?
D'habitude je suis plus imaginatif et je finis par trouver une solution mais là je sèche.
D'autant plus que c'est un besoin que j'aurai par ailleurs car d'autre tâche auront à dialoguer avec d'autres Arduino par exemple pour commander des aiguillages, des feux de signalisation ,des passages à niveaux .....