Partage
  • Partager sur Facebook
  • Partager sur Twitter

Utilisation d'un DataGrid

Sujet résolu
    2 août 2018 à 12:00:50

    Bonjour à tous,

    Je débute avec les bases de données. je travaille avec le pattren MVVM. J'ai un DataGrid qui affiche les données de ma table. J'ai remarqué que lors de l'appui sur la touche ENTER une nouvelle ligne se crée dans le DataGrid. Il existe donc un événement ou une méthode ou je ne sais pas quel nom (excusez moi, je débute). Quelle est cette "chose" et comment l'uitiliser en MVVM.

    Merci pour votre aide.

    • Partager sur Facebook
    • Partager sur Twitter
      3 août 2018 à 23:27:26

      C'est une implémentation de comportement spécifique à la DataGrid.

      Par défaut, lorsque ce composant détecte que sa source de données est une liste mutable et si il n'est pas configuré en lecture seule, alors il ajoute la possibilité d'éditer le contenu de la liste (ajouter, éditer, supprimer).

      S'agissant d'un comportement de la DataGrid, "il n'y a rien à faire" pour s'en servir. Côté ViewModel, tu auras une liste d'élément dans laquelle la DG va effectuer ses modifications.

      • Partager sur Facebook
      • Partager sur Twitter
        6 août 2018 à 12:38:46

        Merci Nisnor pour ta réponse. Je dois pas être très doué mais je travaille avec une observablecollection coté ViewModel et lorsque je rentre manuellement des nouvelles données dans le DG il ne se passe rien. Je pense que je ne sais pas utiliser une observablecollection...

        Un peu d'aide serait bien venu. Merci.

        Je donne la vue, le model et la viewmodel:

        Vue:

        <UserControl x:Class="CompteBancaire.Views.UserControleEntree"
                     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                     xmlns:local="clr-namespace:CompteBancaire.Views"
                     mc:Ignorable="d" 
                     d:DesignHeight="450" d:DesignWidth="800"
                     DataContext="{Binding Source={StaticResource ServiceLocator}, 
                                                   Path=UserControlEntreeViewModel}">
        
            <UserControl.Resources>
                <SolidColorBrush x:Key="ColorEntrees" Color="#FF83FD68" Opacity="0.5"/>
                <SolidColorBrush x:Key="BrushTextEntree" Color="#FF037C03"/>
                <SolidColorBrush x:Key="BrushBackGroundEntree" Color="#FF72EC6C" Opacity="0.75"/>
                <SolidColorBrush x:Key="BrushBackgroundMenu" Color="#FF18706C" Opacity="0.05"/>
            </UserControl.Resources>
            <Border>
                <Grid x:Name="GrilleEntree">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="30"/>
                        <RowDefinition Height=" *"/>
                    </Grid.RowDefinitions>
        
                    <Label Foreground="{DynamicResource BrushTextEntree}" HorizontalAlignment="Center" VerticalAlignment="Center" Content="Entrées " FontStyle="Italic" FontSize="14" FontWeight="Bold" FontFamily="Segoe Print" Grid.ColumnSpan="2" />
        
        
        
                    <DataGrid x:Name="DataGridEntree" 
                              ItemsSource="{Binding ItemEntree }"
                              Margin="0,5" Grid.Row="1" BorderBrush="#FF037C03" Foreground="{DynamicResource BrushTextEntree}" AutoGenerateColumns="False" VerticalGridLinesBrush="{DynamicResource BrushTextEntree}" Width="350" FrozenColumnCount="1" HorizontalGridLinesBrush="{DynamicResource BrushTextEntree}" MaxHeight="350" HeadersVisibility="Column" FontFamily="Segoe Print" AreRowDetailsFrozen="True" Grid.ColumnSpan="2" HorizontalAlignment="Center" 
                              SelectionUnit="Cell" SelectionMode="Single" 
                              >
                        <DataGrid.RowBackground>
                            <SolidColorBrush Color="#FF037C03" Opacity="0.05"/>
                        </DataGrid.RowBackground>
                        <DataGrid.AlternatingRowBackground>
                            <SolidColorBrush Color="#FF037C03" Opacity="0.3"/>
                        </DataGrid.AlternatingRowBackground>
                        <DataGrid.Background>
                            <SolidColorBrush Color="#FF72EC6C" Opacity="0.75"/>
                        </DataGrid.Background>
                        <DataGrid.Columns>
                            <DataGridCheckBoxColumn  Header="Valid." Width="50" 
                                                    Binding= "{Binding ValidationEntree }"/> 
                                                   
                            <DataGridTextColumn 
                                Binding="{Binding OperationEntree }" 
                                 Foreground="{DynamicResource BrushTextEntree}" FontFamily="Segoe Print" Header="Opération" Width="200" CanUserResize="True" CanUserReorder="True" />
                            <DataGridTextColumn 
                                Binding="{Binding CreditEntree}" 
                                 Foreground="{DynamicResource BrushTextEntree}" FontFamily="Segoe Print" Header="Crédit" Width="98" FontWeight="Bold"/>
                        </DataGrid.Columns> 
                    </DataGrid>
        
        
                </Grid>
            </Border>
        </UserControl>



        Le Model:

        using System;
        using System.Collections.Generic;
        using System.ComponentModel;
        using System.Linq;
        using System.Text;
        using System.Threading.Tasks;
        using System.Windows;
        
        namespace CompteBancaire.Model
        {
            public class CollectionEntree : INotifyPropertyChanged
            {
                public event PropertyChangedEventHandler PropertyChanged;
        
                private bool validationEntree;
                private string operationEntree;
                private decimal creditEntree;
                public bool CanEnregistrer=false;
                
                public bool ValidationEntree
                {
                    set
                    {
                         validationEntree = value;
        
                        if (PropertyChanged != null)
                        {
                            PropertyChanged(this, new PropertyChangedEventArgs("ValidationEntree"));
                        }
                    }
                    get
                    {
                        return validationEntree;
                    }
                }
        
                public string OperationEntree
                {
                    set
                    {
                        operationEntree = value;
        
                        if (PropertyChanged != null)
                        {
                            PropertyChanged(this, new PropertyChangedEventArgs("OperationEntree"));
                        }
                    }
                    get
                    {
                        return operationEntree;
                    }
                }
        
                public decimal CreditEntree
                {
                    set
                    {
                        creditEntree = value;
        
                        if (PropertyChanged != null)
                        {
                            PropertyChanged(this, new PropertyChangedEventArgs("CreditEntree"));
                        }
                    }
                    get
                    {
                        return creditEntree;
                    }
                }
        
        
        
        
            }
        }
        

        Le ViewModel:

        using CompteBancaire.DAL;
        using CompteBancaire.Model;
        using GalaSoft.MvvmLight;
        using GalaSoft.MvvmLight.Command;
        using System;
        using System.Collections.Generic;
        using System.Collections.ObjectModel;
        using System.ComponentModel;
        using System.Linq;
        
        namespace CompteBancaire.ViewModel
        {
            public class UserControlEntreeViewModel : ViewModelBase
            {
        
                #region Constructeur
                public UserControlEntreeViewModel()
                {
                    SetSourceEntree();
                }
                #endregion
        
                #region Champs
        
                private ObservableCollection<CollectionEntree> itemEntree = new ObservableCollection<CollectionEntree>();
                private CollectionEntree selectEntree;
               
                #endregion
        
                #region Variables
        
                // Nom de la base de données
                public string NomBase="Gestion.mdf";
        
                #endregion
        
                #region Getter et setter pour les bases de données
        
                public ObservableCollection<CollectionEntree> ItemEntree
                {
                    set
                    {
                        
                        itemEntree = value;
                        RaisePropertyChanged("ItemEntree");
                    }
                    get
                    {
                        return itemEntree;
                    }
                }
        
                #endregion
        
                #region Affichage des entrées
                
                private void SetSourceEntree()
                {
                    GestionContext BddGestion = new GestionContext(NomBase);
                    int ComptEntree = BddGestion.Entrees.Count<Entree>();
        
                    var query = (from c in BddGestion.Entrees select c).ToList();
        
                    for (int i = 0; i < ComptEntree; ++i)
                    {
                        ItemEntree.Add(new CollectionEntree { ValidationEntree = (query[i].Validation), OperationEntree = query[i].Operation, CreditEntree = query[i].Credit });
                    }
        
                }
        
                #endregion
        
            }
            
               
        }
        



        • Partager sur Facebook
        • Partager sur Twitter
          6 août 2018 à 15:37:28

          Ce qui change quand tu rajoutes une ligne, ce n'est pas l'instance de collection (1), ni une donnée d'un des éléments (3), mais bien le contenu de la collection (2).

          Or, exactement comme le ferait WPF pour surveiller ce type de changement, il te faut surveiller l'evenement CollectionChanged de ton ObservableCollection, pour être capable de capter les changements effectués au niveau (2). Si tu voulais capter les changements au niveau (1), tu as le setter de ta propriété ItemEntree pour ça. Ca peut être utile de placer du code là dedans pour te désabonner de l'événement avant de changer ta variable privée et de te réabonner à l'événement voulu. Si tu voulais capter les changements au niveau de (3), c'est dans ta classe CollectionEntree que ce serait le plus simple.

          -
          Edité par Nisnor 6 août 2018 à 15:38:03

          • Partager sur Facebook
          • Partager sur Twitter
            6 août 2018 à 23:55:04

            Merci Nisnor de continuer à suivre mes questions et surtout à y répondre.

            Je m'aperçois que mon niveau doit être vraiment très bas. Je ne comprends pas les niveaux 1, 2 et 3 dont tu parles. J'ai bien essayé d'utiliser CollectionChanged mais je pense que je ne sais pas je dois placer l'abonnement à cette événement.

            Pourrais-tu passer encore un peu de temps pour aider un ignorant...:( ce serait vraiment sympa

            Merci

            • Partager sur Facebook
            • Partager sur Twitter
              7 août 2018 à 13:34:51

              En WPF, quand tu fais un binding sur une propriété, le moteur interne à WPF va s'abonner à un événement : PropertyChanged. Cet événement est proposé par l'interface INotifyPropertyChanged. Du coup, ça devient facile de faire quelque chose comme ça :

              Object unObjet = QuelqueChoseQuiFourniUnObjet;
              
              if(unObjet is INotifyPropertyChanged) {
                ((INotifyPropertyChanged)unObjet).PropertyChanged += UnHandlerSurPropertyChanged;
              }
              
              //Ailleurs dans le code :
              
              private void UnHandlerSurPropertyChanged(Object sender, PropertyChangedEventArgs e) {
                 //sender contient l'instance de l'objet qui indique qu'une de ses propriété à changé
                 //e contient comme seul propriété, le nom de la propriété changée.
                 //Dans le moteur WPF, ça va extraire la nouvelle valeur par reflexion, en utilisant sender et le nom de propriété.
              }

              C'est très important de comprendre cette notion d'instance à ce niveau là.

              Dans une collection d'élément, il y a potentiellement 3 sources de modification possible :

              • 1) L'instance de la collection elle même. Quand tu fais "ItemEntree = new ObservableCollection<>()", tu changes l'instance de ta collection.
              • 2) Le contenu de la collection. Quand tu fais "ItemEntree.Add(new CollectionEntree())", tu utilises la méthode d'instance "Add" pour modifier le contenu de la collection. Cette modification sera un ajout et l'élément ajouté sera "new CollectionEntree()".
              • 3) Le contenu d'un des éléments de la collection. Quand tu fais "ItemEntree[0].ValidationEntree = true", tu modifie la propriété "ValidationEntree" de l'instance d'un objet qui se trouve à la position 0 de ta collection.

              Quand tu utilises un tel système, le code XAML est très proche de cette hirérachie :

              <ItemsControl ItemsSource="{Binding ItemEntree}"><!-- Niveau 1 : On se lie aux changement d'instance de ItemEntree -->
                 <!-- Niveau 2 est réalisé par un composant interne à ItemsControl, non définissable en XAML mais accessible via la propriété ItemsContainerGenerator -->
                 <ItemsControl.ItemTemplate>
                    <DataTemplate>
                       <!-- Niveau 3 : Pour chaque élément présent dans ta collection, ce DataTemplate sera instancié. Son DataContext sera égal à l'instance de l'élément de ta collection. Le Binding se fait donc sur une 
              instance d'un CollectionEntree, répété quant de fois qu'il y a d'instance dans ta collection. --> <TextBlock Text="{Binding .}"/> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl>


              Pour le niveau 2, une DataGrid ne se contente pas de faire que de la restitution de données mais peut aussi (voir mon post plus haut) te permettre de modifier cette collection source quand les conditions sont remplies (voir plus haut aussi).

              Autrement dit : Dans ton code métier, pour surveiller les changements réalisés par la DG sur ta collection source, il faut faire comme la DG elle même, s'abonner à l'événement CollectionChanged et réagir en fonction du type de modification réalisé.

              public class UserControlEntreeViewModel : ViewModelBase
              {
              
              	#region Constructeur
              	public UserControlEntreeViewModel()
              	{
              		//Dans le constructeur, de quoi j'ai besoin? De l'instance de itemEntree, au moins.
              		//Sauf que si je laisse ce code tel quel, je vais avoir des événements catchés, pas voulu.
              		//SetSourceEntree();
              		
              		//Je transforme un peu pour matcher à mes besoins
              		
              		GestionContext BddGestion = new GestionContext(NomBase);//Je me connecte à la BdD
              		
              		//Si tu fais du LINQ, pas besoin de compter d'abord, puis itérer pour convertir.
              		//Linq-To-EF est capable de "deviner" la requête qui permettra de fabriquer ton objet terminal directement
              		//pourvu que cette construction se limite à de l'assignation.
              		IEnumerable<CollectionEntree> entrees = from c in BddGestion.Entrees
              		                                        select new CollectionEntree { 
              													ValidationEntree = c.Validation, 
              													OperationEntree = c.Operation, 
              													CreditEntree = c.Credit 
              												};
              		//A ce stade, la requête n'est pas encore exécutée. J'ai juste fabriqué une requête Linq-To-EF
              		//dans laquelle j'indique qui je requête et ce que je fais des éléments requêtés.
              		//La requête ne sera exécutée que lorsque je commencerais à itérer dessus.
              		
              		//C'est exactement ce qui est fait dans la construction ci-dessous.
              		ObservableCollection<CollectionEntree> collection = new ObservableCollection<CollectionEntree>(entrees);
              		
              		//Je n'ai pas d'autres opération spéciale à mener sur cet objet collection.
              		//Note cependant que dans la ligne du dessous, j'utilise le setter de la propriété, défini plus bas
              		//au lieu de passer par une assignation du champs privé, comme ce qui était fait avant
              		this.ItemEntree = collection;
              		
              		//En fin de construction, tout est OP :
              		//	- La collection stockée dans itemEntree est remplie avec la BdD.
              		//	- Elle est exposée en public via la propriété ItemEntree.
              		//  - Toute modification ultérieure de cette collection sera intercepté et traité dans la méthode plus bas.
              	}
              	#endregion
              
              	#region Champs
              	//C'est pour ça que j'aime pas ces sucres syntaxique apportés par les versions ultérieures de C#.
              	//Ce type de syntaxe ne te permet pas de comprendre facilement qui fait quoi et quand ça le fait.
              	//private ObservableCollection<CollectionEntree> itemEntree = new ObservableCollection<CollectionEntree>();
              	//Du coup, on va rester sur un schéma plus long mais plus simple à comprendre pour gérer ses variables : Déclaration, assignation
              	private ObservableCollection<CollectionEntree> itemEntree;
              	private CollectionEntree selectEntree;
              	
              	#endregion
              
              	#region Variables
              
              	// Nom de la base de données
              	public string NomBase="Gestion.mdf";
              
              	#endregion
              
              	#region Getter et setter pour les bases de données
              
              	public ObservableCollection<CollectionEntree> ItemEntree
              	{
              		set
              		{
              			//Avant de changer quoique ce soit, je vérifie si je n'ai pas déjà une collection
              			//Si c'est le cas, je me désabonne de son événement pour éviter des notifications
              			//indésirable et aussi, pour éviter les fuites mémoire.
              			if(itemEntree != null)
              			{
              				itemEntree.CollectionChanged -= this.OnItemEntreeChanged;
              			}
              			itemEntree = value;//Je conserve l'instance indiquée dans mon champs privé.
              			if(itemEntree != null) //Si c'est null, je n'ai rien à surveiller
              			{
              				//Si ce n'est pas null, je surveille les changements de niveau 2.
              				itemEntree.CollectionChanged += this.OnItemEntreeChanged;
              			}
              			RaisePropertyChanged("ItemEntree");//Et pour finir, je notifie du changement de niveau 1 : Changement d'instance de collection.
              		}
              		get
              		{
              			return itemEntree;
              		}
              	}
              
              	#endregion
              
              	private void OnItemEntreeChanged(Object sender, NotifyCollectionChangedEventArgs e)
              	{
              		//Faire des trucs ici, pour réagir au changement de niveau 2 : Changement de contenu de la collection.
              		//ET voir la doc pour + d'infos : https://docs.microsoft.com/en-us/dotnet/api/system.collections.specialized.inotifycollectionchanged?view=netframework-4.7.2
              	}
              	
              	//#region Affichage des entrées
              	 
              	//Voir commentaire du constructeur
              	//private void SetSourceEntree()
              	//{
              	//	GestionContext BddGestion = new GestionContext(NomBase);
              	//	int ComptEntree = BddGestion.Entrees.Count<Entree>();
                  //
              	//	var query = (from c in BddGestion.Entrees select c).ToList();
                  //
              	//	for (int i = 0; i < ComptEntree; ++i)
              	//	{
              	//		ItemEntree.Add(new CollectionEntree { ValidationEntree = (query[i].Validation), OperationEntree = query[i].Operation, CreditEntree = query[i].Credit });
              	//	}
                  //
              	//}
              
              	//#endregion
              
              }



              -
              Edité par Nisnor 7 août 2018 à 13:36:51

              • Partager sur Facebook
              • Partager sur Twitter
                7 août 2018 à 14:56:17

                Un grand merci à toi d'avoir passé du temps pour me fournir autant d'explications, c'est super. 

                Je décortique tout ce que tu m'as envoyé mais en première lecture cela me parait plus clair que toutes mes lectures sur internet.

                Je n'ai jamais eu de cours d'info et j'ai tout appris seul. C'est une de mes passion. Jusqu'à maintenant j'y arrivais mais avec c# les choses sont assez compliquées et difficiles à saisir. Peut être est-ce l'age:-°. En plus je suis très mauvais en anglais, un vrai boulet...

                Connais tu par hasard un bon site pour avancer en MVVM et c#?

                Je pense que je te recontacterai si j'ai des problèmes et si ça ne te déranges pas.

                Encore mille merci.

                • Partager sur Facebook
                • Partager sur Twitter
                  7 août 2018 à 17:58:55

                  De bon site, non pas spécialement.

                  AMHA, seule l'expérience sera réellement valable. Les sites qui parlent de MVVM parlent souvent dans des cas spécifiques (des applications particulières ou soumis à des framework particulier comme MVVM Light). Ces même sites peuvent faire une interprétation de cette architecture qui peut être vrai dans certains cas, mais fausse dans d'autres. Le mieux, c'est encore de se forger sa propre XP et de savoir adapter les façons de faire aux problèmes rencontrés/exposés; de ne surtout pas se dire "Ah, j'ai lu ça sur tel billet de blog, j'ai testé, ça marche, donc c'est vrai partout et tout le temps".

                  • Partager sur Facebook
                  • Partager sur Twitter
                    7 août 2018 à 23:08:57

                    Je vais continuer à essayer de programmer mais de l'aide est parfois nécessaire.

                    Je reviens sur la classe ViewModel que tu m'as fait parvenir. Je ne comprends pas pourquoi tu passes par observablecollection collection (ligne 29) pour ensuite utiliser observablecollection ItemEntree (ligne 34). Ne peut on pas écrire à la ligne 29:

                    ObservableCollection<CollectionEntree> itemEntree = new ObservableCollection<CollectionEntree>(entrees);

                    Pour ce qui concerne la vue (je ne suis pas plus doué en Xaml) où dois-je placer le bout de programme que tu me donnes? Je ne comprends pas que tu n'utilises pas le DataGrid et ce que vient faire le TextBlock.

                    Pour le reste, je me plonge dans différents essais.

                    A+

                    • Partager sur Facebook
                    • Partager sur Twitter
                      8 août 2018 à 9:01:52

                      berduf a écrit:

                      Je reviens sur la classe ViewModel que tu m'as fait parvenir. Je ne comprends pas pourquoi tu passes par observablecollection collection (ligne 29) pour ensuite utiliser observablecollection ItemEntree (ligne 34). Ne peut on pas écrire à la ligne 29:

                      ObservableCollection<CollectionEntree> itemEntree = new ObservableCollection<CollectionEntree>(entrees);

                      Quand tu écris "private Observable[...] itemEntree;", directement à l'intérieur d'une classe, il s'agit de la déclaration d'un champs (ou d'une variable appelle ça comme tu veux) d'instance (ce qui signifie que, pour que cette variable "existe en mémoire", il faut qu'une instance de la classe qui la contient ait été créée auparavant. A chaque instance de classé créé sera associé un nouvel "espace mémoire" contenant ta variable) privé (ce qui veut dire que seul, d'autres membres de ta classe peuvent accéder à cette variable pour la lire ou y écrire, personne d'autre).

                      Le constructeur d'une classe (ici, simplement déclaré avec "public UserControlEntreeViewModel()" est un membre publique (ce qui veut dire que n'importe qui peut s'en servir, ta classe ou un autre) de ta classe UserControlEntreeViewModel un peu particulier, puisque c'est lui qui pourra contenir un bout de code qui sera exécuté quant, ailleurs, dans ton programme, tu feras "new UserControlEntreeViewModel()". Vu qu'il s'agit d'un membre de ta classe, il peut logiquement accéder à ton champs privé "itemEntree".

                      La propriété "ItemEntree" déclarée par "public Observable[...] ItemEntree { }" est aussi un membre public de ta classe UserControlEntreeViewModel. Tout comme le constructeur, il pourra avoir accès à ton champs d'instance privé. Ca peut aussi être appelé "accesseur", puisque dedans, tu peux définir 2 blocs de code : get et set, qui sera respectivement appelés quand tu feras "var ggg = uneInstanceUserControlEntree.ItemEntree;" et "uneInstanceUserControlEntree.ItemEntree = unTrucDeTypeObservable[...]".

                      En WPF, tu ne peux réaliser tes bindings que sur des propriétés. Rien d'autre.

                      Si tu avais juste écris "itemEntree = new Observable[...]", tu aurais définis une nouvelle valeur, placée dans ton champs "itemEntree", mais à aucun moment, tu n'aurais indiqué à la couche WPF du dessus que cette valeur à changé. Il t'aurais fallu rajouter derrière ton "RaisePropertyChanged("ItemEntree")"...Sauf que toute cette mécanique est déjà faite pour toi dans le set de ta propriété ItemEntree. Donc, plutôt que de dupliquer du code, autant passer exclusivement par ton accesseur quand tu veux changer la valeur de ton champs itemEntree. C'est encore plus vrai que là, dans ce cas précis, quand la valeur du champs itemEntree change, il n'y a pas QUE un RaiseProperty à faire :) .

                      Après, si c'est juste le nom de la variable locale (ce n'est pas un champs d'instance) utilisée ("collection" au lieu de "itemEntree") qui te chiffonne, oui, tu aurais tout aussi bien pu l'appeler itemEntree au lieu de collection bien sûr ^^ . Personnellement, je n'aurais pas nommé cette variable locale de la même façon qu'un champs privé (même si c'est supporté), parce qu'à la lecture du code, c'est moins facile de comprendre dans qui on tape (le champ d'instance? Ou la variable locale?)

                      berduf a écrit:

                      Pour ce qui concerne la vue (je ne suis pas plus doué en Xaml) où dois-je placer le bout de programme que tu me donnes? Je ne comprends pas que tu n'utilises pas le DataGrid et ce que vient faire le TextBlock.

                      C'était juste un exemple pour faire le rapprochement, sur ces histoires de niveau de notification, avec l'explication qui précédait...Ce n'est pas à utiliser dans ton programme.

                      Dans une DataGrid, le "DataTemplate" de ligne est en fait "fabriqué" à partir des Columns que tu as renseigné.

                      -
                      Edité par Nisnor 8 août 2018 à 9:43:03

                      • Partager sur Facebook
                      • Partager sur Twitter
                        8 août 2018 à 9:51:28

                        Beaucoup d'infos c'est super mais il faut que je reprenne ça à tête reposée. Mon premier problème en c#, je crois, c'est le vocabulaire. J'ai du mal a assimiler toutes les dénominations et je m'y perds.

                        Si je peux me permettre encore une question:ange: Ce que j'aimerais me paraissait simple mais...

                        Je voudrais, lorsqu'un utilisateur rempli le DataGrid et appui sur la touche ENTER, avoir la possibilité de mettre a jour la base de donnée en ajoutant une entrée si elle est nouvelle ou en remplaçant une entrée si l'utilisateur à changé des valeurs. Tout cela sans avoir à utiliser des boutons comme dans les exemples présentés sur le net.

                        Si tu as encore un peu de temps et de courage pour te pencher sur mon cas...

                        Merci encore car c'est génial que tu me donnes autant d'explication. 

                        • Partager sur Facebook
                        • Partager sur Twitter
                          9 août 2018 à 10:17:47

                          Je ne ferais pas ce code à ta place ^^ .

                          Pour le coup de l'appuie sur la touche entrée, je t'invite à utiliser le debugger, placer des points d'arrêt un peu partout dans ton code pour explorer qui fait quoi et quand ça le fait.

                          Du reste, pour ce que tu veux faire...il faudra pas mal ruser, parce que la DataGrid a un fonctionnement un peu particulier. Quand tu ajoutes une nouvelle ligne dans la DG, ça ajoute un objet dans ta collection. Si l'ajout est annulé, ce même objet est supprimé de la collection.

                          En temps normal, ça ne pose pas trop de problèmes...sauf quand les modifications apportées à ladite collection sont "instantanément" sauvées quelque part...dans une BdD par exemple ^^ . En plus des problèmes de ralentissement, ça peut avoir des effets métier indésirable (si tu as des incréments de numéro de séquence par exemple, il faut prévoir le coup et pouvoir faire un rollback de ces incréments.)

                          • Partager sur Facebook
                          • Partager sur Twitter
                            9 août 2018 à 12:44:01

                            Je ne pensais absolument pas que tu allais faire du code pour moi ce n'est pas du tout mon intention et d'ailleurs ça ne permettrait pas d'avancer. Je veux juste des pistes. Pour l'utilisation du debugger et les points d'arrêt je vais le faire.

                            J'ai pensé utiliser DataGridRow.unselected mais il faut une méthode donc pour le binding c'est raté à moins qu'il y ait une technique. L'idée est elle bonne?

                            Une  autre idée consisterait à placer un bouton "enregistrer" dans un autre usercontrol. Tu m'as dit que la collection ItemEntree est accessible à partir de n'importe quelle classe. Donc je pense qu'il n'y a pas de problème. Par contre il va falloir que j'efface la table de la BD avant d'enregistrer les données (en faisant ça j'enregistre les modifications). Qu'en penses-tu? Et si cette technique est valable comment vide-t-on une table d'une BD.

                            Pour ce qui est du rollback je pense qu'il s'agit de l'annulation des dernières actions effectuées. Je me trompe?

                            Tu vois pas de code juste de l'aide si bien sur ça ne te déranges pas.

                            Merci.

                            • Partager sur Facebook
                            • Partager sur Twitter
                              9 août 2018 à 12:58:45

                              berduf a écrit:

                              J'ai pensé utiliser DataGridRow.unselected mais il faut une méthode donc pour le binding c'est raté à moins qu'il y ait une technique. L'idée est elle bonne?

                              Juste pour tester, tente de suivre les événements tels qu'ils te sont envoyés par la DG. Pas besoin de code additionnel pour ça ou de gestion d'événement sur la DG, tout peut se faire par binding. Rappelles toi des 3 niveaux de modifications; Tu en as au moins 2 qui te permettraient de faire ce que tu veux.

                              Il y a aussi une interface que tu peux explorer : IEditableObject. Tu implémentes ça sur CollectionEntree et tu vois à quels moment sont appelés les méthodes à implémenter. Tu as aussi ISupportInitialize qui pourrait être utile.

                              C'est pas le plus optimisé...mais ça marchera.

                              berduf a écrit:

                              Une  autre idée consisterait à placer un bouton "enregistrer" dans un autre usercontrol. Tu m'as dit que la collection ItemEntree est accessible à partir de n'importe quelle classe. Donc je pense qu'il n'y a pas de problème. Par contre il va falloir que j'efface la table de la BD avant d'enregistrer les données (en faisant ça j'enregistre les modifications). Qu'en penses-tu? Et si cette technique est valable comment vide-t-on une table d'une BD.

                              Je ne suis pas sûr de bien saisir.

                              Considère qu'un ordinateur, c'est une sorte de secrétaire qui fait du travail répétitif à une vitesse hallucinante et avec un taux d'erreur (quasi-)nul (pour peu que les instructions qu'on lui donne soient juste bien sûr).

                              Quand tu demandes à ta secrétaire d'ajouter une nouvelle fiche client dans le carnet clientèle, je doute que la logique première soit "Ok, je commence par copier toutes les fiches sur des nouvelles en incluant la nouvelle puis je jette toutes les anciennes et enfin de les range dans le même casier qu'avant".

                              C'est largement plus rapide de juste prendre une nouvelle feuille blanche, écrire les infos du client dessus et ranger cette feuille parmi les fiches cliente existante.

                              Avec un ordinateur c'est pareil. Une BdD te permettra d'insérer de nouvelles lignes sans avoir à tout effacer d'abord puis tout recréer et sauvegarder l'ensemble.

                              berduf a écrit:

                              Pour ce qui est du rollback je pense qu'il s'agit de l'annulation des dernières actions effectuées. Je me trompe?

                              C'est ça. Mais si tu n'as pas de N° de séquence ou autre, tu n'as pas trop à te soucier de ce genre de considération.

                              -
                              Edité par Nisnor 9 août 2018 à 13:14:33

                              • Partager sur Facebook
                              • Partager sur Twitter
                                9 août 2018 à 15:32:33

                                je suis d'accord avec toi pour le travail de l'ordi.

                                J'ai essayer de travailler directement avec le model de CollectionEntree et ça fonctionne bien pour les nouvelles entrées dans le DG. Je ne sais pas si c'est une bonne technique.

                                Mon problème est pour les données déjà présentes mais qui ont été modifiées et pour celles qui ont été supprimées c'est peut être moins simple non?

                                J'avoue que je croyais avoir commencé à comprendre quelque chose à c# mais je crois que je me suis mis le doigt dans l'oeil

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  9 août 2018 à 16:48:12

                                  Je ne connais pas bien WPF mais j'ai l'impression que ton problème de mise à jour serait totalement résolu en utilisant un DataSet comme stockage "Model" du MVVM.

                                  Un simple DataAdapter permettrait de faire tout le boulot "CRUD" dans la base de données en un seul appel à "Save".

                                  L'usage d'un ORM comme Entity Framework peut aussi faire ce travail de "secrétaire".

                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                  Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                                    9 août 2018 à 17:06:06

                                    Merci Bacelar de me répondre.

                                    Saches tout d'abord que tu as à faire à un débutant donc excuses moi pour les erreurs de langage. J'utilise EF mais je suis bloqué. Comment faire une sauvegarde, un remplacement, ou une suppression. Je cherche sur le NET et les réponses me paraissent toutes différentes et compliquées. 

                                    Que faut-il créer?

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      9 août 2018 à 17:31:20

                                      Avec EF, "SaveChanges" devrait faire le job, non ?

                                      http://www.entityframeworktutorial.net/crud-operation-in-connected-scenario-entity-framework.aspx

                                      -
                                      Edité par bacelar 9 août 2018 à 17:31:45

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                      Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                                        9 août 2018 à 19:11:52

                                        Merci Bacelar, en première lecture tu as raison ça a l'air de faire le travail et d'être assez simple. J'eassaie le plus rapidement possible.

                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          9 août 2018 à 20:21:22

                                          E(entity)F(ramework) est un O(bject)R(elationnal)M(apper) assez puissant et simple à utiliser.

                                          Utilise le de façon naturelle, sans chercher midi à quatorze heure et tu obtiens des résultats déjà très satisfaisant.

                                          Tu veux lire des données de la BdD? => tonContext.MesDonnees.

                                          Tu veux filtrer ces données? Conjointement avec Linq-To-Entity, ça donnerait "tonContext.MesDonnees.Where(d => [UnPredicatOu'd'EstUneLigneDeLaBdD])" ou "from d in tonContext.MesDonnees where [UnPredicatOu'd'EstUneLigneDeLaBdD] select d".

                                          Je ne vais pas énumérer toutes les possibilités de lecture. Dans son ensemble : Ce qui faisable avec une base de données l'est aussi avec Linq-To-Entity & EF (filtrage, regroupement, jointure, tri, select de colonne spécifique, certains agrégateurs comme count, min, max ...).

                                          Tu veux ajouter une donnée? tonContext.MesDonnees.Add(unObjetDuBonType); suivi effectivement d'un SaveChanges pour persister les modifications.

                                          Tu veux supprimer une donnée? tonContext.MesDonnees.Remove(unObjetDuBonType); suivi effectivement d'un SaveChanges pour persister les modifications.

                                          Tu veux mettre à jour une donnée? unObjetDuBonType.TaPropriete = [NouvelleValeur]; suivi effectivement d'un SaveChanges pour persister les modifications.

                                          Tout simplement :) .

                                          Edit : Ca va encore plus vite si tu expose directement les instances d'objet fournis par EF à des bindings WPF puisqu'il me semble que, par défaut, ces objets implémentent déjà les interfaces nécessaire à WPF pour réaliser ses bindings. Tu n'as plus aucun code à écrire pour faire un C(reate)R(ead)U(pdate)D(elete) complet.

                                          -
                                          Edité par Nisnor 9 août 2018 à 20:25:28

                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            9 août 2018 à 23:49:10

                                            Après essais l'ajout et la modification de valeurs fonctionnent parfaitement. Merci à vous deux vous avez été d'un grand secours.

                                            Je vais tenter la suppression de ligne qui me parait un peu plus compliqué.

                                            -
                                            Edité par berduf 10 août 2018 à 11:25:33

                                            • Partager sur Facebook
                                            • Partager sur Twitter

                                            Utilisation d'un DataGrid

                                            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                            • Editeur
                                            • Markdown