WPF ComboBox et String [Résolu]

Signaler
-
 Theolit -
Bonjour à tous,

Mon but est de faire un WPF qui contient une ComboBox {=CBox} (sans Items)
Au lancement je récupère dans un tableau , les Ports Série actifs du PC.
J'utilise ensuite ce tableau pour remplir ma CBox. Jusqu'ici aucun problème.
Il parvient quand je souhaite récupérer la sélection du COM de la CBox dans un string :
 MonString = CBox.SelectedValue.ToString(); 


J'ai une exception du type:

'((ComboBoxItem)CBox.SelectedItem).Content' threw an exception of type 'System.InvalidCastException'

Cependant en essayant avec des Items pré-remplis, aucun problème..
J'ai essayé de convertir mon tableau en plusieurs type différents mais aucun résultat.

Merci d'avance pour vos réponses :D
Je reste à votre dispo pour toutes questions


Mon code:
public partial class MainWindow : Window
    {
        public  SerialPort myport;
        string MonString = "";
        public MainWindow()
        {
            InitializeComponent();
            myport = new SerialPort();
            myport.BaudRate = 9600;

            string[] ports = SerialPort.GetPortNames();
            foreach (string port in ports)
            {
               // Console.WriteLine(port);
                CBox.Items.Add(port);
            }
        }

        private void Connect_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                MonString = CBox.SelectedValue.ToString(); // Le problème est ici!!
                myport.PortName = MonString;
                myport.Open();
            }
            catch { StatuBar.Content = "Echec de connection..."; }
        }
    }

8 réponses

Messages postés
14472
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
7 avril 2020
501
Là je ne vois pas.

Peux tu mettre ton projet zippé sur un serveur en ligne (cjoint.com par exemple), et poster le lien ici.
Je n'ai plus accès au PC avec des ports com et avec le confinement c'est pas pour tout de suite mais je peux essayer de voir quand même.

Theolit
Messages postés
3
Date d'inscription
mercredi 18 mars 2020
Statut
Membre
Dernière intervention
18 mars 2020

C'est bien ça le problème, ça devrait fonctionner normalement ..

Le lien du projet:

https://www.cjoint.com/c/JCslMC2q7r7
Messages postés
14472
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
7 avril 2020
501
Dans le xaml, supprime
SelectedValuePath="Content"
il n'y a pas de propriété Content dans une string
Theolit
Messages postés
3
Date d'inscription
mercredi 18 mars 2020
Statut
Membre
Dernière intervention
18 mars 2020

Tu es un héro !!!
Merci énormément pour ton aide.
Whismeril
Messages postés
14472
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
7 avril 2020
501 > Theolit
Messages postés
3
Date d'inscription
mercredi 18 mars 2020
Statut
Membre
Dernière intervention
18 mars 2020

un héros? on ne va pas aller jusque là.

SelectedValuePath permet d'indiquer quelle propriété de l'objet est retournée par SelectedValue.
Si la propriété n'existe pas, SelectedValue vaut null.

Dés que j'ai vu le xaml, j'ai compris, la prochaine fois je demanderais de le poster avec le code behind ;)
> Whismeril
Messages postés
14472
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
7 avril 2020

Merci pour tes explications en tout cas :)
Messages postés
14472
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
7 avril 2020
501
Bonsoir

ton code enfreint à la fois les principes de bases de la programmation objet et l'essence de WPF, à savoir la liaison de données (binding).

public partial class MainWindow : Window
    {
        public  SerialPort myport; // on ne met pas une variable interne public, et par convention le nom d'un membre public commence par une majuscule.
        string MonString = ""; //par convention le nom d'une variable interne commence par une minuscule
        public MainWindow()
        {
            InitializeComponent();
            myport = new SerialPort(); //pas d'objet modèle
            myport.BaudRate = 9600;

            string[] ports = SerialPort.GetPortNames();
            foreach (string port in ports) // pas de liaison de données
            {
               // Console.WriteLine(port);
                CBox.Items.Add(port);
            }
        }

        private void Connect_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                MonString = CBox.SelectedValue.ToString(); // pas de liaison de données
                myport.PortName = MonString;
                myport.Open();
            }
            catch { StatuBar.Content = "Echec de connection..."; }
        }
    }



Une fenêtre est un objet comme un autre et doit respecter les mêmes règles.
Si tu veux que le port série soit accessible de l'extérieur, tu en fais une propriété.

Option 1
public SerialPort MyPort {get; set;}


Dans le code behind, tu pourras l'utiliser exactement comme un champ
toto.MyPort = bidule.MyPort;


Cependant, si tu dois changer quoique ce soit au comportement interne, tu passes à l'option 2

priavte SerialPort myPort;
public SerialPort MyPort
{
    get { return myPort;}
    set  {myPort = value;}
}

On voit que la convention de nommage a tout son sens ici.
Le champ privé est protégé par l'encapsulation dans une propriété, si par sécurité MyPort doit être en lecture seule, c'est impossible avec un champ public, alors qu'avec une propriété il suffit de ne pas écrire le setter.
De plus, la liaison de donnée utilise les propriétés et non les champs.

