Supprimer des boutons créés dynamiquement

Résolu/Fermé
robunccm Messages postés 52 Date d'inscription jeudi 7 février 2019 Statut Membre Dernière intervention 9 mars 2024 - 16 févr. 2019 à 17:02
Whismeril Messages postés 19021 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 16 avril 2024 - 19 févr. 2019 à 00:04
Bonjour à tous et à Whismeril en particulier tellement assidu à partager mes interrogations.

Voici le contexte : dans mon appli j'interroge une base de données Access dont les enregistrements caractérisent des locomotives. Deux champs Boolean, Existe et Choisi, déterminent le type d'affichage voulu.
Existe && !Choisi affiche un bouton permettant de basculer Choisi.
Existe && Choisi affiche une Window pour piloter la locomotives.

Ma question porte sur l'affichage bouton qui fonctionne correctement avec le programme suivant
            for (x_numId = 1; x_numId <= nbl; x_numId = x_numId + 1)
            {
                if ((Loco.existe[x_numId] == true) && (Loco.choisi[x_numId] != true))
                {
                    Button btn = new Button();
                    btn.Height = 23; btn.Width = 80; btn.VerticalAlignment = VerticalAlignment.Top; btn.HorizontalAlignment = HorizontalAlignment.Left;
                    btn.Margin = new Thickness(400 + (xBtn * 80), 141, 0, 0);

                    btn.Background = Brushes.Yellow;
                    // Create source.   BitmapImage.UriSource must be in a BeginInit/EndInit block.
                    BitmapImage bi = new BitmapImage(); bi.BeginInit(); bi.UriSource = new Uri("pack://siteoforigin:,,,/Resources/" + Loco.vignette7523[x_numId], UriKind.RelativeOrAbsolute); bi.EndInit();
                    // Set the image source.
                    var brush = new ImageBrush(); brush.ImageSource = bi; btn.Background = brush;

                    btn.Tag = Loco.Id[x_numId];
                    btn.Click += new RoutedEventHandler(btn_Click);
                    btn.Name = "btnLoco" + Convert.ToString(Loco.Id[x_numId]);
                    btn.Content = btn.Name;

                    myGridAC.Children.Insert(myGridAC.Children.Count, btn);
                    xBtn = xBtn + 1;
                }


Voici une partie de l'ecran on apperçoit 4 boutons de loco à choisir et trois pupitres de commande de loco choisies. Pour les testes j'ai rendu Content égale à Name.


Hormis le fait que le programme et sans doute perfectible mon soucis est de supprimer le bouton de myGridAc , non pas le masquer mais le supprimer.

J'ai fait un test pour essayer de l'adresser par son nom
            MessageBox.Show("FindName" + Convert.ToString(GD.FoAC.FindName("btnAffichageUtilities")));
            MessageBox.Show("FindName" + Convert.ToString(GD.FoAC.FindName("btnLoco4")));


la première ligne pointe sur un bouton créer dans XAML me renvoi bien le Content
la deuxième ligne point sur un bouton créé avec le code précédent et ne renvoi rien !!!!

Plus je comprends moins je comprends ..... mais j'avance
Merci de votre aide Roland

J'ai aussi imaginé de lister les control de ma fenêtre mais en WPF je n'y suis pas encore arrivée malgré les exemples, souvent contradictoires, que j'ai pu trouver.
A voir également:

6 réponses

Whismeril Messages postés 19021 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 16 avril 2024 928
16 févr. 2019 à 17:59
Bonsoir

peux tu expliquer ce que tu veux faire (à part supprimer un bouton)?

Je crois comprendre que tu as des locomotives, et que tu en choisis un certain nombre pour en faire quelque chose (peu importe quoi pour l'instant), et que forcément une fois choisies elle ne doivent plus apparaître dans cette fenêtre.
C'est bien ça?
1
robunccm Messages postés 52 Date d'inscription jeudi 7 février 2019 Statut Membre Dernière intervention 9 mars 2024 1
Modifié le 16 févr. 2019 à 19:03
Bonsoir Whismeril. oui c'est ça et plus précisément
En effet mon application est destinée à la conduite d’un réseau ferroviaire miniature.
J’ai donc une base Access qui décrit des locomotives. Seules celles opérationnelles (cochées Existe) sont visibles à l’écran soit sous forme d’un Bouton soit sous forme d’un Pupitre de conduite suivant l'état du champ Choisi disponible dans la base.
Au lancement de l’application, après une lecture de ma base, je lance une méthode AffichageBoutonsEtPupitre( ;;;;) c’est ce l’on voit sur la copie partielle d’écran.
Les boutons sont créer dynamiquement et appellent une action commune, la discrimination se fait par la récupération du Tag pour basculer la coche Choisi dans la base.
Tout cela marche assez bien sauf que je ne sais pas supprimer le bouton qui n’a plus à exister puisqu'un Pupitre à été créer pour cette loco.
En fait mon problème est que je ne sais pas adresser un Control ainsi créé. Dans le vieux monde j’usait, voire abusait, du Control.Item("name" + index) mais ça c’était avant … heureusement je ne suis pas du genre nostalgique

J'ai un site balbutiant, très balbutiant, qui devra à terme décrire le projet www.locorob1.fr
0
Whismeril Messages postés 19021 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 16 avril 2024 928
16 févr. 2019 à 19:58
heureusement je ne suis pas du genre nostalgique

en fait si.

Comme je te l'ai dit précédent, pour exploiter WPF, il faut travailler objet.
Dans sa représentation la plus simple, un objet locomotive pourrait contenir tous les champs de ta table de locomotives.

Tu charges ces locomotives dans une collection, tu ta fenêtre tu mets un conteneur de collection (le plus simple étant ListBox) et
  • soit tu fais 2 requêtes, une qui retourne les choisies et une qui retourne les autres, ensuite tu appliques un style ou un Datatemplate à chaque liste
  • soit tu gères directement l'affichage dans le xaml en fonction de la propriété "choisi"


En faisant ainsi, tu n'as aucun contrôles à instancier, supprimer modifier.

Je vais tacher de t'écrire un petit exemple.
1
robunccm Messages postés 52 Date d'inscription jeudi 7 février 2019 Statut Membre Dernière intervention 9 mars 2024 1
16 févr. 2019 à 21:06
en fait si.

en fait non.

"La nostalgie est un sentiment de regret des temps passés ou de lieux disparus ou devenus lointains, auxquels on associe des sensations agréables, souvent a posteriori"

Je ne regrette pas le VBA, seulement il est des ages où le poids du passé est un handicap pour assimiler rapidement des concepts nouveaux car ils constituent un changement de paradigme, mais je ne renonce pas ton exemple, si tu en as le temps, sera le bienvenu.
0
Whismeril Messages postés 19021 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 16 avril 2024 928
16 févr. 2019 à 23:16
Alors, vite fait, pas très joli mais fonctionnel

La classe locomotive:
using System;
using System.ComponentModel;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace Test_WPF
{
    public class Locomotive : INotifyPropertyChanged
    {
        public Locomotive(string LeNom, string LeChemin, bool LeChoix, int Pourcent)
        {
            Nom = LeNom;
            CheminImage = LeChemin;
            Choisie = LeChoix;
            Pourcentage = Pourcent;
        }

        private string nom;
        /// <summary>
        /// Nom de la locomotive
        /// </summary>
        public string Nom
        {
            get { return nom; }
            set
            {
                if (nom != value)
                {
                    nom = value;
                    GenerePropertyChanged("Nom");
                }
            }
        }

        private bool choisie;
        /// <summary>
        /// Retourne ou définit si la loco a été choisie
        /// </summary>
        public bool Choisie
        {
            get { return choisie; }
            set
            {
                if (choisie != value)
                {
                    choisie = value;
                    GenerePropertyChanged("Choisie");
                }
            }
        }

        private string cheminImage;
        /// <summary>
        /// Chemin de l'image
        /// </summary>
        public string CheminImage
        {
            get { return cheminImage; }
            set
            {
                if (cheminImage != value && !string.IsNullOrWhiteSpace(value))
                {
                    cheminImage = value;
                    GenerePropertyChanged("CheminImage");

                    var yourImage = new BitmapImage(new Uri(cheminImage, UriKind.Relative));
                    yourImage.Freeze(); // -> to prevent error: "Must create DependencySource on same Thread as the DependencyObject"
                    Image = yourImage;
                }
            }
        }

        private ImageSource image;
        /// <summary>
        /// Image de la loco
        /// </summary>
        public ImageSource Image
        {
            get { return image; }
            private set
            {
                if (image != value)
                {
                    image = value;
                    GenerePropertyChanged("Image");
                }
            }
        }


        private int pourcent;
        /// <summary>
        ///Pourcentage à afficher sur un slider
        /// </summary>
        public int Pourcentage
        {
            get { return pourcent; }
            set
            {
                if (pourcent != value)
                {
                    if (value > 100 || value < 0)
                        return;

                    pourcent = value;
                    GenerePropertyChanged("Pourcentage");
                }
            }
        }


        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;

        private void GenerePropertyChanged(string Propriete)
        {
            if (this.PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(Propriete));
        }

        #endregion
    }
}


le code behind de la fenêtre
        List<Locomotive> locos;

        //Ce type de collection signale au binding quand un item est ajouté ou supprimé
        public ObservableCollection<Locomotive> Disponibles { get; set; }
        public ObservableCollection<Locomotive> Choisies { get; set; }

        public MainWindow()
        {
            InitializeComponent();


            //pour l'exemple, je remplis la liste dans le code, il faudra le faire à partir ta base de données.
            locos = new List<Locomotive>
            {
                new Locomotive("Loco 1", "tgv.jpg", false, 10),
                new Locomotive("Loco 2", "tgv.jpg", false, 20),
                new Locomotive("Loco 3", "tgv.jpg", true, 30),
                new Locomotive("Loco 4", "tgv.jpg", true, 50),
            };

            Choisies = new ObservableCollection<Locomotive>(locos.Where(l => l.Choisie));//on crée la collection de locos choisies
            Disponibles = new ObservableCollection<Locomotive>(locos.Where(l => !l.Choisie));//on crée la collection de locos disponibles

            this.DataContext = this;//on dit à la fenêtre que son contexte de données est lui-même, une classe 'vue' serait mieux, mais ça marche comme ça aussi


Pour le xaml, j'ai pris une liste box pour afficher mes simili pupitres, car ça empile verticalement ses items et il y a un ascenseur qui apparait si besoin.

Pour les boutons, comme sur ton image ils sont à l'horizontale, je voulais prendre un Wrappanel, qui dispose ses items sur une ligne tant qu'il y a de la place, puis sur une seconde ligne etc...
Cependant il ne se binde pas facile, alors j'ai trouvé sur stacoverflow qu'on peut forcer un ItemControl à se comporter comme un wrappanel.

<Window x:Class="Test_WPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:def="Definition"
        xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
        xmlns:s="clr-namespace:System;assembly=mscorlib"
        
        Title="MainWindow" Height="719" Width="694" DataContext="{Binding}">
    <Grid DataContext="{Binding .}">
        <!--l'itemcontrol hérite son data context de son parent, et il est bindé sur la propriété 'Disponibles'-->
        <ItemsControl DataContext="{Binding .}" ItemsSource="{Binding Disponibles}" Margin="20,20,20,500">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <!--se comporte comme un wrappanel-->
                    <WrapPanel/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <!--le template est la façon de présenter l'item-->
                <DataTemplate>
                    <!--il est composé d'un bouton, dont le background et le content sont bindés, le click est abonné à la méthode 'butChoixLoco_Click'-->
                    <Button Content="{Binding Nom}" Width="200" Height="30" Margin="5" Name="butChoixLoco" Click="butChoixLoco_Click">
                        <Button.Background>
                            <ImageBrush ImageSource="{Binding Image}"/>
                        </Button.Background>
                    </Button>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
        
        <!--la listbox est bindée sur la propriété 'Choisies'-->
        <ListBox DataContext="{Binding .}" ItemsSource="{Binding Choisies}" Margin="20,220,20,20">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <!--son template est composé d'un stackpanel, qui empile les controles, verticalement par défaut (on peut demander horizontalement)-->
                    <StackPanel Width="400">
                        <!--le nom est affiché en rouge, l'image en fond et un slider est bindé sur la propriété 'Pourcentage'-->
                        <StackPanel.Background>
                            <ImageBrush ImageSource="{Binding Image}"/>
                        </StackPanel.Background>
                        <TextBlock Text="{Binding Nom}" Foreground="Red"/>
                        <Button Content="Un bouton" Margin="2"/>
                        <Slider Minimum="0" Maximum="100" Value="{Binding Pourcentage}"/>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
</Grid>


A ce moment là, les locomotives sont affichées différemment selon qu'elles sont choisies ou pas.

Il ne reste plus qu'à en choisir une nouvelle quand le bouton est cliqué
        private void butChoixLoco_Click(object sender, RoutedEventArgs e)
        {
            Locomotive loco = (Locomotive)((Button)sender).DataContext;//sender est le button qui déclenche l'évènement, et son DataContext est la loco que l'on choisit, un jeu de cast permet de récuper l'instance à traiter
            loco.Choisie = true;//on affecte la propriété, pour la sauver dans la bdd plus tard
            Choisies.Add(loco);// on change de collection
            Disponibles.Remove(loco);
        }


Je n'ai instancié aucun contrôle.
J'ai écrit 2 template, l'un affichage un bouton dans lequel il y a un nom et une image, et l'autre empile une boite de texte, un bouton et un slider sur une image.

1
robunccm Messages postés 52 Date d'inscription jeudi 7 février 2019 Statut Membre Dernière intervention 9 mars 2024 1
17 févr. 2019 à 00:57
Je n'espérais pas une réponse si prompte merci beaucoup
J'ai su régler 2 petites coquilles un Using manquant pour ObservableCollection
La fermeture de balise </window> manquante

mais j'ai encore une erreur ou je bute

Gravité	Code	Description	Projet	Fichier	Ligne	État de la suppression
Erreur	CS1061	'MainWindow' ne contient pas de définition pour 'butChoixLoco_Click' et aucune méthode d'extension accessible 'butChoixLoco_Click' acceptant un premier argument de type 'MainWindow' n'a été localisée (une directive using ou une référence d'assembly est-elle manquante ?)
Test_WPF	C:\Users\Roland\source\repos\Test_WPF\Test_WPF\MainWindow.xaml	22	Actif
0
Whismeril Messages postés 19021 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 16 avril 2024 928
Modifié le 17 févr. 2019 à 08:15
Ha pardon je n’ai pas été assez clair, c’est la dernière méthode que je t’ai donnée, il faut la mettre dans le .cs de MainWindow.

Et aussi, il faut une image nommée « tgv.jgp » dans le repertoire Debug ou Release selon en quoi tu compilés
0
robunccm Messages postés 52 Date d'inscription jeudi 7 février 2019 Statut Membre Dernière intervention 9 mars 2024 1
17 févr. 2019 à 10:55
Bonjour Whismeril,

C'est ce que j'avais fait, j'ai même mis les majuscules ButChoixLoco_Click pour faire plaisir à Visual, sachant bien que ce n'était le problème ...

Eureka, je n'avais pas fait de génération je ne lançait qu'en debug

Merci c'est ce que je cherchait à faire mais de cette manière je n'y serai jamais arrivé. Là c'est un bon exemple que je vais décortiquer pour assimiler tout les mécanismes.

Je vais déjà transposer tout le fonctionnement de mon pupitre.

Je risque de revenir vers toi pour pour la fonction inverse, encore merci, en tout cas je te tiens au courant.
0
Whismeril Messages postés 19021 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 16 avril 2024 928
Modifié le 17 févr. 2019 à 11:14
Ha oui, la régénération....

Merci c'est ce que je cherchait à faire mais de cette manière je n'y serai jamais arrivé.

Comme je te l'ai déjà dit apprendre de front C#, l'objet (comme tu l'as écrit dans un message disparu, un tout autre paradigme) et WPF n'est pas le plus simple.

Je vais déjà transposer tout le fonctionnement de mon pupitre.
Sur ton pupitre il y a plein de boutons, je suppose que ce sont des actions à exécuter directement sur la locomotive. La logique voudrait que dans le code behind de la fenêtre tu appelles une méthode dédiée de la classe locomotive.
Par exemple, j'imagine que le bouton Avant fait avancer la locomotive (en fonction du slider pour la vitesse?), et la méthode butAvant_Click devrait appeler la méthode Avancer de la locomotive.

Dans le principe, un objet informatique modélise un objet, concept, être vivant, réel. Il est donc responsable de son fonctionnement.
Tu n'as pas besoin d'être mécanicien pour conduire une voiture, tu passes une vitesse, tu accélères, et tu tournes le volant. Et bien l'objet voiture dispose par exemple, d'une propriété Vitesse, d'une méthode Accélérer et d'une propriété PositionVolant accessibles à un objet conducteur. La propriété Vitesse et la méthode Accélérer vont dialoguer avec l'objet moteur, alors que la propriété PositionVolant va dialoguer avec l'objet Direction, etc....

Je risque de revenir vers toi pour pour la fonction inverse

il suffit de faire l'inverse de ce que fait butChoixLoco_Click
1
robunccm Messages postés 52 Date d'inscription jeudi 7 février 2019 Statut Membre Dernière intervention 9 mars 2024 1
17 févr. 2019 à 12:11
Dans l'esprit c'est déjà ce que j'avais fait en WinForm avec les controles utilisateurs mais avec WPF et en Objet c'est mieux, y a pu qu'à ...

Le pupitre élabore une séquence Ascii qui doit être transmise à un Arduino générant la trame sur les rails celle-ci étant reconnue par une des locomotives grâce à son décodeur intégré selon le principe du DCC

Sur mon site www.locorob1.fr dans la rubrique Réseau - Gestionnaire tu pourras voir ce que j'avais déjà réalisé
Mais je pense qu'il est temps que je déclare ma question comme résolue.
0
robunccm Messages postés 52 Date d'inscription jeudi 7 février 2019 Statut Membre Dernière intervention 9 mars 2024 1
17 févr. 2019 à 19:14
J'avoue que ce n'est pas simple
J'ai bien réussi à créer mes locos suivant ma base Access
J'ai réussi à intégrer mes différents boutons dans ListBox.ItemTemplate
J'ai mis Grid car autrement tous les boutons se mettait les uns sous les autres
                         <StackPanel.Background>
                            <ImageBrush ImageSource="{Binding Image}"/>
                        </StackPanel.Background>
                        <Grid>
                            <TextBlock Text="{Binding Nom}" Foreground="Red"/>
                            <Label x:Name="labEtNumDcc" Content="N°DCC" HorizontalAlignment="Left" VerticalAlignment="Top" Height="24" Margin="0,75,0,0" Width="40" FontSize="8"/>
                            <Slider Value="{Binding Pourcentage}"  HorizontalAlignment="Left" VerticalAlignment="Top" Height="24" Margin="113,10,0,0"  Width="197" Maximum="31" LargeChange="10" SmallChange="8" TickPlacement="TopLeft" />
                            <Button x:Name="btnAvant" Content="AVANT" HorizontalAlignment="Left" VerticalAlignment="Top" Height="23" Margin="120,39,0,0"  Width="65" TabIndex="1" />
                            <Button x:Name="btnArriere" Content="ARRIERE" HorizontalAlignment="Left" VerticalAlignment="Top" Height="23" Margin="190,39,0,0" Width="65" />


J'ai réussi à gérer la libération des locomotives
Je suis récompensé de tes efforts c'est super efficace
Je ne suis pas sûr que Lamartine pensait à la programmation objet quand il à écrit
"Objets inanimés, avez-vous donc une âme ..." mais qui sait

Mais je n'arrive toujours pas à créer les événement liés à ces boutons pour avoir un traitement au sein de l'objet.
Si je déclare un Clik="btnAVANT_Click" en XAML la méthode est crée dans MainWindow
Si je crée cette méthode dans la classe Locomotive elle n'est pas sollicité

Merci d'avance
0
Whismeril Messages postés 19021 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 16 avril 2024 928
17 févr. 2019 à 19:23
Si je déclare un Clik="btnAVANT_Click" en XAML la méthode est crée dans MainWindow
Si je crée cette méthode dans la classe Locomotive elle n'est pas sollicité


Oui c'est normal.
Le Window c'est le support interactif sur lequel sont projetées tes données (un peu comme l'écran d'une tablette).
La méthode abonnée à un évènement d'interface est donc routée dans le code behind du Window.

Là il faut que tu remontes à l'instance de la locomotive et que tu appelles là méthode adéquate.
Regarde butChoixLoco_Click
        private void butChoixLoco_Click(object sender, RoutedEventArgs e)
        {
            Locomotive loco = (Locomotive)((Button)sender).DataContext;//sender est le button qui déclenche l'évènement, et son DataContext est la loco que l'on choisit, un jeu de cast permet de récuper l'instance à traiter
            loco.Choisie = true;//on affecte la propriété, pour la sauver dans la bdd plus tard
            Choisies.Add(loco);// on change de collection
            Disponibles.Remove(loco);
        }

La première ligne récupère la locomotive. Une fois fait tu en fais ce que tu veux, par exemple dans le bouton Avant
loco.Avant();


Il y a moyen d'appeler directement une méthode dans le xaml, mais la syntaxe est alambiquée.
0
Whismeril Messages postés 19021 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 16 avril 2024 928
17 févr. 2019 à 19:25
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Whismeril Messages postés 19021 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 16 avril 2024 928
18 févr. 2019 à 18:08
Comment as tu affiché / masqué / modifiés les boutons « avant arrière arrêt fermer stop »?
1
robunccm Messages postés 52 Date d'inscription jeudi 7 février 2019 Statut Membre Dernière intervention 9 mars 2024 1
18 févr. 2019 à 18:38
J'ai interprété ton exemple comme suit et je vais tenter de te l'expliquer avec un vocabulaire qui ne m'est pas encore familier, j'accepte toute remarque ..
Dans Xaml j'ai bindé Visibility

  </StackPanel.Background>
                        <Grid>
                            <TextBlock Text="{Binding Nom}" Foreground="Brown" HorizontalAlignment="Left" VerticalAlignment="Top" Height="24" Width="90"  Margin="20,30,0,0" FontSize="16" FontWeight="Bold" FontFamily="Arial" />
                            <Label x:Name="labEtNumDcc" Content="N°DCC" HorizontalAlignment="Left" VerticalAlignment="Top" Height="24" Margin="2,0,0,0" Width="40" FontSize="8"/>
                            <Label x:Name="labNumDcc" Content="{Binding NumDCC}" HorizontalAlignment="Left" VerticalAlignment="Top" Height="30"  Width="28" Margin="5,8,0,0" FontSize="18" FontWeight="Bold" FontFamily="Arial" Foreground="Red" />
                            <Image x:Name="vignette" Source="{Binding Image}" VerticalAlignment="Top" HorizontalAlignment="Left" Height="23" Width="70" Margin="32,5,0,0"/>
                            <Slider x:Name="sliVitesse" Value="{Binding Vitesse}" IsEnabled="{Binding SliIsEnabled}" HorizontalAlignment="Left" VerticalAlignment="Top" Height="24" Margin="113,17,0,0"  Width="197" Maximum="124" LargeChange="10" SmallChange="8" TickPlacement="TopLeft" ValueChanged="SliVitesse_ValueChanged" />
                            
                            <Button x:Name="btnFermer" Content="FERMER" Style="{StaticResource styleBouton}" HorizontalAlignment="Left" VerticalAlignment="Top" Height="23" Margin="260,70,0,0" Width="45"  Click="btnFermer_Click"/>
                            <Button x:Name="btnAvant" Content="AVANT" Style="{StaticResource styleBouton}"  Visibility="{Binding CdeVisible}" HorizontalAlignment="Left" VerticalAlignment="Top" Height="23" Margin="120,43,0,0"  Width="65" TabIndex="1" Click="btnAvant_Click">
                                <Button.Background>
                                    <SolidColorBrush Color="{Binding BtnAvantColor}" />
                                </Button.Background>
                                </Button>


dans le behind j'appelle la méthode loco.CdeVisible = "Hidden";
        private void btnStop_Click(object sender, RoutedEventArgs e)
        {
            C20Locomotive loco = (C20Locomotive)((Button)sender).DataContext;
            loco.Vitesse = 0;
            loco.SliIsEnabled = "False";
            if (loco.BtnStopHeight.Equals("50"))
            {
                loco.BtnStopHeight = "23";
                loco.BtnStopColor = "Red";
                loco.CdeVisible = "Hidden";
            }
            else
            {
                loco.BtnStopHeight = "50";
                loco.BtnStopColor = "Yellow";
                loco.CdeVisible = "Visible";
            }
        }


et dans la classe Locomotive j'ai créé la méthode loco.CdeVisible
        private string cdeVisible;
        /// <summary>
        /// Gére Visisible pour les boutons Avant Arriere Arret
        /// </summary>
        public string CdeVisible
        {
            get { return cdeVisible; }
            set
            {
                if (cdeVisible != value)    {   cdeVisible = value; GenerePropertyChanged("CdeVisible");    }
            }
        }

j'ai également toujours dans cette classe initialiser
            cdeVisible = "Visible";


j'applique un traitement similaire pour le Slider sur IsEnabled que je ne valide que si Avant ou Arriere sont actifs

mais ce n'est pas fini je veux également faire passer au rouge le bargraph lorsqu'il dépasse 80% de la vitesse

par contre il faut s'habituer à passé les paramètres sous forme Ascii c'est pas inné pour moi

mais d'abord je veux attaquer mes connexions ethernet si tu m'y autorise j'ouvre une autre question sur ce sujet pour que l'on puisse partager

A+ Roland
0
Whismeril Messages postés 19021 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 16 avril 2024 928
19 févr. 2019 à 00:04
par contre il faut s'habituer à passé les paramètres sous forme Ascii c'est pas inné pour moi


parce qu'il ne faut pas faire comme ça.
                loco.BtnStopHeight = 23;
                loco.BtnStopColor = Colors.Red;
                loco.CdeVisible = Visibility.Hidden;


Tu peux aussi, tout gérer dans le xaml.

Supposons que les méthodes Avancer, Reculer et Stop basculent une propriété Mouvement à true ou false, tu peux modifier le style des bouton avec un datatrigger
        <Style x:Key="styleBouton" TargetType="{x:Type Button}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Border x:Name="Border"  CornerRadius="2"  BorderThickness="1" Background="{Binding Background, RelativeSource={RelativeSource TemplatedParent}}" BorderBrush="#404040">
                            <ContentPresenter Margin="2" HorizontalAlignment="Center" VerticalAlignment="Center" RecognizesAccessKey="True"/>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <DataTrigger Binding="{Binding Mouvement}" Value="True">
                    <Setter Property="Visibility" Value="Hidden"/>
                    <Setter Property="Height" Value="23"/>
                    <Setter Property="Background" Value="Red"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>


Par contre, si tu fais un binding, il ne faut jamais modifier la propriété bindée dans le code behind, sinon ça casse la liaison de données et plus rien ne marche
0
robunccm Messages postés 52 Date d'inscription jeudi 7 février 2019 Statut Membre Dernière intervention 9 mars 2024 1
18 févr. 2019 à 17:47
Bonsoir
Juste pour dire ou montrer ce que j'ai réussi à faire grâce à l'aide de Whismeril que je remercie encore


Dans le pupitre 3 c'est l'état après avoir appuyer sur Stop
Si l'on acquitte en appuyant à nouveau sur Stop on retrouve les boutons de commandes et Stop s'agrandit pour masquer le bouton Fermer
Si l'on appuie sur Fermer le tableau de commande s'efface et un bouton correspondant à cette locomotive rejoint ceux des machines disponibles en haut d'écran

Dans le pupitre du milieu le slider règle la vitesse de la locomotive, en réalité en élabore une chaîne de caractère (visible sous l'image de la loco) qui représente la commande à transmettre via ethernet à un Arduino qui traite la partie puissance.
t1 préfixe de la commande vitesse
10 codage du numéro de locomotive
62 consigne de vitesse
un dernier caractère 0 ou 1 représente le sens de déplacement à venir

Fort de cette expérience je me lance dans la gestion des connexions avec les Arduino, potentiellement une dizaine, donc welcom les objets.

A+ Roland
0