« WinForms » : différence entre les versions
Aucun résumé des modifications |
|||
Ligne 1 : | Ligne 1 : | ||
=Événements Initialize, Load et Activate= | [[Category:CSharp]] | ||
*Initialize: appelé lors de la création de la Form | = Événements Initialize, Load et Activate = | ||
*Load: appelé lorsque la Form est chargée en mémoire | * Initialize: appelé lors de la création de la Form | ||
*Activate: appelé à chaque fois que la Form devient la fenêtre active | * Load: appelé lorsque la Form est chargée en mémoire | ||
* Activate: appelé à chaque fois que la Form devient la fenêtre active | |||
[http://support.microsoft.com/kb/138819/en-us?fr=1 MSDN] | [http://support.microsoft.com/kb/138819/en-us?fr=1 MSDN] | ||
=Dock et superposition= | = Dock et superposition = | ||
ElementA docké en Fill et ElementB docké en bottom.<br/> | ElementA docké en Fill et ElementB docké en bottom.<br/> | ||
ElementB se retrouve par dessous ElementA et masque le bas d'ElementA.<br/> | ElementB se retrouve par dessous ElementA et masque le bas d'ElementA.<br/> | ||
<u>Solutions:</u> | <u>Solutions:</u> | ||
*Right click sur ElementA and select “Bring to Front” | * Right click sur ElementA and select “Bring to Front” | ||
*Ajouter ce code: | * Ajouter ce code: | ||
<kode lang="csharp"> | |||
private void Form_Load(object sender, EventArgs e) | private void Form_Load(object sender, EventArgs e) | ||
{ | { | ||
ElementA.BringToFront(); | ElementA.BringToFront(); | ||
</ | </kode> | ||
=Centrer un Label= | = Centrer un Label = | ||
AutoSize → False<br/> | AutoSize → False<br/> | ||
TextAlign → MiddleCenter | TextAlign → MiddleCenter | ||
=Simuler une entrée au clavier= | = Simuler une entrée au clavier = | ||
[http://msdn.microsoft.com/en-us/library/system.windows.forms.sendkeys.send.aspx] | [http://msdn.microsoft.com/en-us/library/system.windows.forms.sendkeys.send.aspx] | ||
<kode lang="csharp"> | |||
< | |||
SendKeys.Send("{Tab}"); | SendKeys.Send("{Tab}"); | ||
</ | </kode> | ||
=Menu Contextuel= | = Menu Contextuel = | ||
Ajouter un ContextMenuStrip → drag-drop depuis la boite à outils.<br/> | Ajouter un ContextMenuStrip → drag-drop depuis la boite à outils.<br/> | ||
Lier le CMS à un élément graphique → via la propriété ContextMenuStrip<br/> | Lier le CMS à un élément graphique → via la propriété ContextMenuStrip<br/> | ||
Ligne 40 : | Ligne 36 : | ||
Lier un événement à la sélection d'un menu → sélectionner l'élément du menu dans la vue du designer et ajouter un handler sur l'évènement Click<br/> | Lier un événement à la sélection d'un menu → sélectionner l'élément du menu dans la vue du designer et ajouter un handler sur l'évènement Click<br/> | ||
La propriété ShotcutKeys permet d'associer un raccourci clavier à un élément du menu. | La propriété ShotcutKeys permet d'associer un raccourci clavier à un élément du menu. | ||
<kode lang="csharp"> | |||
< | |||
// récupération du control contenant le menu contextuel | // récupération du control contenant le menu contextuel | ||
private void tsmi_Click(object sender, EventArgs e) | private void tsmi_Click(object sender, EventArgs e) | ||
Ligne 55 : | Ligne 49 : | ||
var control = (DataGridView)ActiveControl; | var control = (DataGridView)ActiveControl; | ||
} | } | ||
</ | </kode> | ||
=Form= | = Form = | ||
==Propriétés intéressantes== | == Propriétés intéressantes == | ||
*ControlBox → Affiche/cache l'icône en haut à gauche ainsi que les boutons réduire, grandir et fermer en haut à droite. | * ControlBox → Affiche/cache l'icône en haut à gauche ainsi que les boutons réduire, grandir et fermer en haut à droite. | ||
==Interdire le redimensionnement== | == Interdire le redimensionnement == | ||
*Propriété FormBorderStyle → FixedSingle | * Propriété FormBorderStyle → FixedSingle | ||
*Propriété MaximizeBox → false | * Propriété MaximizeBox → false | ||
==AutoScaleMode== | == AutoScaleMode == | ||
Détermine le comportement du formulaire lors d'un changement de la résolution (dpi) ou de la police (font).<br/> | Détermine le comportement du formulaire lors d'un changement de la résolution (dpi) ou de la police (font).<br/> | ||
Choisir l'AutoScaleMode du formulaire principal, les sous formulaires peuvent hériter de l'AutoScaleMode de leur parent (Inherit).<br/> | Choisir l'AutoScaleMode du formulaire principal, les sous formulaires peuvent hériter de l'AutoScaleMode de leur parent (Inherit).<br/> | ||
La valeur par défaut est font, cela peut causer des problèmes d'affichage. Préférer ''dpi'' ou ''none''.<br/> | La valeur par défaut est font, cela peut causer des problèmes d'affichage. Préférer ''dpi'' ou ''none''.<br/> | ||
==Boutons OK et CANCEL dans une Form== | == Boutons OK et CANCEL dans une Form == | ||
Il faut affecter respectivement les valeurs OK et CANCEL à la propriété DialogResult des boutons. | Il faut affecter respectivement les valeurs OK et CANCEL à la propriété DialogResult des boutons. | ||
<kode lang="csharp"> | |||
< | |||
NewForm form = new NewForm(); | NewForm form = new NewForm(); | ||
if (form.ShowDialog(this) == DialogResult.OK) // fenetre modale | if (form.ShowDialog(this) == DialogResult.OK) // fenetre modale | ||
{ ... } | { ... } | ||
form.Dispose(); | form.Dispose(); | ||
</ | </kode> | ||
==Thread graphique et thread de calcul== | == Thread graphique et thread de calcul == | ||
Pour que le formulaire soit toujours visible et interactif, il est nécessaire de lancer un second thread qui s'occupera des calcul pendant que le premier thread (thread graphique) s'occupera de l'affichage du formulaire.<br/> | Pour que le formulaire soit toujours visible et interactif, il est nécessaire de lancer un second thread qui s'occupera des calcul pendant que le premier thread (thread graphique) s'occupera de l'affichage du formulaire.<br/> | ||
Attention, le thread de calcul ne peut pas modifier directement les éléments du formulaire car ils appartiennent à un autre thread. Il faut donc utiliser les callback. | Attention, le thread de calcul ne peut pas modifier directement les éléments du formulaire car ils appartiennent à un autre thread. Il faut donc utiliser les callback. | ||
<kode lang="csharp"> | |||
< | |||
Thread thread = new Thread(new ThreadStart(delegate() | Thread thread = new Thread(new ThreadStart(delegate() | ||
{ // code qui doit être réalisé par le thread de calcul })); | { // code qui doit être réalisé par le thread de calcul })); | ||
Ligne 98 : | Ligne 86 : | ||
thread.Start(); | thread.Start(); | ||
</ | </kode> | ||
==Callback et thread-safe== | == Callback et thread-safe == | ||
Fonction de rappel, permet de passer un pointeur sur fonction en paramètre (délégué).<br/> | Fonction de rappel, permet de passer un pointeur sur fonction en paramètre (délégué).<br/> | ||
Dans cet exemple, c’est une méthode qui s’appelle elle-même de manière asynchrone via un délégué. | Dans cet exemple, c’est une méthode qui s’appelle elle-même de manière asynchrone via un délégué. | ||
<kode lang="csharp"> | |||
< | |||
public class MainForm : Form | public class MainForm : Form | ||
{ | { | ||
Ligne 136 : | Ligne 121 : | ||
} | } | ||
} | } | ||
</ | </kode> | ||
[http://msdn.microsoft.com/fr-fr/library/ms171728.aspx] | [http://msdn.microsoft.com/fr-fr/library/ms171728.aspx] | ||
=DataGridView= | = DataGridView = | ||
==Coller des données provenant d'Excel== | == Coller des données provenant d'Excel == | ||
<kode lang="csharp"> | |||
< | |||
// récupération du contenu du presse papier | // récupération du contenu du presse papier | ||
string clipboardText = Clipboard.GetText(); | string clipboardText = Clipboard.GetText(); | ||
Ligne 197 : | Ligne 178 : | ||
// cette ligne peut générer une exception si la cellule est hidden | // cette ligne peut générer une exception si la cellule est hidden | ||
dgv.CurrentCell = dgv[newColumnIndex, dgv.CurrentCell.RowIndex]; | dgv.CurrentCell = dgv[newColumnIndex, dgv.CurrentCell.RowIndex]; | ||
</ | </kode> | ||
==EditMode== | == EditMode == | ||
<u>EditOnKeyStrokeOrF2 :</u> Mode par défaut, il faut double-cliquer sur une cellule pour l’éditer.<br/> | <u>EditOnKeyStrokeOrF2 :</u> Mode par défaut, il faut double-cliquer sur une cellule pour l’éditer.<br/> | ||
<u>EditOnEnter :</u> Dans ce mode il suffit de cliquer sur la cellule pour l’éditer. Par contre un clique sur le header d’une ligne édite la première cellule, ce qui empêche de supprimer la ligne.<br/> | <u>EditOnEnter :</u> Dans ce mode il suffit de cliquer sur la cellule pour l’éditer. Par contre un clique sur le header d’une ligne édite la première cellule, ce qui empêche de supprimer la ligne.<br/> | ||
EditOnEnter et suppression de ligne : | EditOnEnter et suppression de ligne : | ||
<kode lang="csharp"> | |||
< | |||
private void DGV_MouseClick(object sender, MouseEventArgs e) | private void DGV_MouseClick(object sender, MouseEventArgs e) | ||
{ | { | ||
Ligne 221 : | Ligne 199 : | ||
} | } | ||
} | } | ||
</ | </kode> | ||
==Tester les données des cellules dès leurs saisies== | == Tester les données des cellules dès leurs saisies == | ||
La validation bloque l’utilisateur tant qu’il n’a pas saisie de valeur valide et affiche un message d’erreur. | La validation bloque l’utilisateur tant qu’il n’a pas saisie de valeur valide et affiche un message d’erreur. | ||
<kode lang="csharp"> | |||
< | |||
private void dataGridView_CellValidating(object sender, | private void dataGridView_CellValidating(object sender, | ||
DataGridViewCellValidatingEventArgs e) | DataGridViewCellValidatingEventArgs e) | ||
Ligne 248 : | Ligne 223 : | ||
((DataGridView)sender).Rows[e.RowIndex].ErrorText = String.Empty; | ((DataGridView)sender).Rows[e.RowIndex].ErrorText = String.Empty; | ||
} | } | ||
</ | </kode> | ||
=ComboBox= | = ComboBox = | ||
L'événement SelectionChangeCommitted, à la différence des événements SelectedIndexChanged ou SelectedValueChanged, ne se produit que lorsque l'utilisateur et non le programme modifie la sélection de la liste déroulante. | L'événement SelectionChangeCommitted, à la différence des événements SelectedIndexChanged ou SelectedValueChanged, ne se produit que lorsque l'utilisateur et non le programme modifie la sélection de la liste déroulante. | ||
=Pop-up message= | = Pop-up message = | ||
<kode lang="csharp"> | |||
< | |||
MessageBox.Show("message", "titre", MessageBoxButtons.OKCancel, MessageBoxIcon.Error); | MessageBox.Show("message", "titre", MessageBoxButtons.OKCancel, MessageBoxIcon.Error); | ||
</ | </kode> | ||
=Progress Bar et Timer= | = Progress Bar et Timer = | ||
<kode lang="csharp"> | |||
< | |||
public partial class Form1 : Form | public partial class Form1 : Form | ||
{ | { | ||
Ligne 322 : | Ligne 289 : | ||
} | } | ||
} | } | ||
</ | </kode> | ||
Dernière version du 12 avril 2020 à 22:06
Événements Initialize, Load et Activate
- Initialize: appelé lors de la création de la Form
- Load: appelé lorsque la Form est chargée en mémoire
- Activate: appelé à chaque fois que la Form devient la fenêtre active
Dock et superposition
ElementA docké en Fill et ElementB docké en bottom.
ElementB se retrouve par dessous ElementA et masque le bas d'ElementA.
Solutions:
- Right click sur ElementA and select “Bring to Front”
- Ajouter ce code:
private void Form_Load(object sender, EventArgs e) { ElementA.BringToFront(); |
Centrer un Label
AutoSize → False
TextAlign → MiddleCenter
Simuler une entrée au clavier
SendKeys.Send("{Tab}"); |
Menu Contextuel
Ajouter un ContextMenuStrip → drag-drop depuis la boite à outils.
Lier le CMS à un élément graphique → via la propriété ContextMenuStrip
Ajouter des éléments au menu → via la propriété Items ou via la petite flèches au dessus du CMS dans le bas de la vue du designer
Lier un événement à la sélection d'un menu → sélectionner l'élément du menu dans la vue du designer et ajouter un handler sur l'évènement Click
La propriété ShotcutKeys permet d'associer un raccourci clavier à un élément du menu.
// récupération du control contenant le menu contextuel private void tsmi_Click(object sender, EventArgs e) { var menu = (ToolStripDropDownItem)sender; var strip = (ContextMenuStrip)menu.Owner; // SourceControl est null lors de l'utilisation des raccourcis clavier var control = (DataGridView)strip.SourceControl; // Dans ce cas et si le control n'est pas dans un SplitContainer var control = (DataGridView)ActiveControl; } |
Form
Propriétés intéressantes
- ControlBox → Affiche/cache l'icône en haut à gauche ainsi que les boutons réduire, grandir et fermer en haut à droite.
Interdire le redimensionnement
- Propriété FormBorderStyle → FixedSingle
- Propriété MaximizeBox → false
AutoScaleMode
Détermine le comportement du formulaire lors d'un changement de la résolution (dpi) ou de la police (font).
Choisir l'AutoScaleMode du formulaire principal, les sous formulaires peuvent hériter de l'AutoScaleMode de leur parent (Inherit).
La valeur par défaut est font, cela peut causer des problèmes d'affichage. Préférer dpi ou none.
Boutons OK et CANCEL dans une Form
Il faut affecter respectivement les valeurs OK et CANCEL à la propriété DialogResult des boutons.
NewForm form = new NewForm(); if (form.ShowDialog(this) == DialogResult.OK) // fenetre modale { ... } form.Dispose(); |
Thread graphique et thread de calcul
Pour que le formulaire soit toujours visible et interactif, il est nécessaire de lancer un second thread qui s'occupera des calcul pendant que le premier thread (thread graphique) s'occupera de l'affichage du formulaire.
Attention, le thread de calcul ne peut pas modifier directement les éléments du formulaire car ils appartiennent à un autre thread. Il faut donc utiliser les callback.
Thread thread = new Thread(new ThreadStart(delegate() { // code qui doit être réalisé par le thread de calcul })); // ou Thread thread = new Thread(methode); thread.Start(); |
Callback et thread-safe
Fonction de rappel, permet de passer un pointeur sur fonction en paramètre (délégué).
Dans cet exemple, c’est une méthode qui s’appelle elle-même de manière asynchrone via un délégué.
public class MainForm : Form { delegate void mainFormCallback(string text); private void button_Click(object sender, EventArgs e) { Thread thread = new Thread(new ThreadStart(delegate() { SetText("OK"); }); thread.Start(); } private void SetText (string text) { // InvokeRequired compares the thread ID of the // calling thread to the thread ID of the creating thread. // If these threads are different, it returns true. if (this.button.InvokeRequired) { // calls itself asynchronously mainFormCallback callback = new mainFormCallback(SetText); this.Invoke(callback, text); } else { button.Text = text; } } } |
DataGridView
Coller des données provenant d'Excel
// récupération du contenu du presse papier string clipboardText = Clipboard.GetText(); // séparation par lignes et suppression des lignes vides string[] clipboardLines = clipboardText.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); // séparation par cellules afin de connaitre le nombre d'éléments à coller var clipboardElements = new List<string>(); foreach (var line in clipboardLines) { clipboardElements.AddRange(line.Split('\t')); } // trie des éléments dans l'ordre croissant car les SelectedCells sont dans l'ordre de la sélection // si elle s'est faite de gauche à droite et/ou de haut en bas // les cellules sont en ordre décroissant d'index var orderedSelectedCells = new List<DataGridViewCell>(); foreach (DataGridViewCell cell in dataGridView1.SelectedCells) { orderedSelectedCells.Add(cell); } orderedSelectedCells.Sort((dgvc1, dgvc2) => { var rowCompare = dgvc1.RowIndex.CompareTo(dgvc2.RowIndex); if (rowCompare != 0) return rowCompare; else { return dgvc1.ColumnIndex.CompareTo(dgvc2.ColumnIndex); } }); // seulement si le nombre d'éléments à copier est <= à l'espace sélectionné pour la copie if (clipboardElements.Count <= orderedSelectedCells.Count) { for (int i = 0; i < clipboardElements.Count; i++) { orderedSelectedCells[i].Value = Convert.ChangeType(clipboardElements[i], orderedSelectedCells[i].ValueType); } } // si le mode d'édition est EditOnEnter, la dernière cellule collée est toujours en édition // et son contenu visuellement pas à jour. // pour corrigé ça on déplace le focus sur la cellule suivante ou sur la première int newColumnIndex = 0; if (dgv.CurrentCell.ColumnIndex + 1 <= dgv.Columns.Count) { newColumnIndex = dgv.CurrentCell.ColumnIndex + 1; } // cette ligne peut générer une exception si la cellule est hidden dgv.CurrentCell = dgv[newColumnIndex, dgv.CurrentCell.RowIndex]; |
EditMode
EditOnKeyStrokeOrF2 : Mode par défaut, il faut double-cliquer sur une cellule pour l’éditer.
EditOnEnter : Dans ce mode il suffit de cliquer sur la cellule pour l’éditer. Par contre un clique sur le header d’une ligne édite la première cellule, ce qui empêche de supprimer la ligne.
EditOnEnter et suppression de ligne :
private void DGV_MouseClick(object sender, MouseEventArgs e) { DataGridView.HitTestInfo hitInfo = this.DGV.HitTest(e.X, e.Y); if (hitInfo.Type == DataGridViewHitTestType.RowHeader) { this.DGV.EditMode = DataGridViewEditMode.EditOnKeystrokeOrF2; this.DGV.EndEdit(); } else { this.DGV.EditMode = DataGridViewEditMode.EditOnEnter; } } |
Tester les données des cellules dès leurs saisies
La validation bloque l’utilisateur tant qu’il n’a pas saisie de valeur valide et affiche un message d’erreur.
private void dataGridView_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) { DataGridView dgv = (DataGridView)sender; if (dgv.Columns[e.ColumnIndex] == "ColumnName") { if (string.IsNullOrEmpty(e.FormattedValue.ToString()) { dgv.Rows[e.RowIndex].ErrorText = "Cell must not be empty"; e.Cancel = true; } } } private void cduDataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e) { ((DataGridView)sender).Rows[e.RowIndex].ErrorText = String.Empty; } |
ComboBox
L'événement SelectionChangeCommitted, à la différence des événements SelectedIndexChanged ou SelectedValueChanged, ne se produit que lorsque l'utilisateur et non le programme modifie la sélection de la liste déroulante.
Pop-up message
MessageBox.Show("message", "titre", MessageBoxButtons.OKCancel, MessageBoxIcon.Error); |
Progress Bar et Timer
public partial class Form1 : Form { ToDO toDO; public Form1() { progressBar1.Minimum = 1; progressBar1.Maximum = 20; progressBar1.Value = 1; progressBar1.Step = 1; toDO = new ToDO(); toDO.ReportStatusUpdated += new ToDO.Delegate(toDO_ReportStatusUpdated); toDO.EndOfWork += new ToDO.Delegate(toDO_EndOfWork); } void toDO_EndOfWork() { button1.Text = "OK"; } void toDO_ReportStatusUpdated() { progressBar1.PerformStep(); } private void button1_Click(object sender, EventArgs e) { toDO.DoWork(); } } public class ToDO { public delegate void Delegate(); public event Delegate ReportStatusUpdated; public event Delegate EndOfWork; Timer timer; int count = 1; void timer_Tick(object sender, EventArgs e) { if (count++ > 19) WorkFinished(); else ReportStatusUpdated(); } private void WorkFinished() { timer.Enabled = false; EndOfWork(); } public void DoWork() { timer = new Timer(); timer.Interval = 1000; timer.Tick += new EventHandler(timer_Tick); timer.Enabled = true; } } |