Pour bien coder en WPF, il faut d'abord, bien coder objet, et avoir compris le binding.
J'ai écrit 2 tutos qui présentent mon point de vue d'autodidacte, ils ne sont pas très académiques, mais justement trop académique pour un autodidacte ça ne marche pas forcément.
https://codes-sources.commentcamarche.net/faq/11239-la-programmation-objet-appliquee-a-net-par-l-exemple-partie-1-sur-3
et
https://codes-sources.commentcamarche.net/faq/11277-apercu-du-binding-en-wpf

Pour approfondir, je te conseille d'acquérir le livre WPF par la pratique de Thomas Lebrun.

Ce soir, je n'ai pas de ports série sous la main pour tester ton problème.
Je regarderai demain, si je peux.
Merci beaucoup pour ta réponse. Comme tu as pu le constater je code depuis pas très longtemps en c#/WPF , mais le meilleur moyen d'apprendre reste d'essayer :D

J'ai effectué les quelques modifications que tu avais mis en commentaire (hors les liaisons de données où je n'ai pas vraiment compris par quoi remplacer)

Voilà ce que ça donne: (Oui les noms ont changés entre temps)

public partial class MainWindow : Window
    {
        private SerialPort Myport ;
        public SerialPort MyPort
        {
            get { return MyPort; }
            set { MyPort = value; }
        }

        string COMChange = "";
        public MainWindow()
        {
            InitializeComponent();
            Myport = new SerialPort();
            Myport.BaudRate = 9600;

            string[] ports = SerialPort.GetPortNames();
            foreach (string port in ports)
            {
                Console.WriteLine(port);
                ChoixCOM.Items.Add(port);
            }
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                Myport.Close();
                COMChange = ChoixCOM.SelectedValue.ToString();
                StatuBar.Content = "Connecté au" + COMChange;
                Myport.PortName = COMChange;
                Myport.Open();
            }
            catch { StatuBar.Content = "Echec de connection..."; }
        }
    }



Merci d'avance!!

PS: Vraiment pas mal les tutos
Messages postés
14472
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
7 avril 2020
501
La liaison de données, c'est la traduction de Binding.

Je tache de voir ce qui ne va pas avec les ports dans la journée.

Messages postés
14472
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
7 avril 2020
501
J’ai pris ton code initial, sur un pc avec des ports com.
J’ai juste viré le try catch.
J’ai une erreur quand je ne sélectionne rien (normal), mais sinon ça fonctionne.
Hier ce qui m’étonnait était le fait que l’erreur n’est pas en lien direct avec ton code.

As tu posté tout le code?

Peux tu virer le try catch, parfois un catch reçoit une erreur venue d’ailleurs dans le code en raison de la pile d’appel:
  • le try catch est dans bidule
  • bidule appelle machin
  • dans machin pas de try catch
  • machin appelle trucmuche
  • dans trucmuche pas de try catch.
  • trucmuche plante, c’est le catch de bidule qui reçoit l’erreur

J'ai essayé sur un autre PC ça ne fonctionne pas non plus (sans le try catch)


Voilà tout le code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO.Ports;

namespace WpfArduino
{
    public partial class MainWindow : Window
    {
        private SerialPort Myport ;
        public SerialPort MyPort
        {
            get { return MyPort; }
            set { MyPort = value; }
        }

        string COMChange = "";
        public MainWindow()
        {
            InitializeComponent();
            Myport = new SerialPort();
            Myport.BaudRate = 9600;

            string[] ports = SerialPort.GetPortNames();
            foreach (string port in ports)
            {
                Console.WriteLine(port);
                ChoixCOM.Items.Add(port);
            }
        }

        private void Button1_Click(object sender, RoutedEventArgs e)
        {
            Myport.WriteLine("O");
        }

        private void Button2_Click(object sender, RoutedEventArgs e)
        {
            Myport.WriteLine("F");
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            
                Myport.Close();
                COMChange = ChoixCOM.SelectedValue.ToString();
                StatuBar.Content = "Connecté au  " + COMChange;
                Myport.PortName = COMChange;
                Myport.Open();
            
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            Myport.Close();
        }
    }
}




Et ici mon erreur:
{"La référence d'objet n'est pas définie à une instance d'un objet."}
Messages postés
14472
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
7 avril 2020
501
A quelle ligne?
As tu bien sélectionné un port? Cette erreur vaut dire qu’un objet est null.
Or si tu n’as rien sélectionné dans le comboxbox SelectedValue est null
Oui j'ai bien vu que ça venait de ça ligne 57 , je sélectionne bien l'un des ports présent. Comme je l'ai dis plus haut, quand j'ajoute un item à la "main" ça fonctionne mais quand je passe par la récupération des ports actifs et mon tableau , le port que je sélectionne ne fonctionne pas
Messages postés
14472
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
7 avril 2020
501
Mets un point d’arrêt sur la ligne 57.
Avec la souris passe sur tous comChange, Choixcom et selectedvalue pour voir lequel des ces 3 objets est null.

Il faudra ensuite déterminer pourquoi
C'est SelectedValue qui est null , ChoixCOM récupère bien ce qu'il faut :( System.Windows.Controls.ComboBox Items.Count : 3)
Messages postés
14472
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
7 avril 2020
501
Tu peux poster une capture d’écran juste avant de cliquer sur le bouton?
Theolit
Messages postés
3
Date d'inscription
mercredi 18 mars 2020
Statut
Membre
Dernière intervention
18 mars 2020

La photo avant de cliquer:



Celle de l'erreur après avoir sélèctionné le COM3 et cliquer sur le bouton: