TOC

This article is currently in the process of being translated into French (~56% done).

Dialogs:

Creating a custom input dialog

Dans les précédents articles, nous avons vu l'utilisation des boîtes de dialogues intégrées dans WPF ; cela étant, créer votre propre boîte de dialogue est presque aussi simple. En fait, vous devez simplement créer une fenêtre, y placer les contrôles souhaités et l'afficher.

Cependant, Il reste quelque éléments à ne pas oublier lors de la création de boite de dialogues, afin de s'assurer que votre application réagissent comme tout autre application Windows. Dans cet article nous allons voir comment créer une boite de dialogue simple proposant à l'utilisateur une question et qui retournera la réponse. Ainsi nous verrons petit à petit les différents réflexes à adopter.

Création de la boite de dialogue

Pour cette boite de dialogue, Je voulais juste un Label demandant à l'utilisateur une information à son propos, une TextBox permettant de répondre, Et les habituel boutons "Ok" et "Annuler". J'ai décidé d'ajouter de plus une icône à ma boite de dialogue, pour une meilleur esthétique. Voici le résultat :

Et voici le code pour cette boite de dialogue :

<Window x:Class="WpfTutorialSamples.Dialogs.InputDialogSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Input" SizeToContent="WidthAndHeight" WindowStartupLocation="CenterScreen"
        ContentRendered="Window_ContentRendered">
    <Grid Margin="15">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <Image Source="/WpfTutorialSamples;component/Images/question32.png" Width="32" Height="32" Grid.RowSpan="2" Margin="20,0" />

        <Label Name="lblQuestion" Grid.Column="1">Question:</Label>
        <TextBox Name="txtAnswer" Grid.Column="1" Grid.Row="1" MinWidth="250">Answer</TextBox>

        <WrapPanel Grid.Row="2" Grid.ColumnSpan="2" HorizontalAlignment="Right" Margin="0,15,0,0">
            <Button IsDefault="True" Name="btnDialogOk" Click="btnDialogOk_Click" MinWidth="60" Margin="0,0,10,0">_Ok</Button>
            <Button IsCancel="True" MinWidth="60">_Cancel</Button>
        </WrapPanel>
    </Grid>
</Window>
using System;
using System.Windows;

namespace WpfTutorialSamples.Dialogs
{
	public partial class InputDialogSample : Window
	{
		public InputDialogSample(string question, string defaultAnswer = "")
		{
			InitializeComponent();
			lblQuestion.Content = question;
			txtAnswer.Text = defaultAnswer;
		}

		private void btnDialogOk_Click(object sender, RoutedEventArgs e)
		{
			this.DialogResult = true;
		}

		private void Window_ContentRendered(object sender, EventArgs e)
		{
			txtAnswer.SelectAll();
			txtAnswer.Focus();
		}

		public string Answer
		{
			get { return txtAnswer.Text; }
		}
	}
}

Le code est plutôt simple, mais voici les différents éléments auxquels vous devez faire attention :

XAML

Dans la partie XAML, j'ai utilisé un objet Grid pour l'affichage des contrôles - rien de sophistiqué là-dedans. J'ai retiré les propriétés Width et Height de la fenêtre et, à la place, j'ai défini la fenêtre en redimensionnement automatique pour s'adapter au contenu - cela a un sens dans le cas d'une boîte de dialogue, si bien que vous n'avez pas besoin de régler finement la taille pour que tout s'affiche correctement. A la place, utilisez les propriétés de marge et de taille minimum pour vous assurer que les éléments apparaissent comme vous le voulez, tout en laissant la possibilité à l'utilisateur de redimensionner la boîte de dialogue.

Une autre propriété de la fenêtre que j'ai modifié est sa position de départ WindowStartupLocation. Pour une boite de dialogue comme celle-ci, et probablement pour tout autres fenêtres secondaires, vous devriez changer cette propriété à "CenterScreen" ou "CenterOwner" (le paramètre par défaut laissant Windows décider de la position) , si vous n'avez pas manuellement définie les paramètres Top et Left auparavant.

Faites également particulièrement attention aux deux propriétés que j'ai utilisées sur les boutons de la boite de dialogue: IsCancel et IsDefault. "IsCancel" indique à WPF que, lorsque l'utilisateur clic sur ce bouton, le DialogResult de notre fenêtre doit être définie à faux (false) et que la fenêtre doit ensuite être fermé. Cela permet aussi de s'assurer que l'utilisateur puisse appuyer sur la touche Esc du clavier pour fermer la fenêtre, ce qui devrait toujours être possible avec une boite de dialogue Windows.

La propriété IsDefault donne le focus au bouton "Ok" et s'assure que lorsque l'utilisateur appuie sur la touche Entrer, ce bouton soit déjà activé. Dans ce cas un gestionnaire d'événement est nécessaire pour définir le "DialogResult", comme décrit ultérieurement.

Code-behind

In Code-behind, I changed the constructor to take two parameters, with one being optional. This allows us to place the question and the default answer, if provided, into the designated UI controls.

The Ok button has an event handler which ensures that the special DialogResult property of the Window is set to true when clicked, to signal to the initiator of the dialog that the user accepted the entered value. We don't have one for the Cancel button, because WPF handles this for us when we set the IsCancel property to true, as described above.

To give focus to the TextBox upon showing the dialog, I've subscribed to the ContentRendered event, where I select all the text in the control and then give focus. If I just wanted to give focus, I could have use the FocusManager.FocusedElement attached property on the Window, but in this case, I also want to select the text, to allow the user to instantly overwrite the answer provided by default (if any).

A last detail is the Answer property which I've implemented. It simply gives access to the entered value of the TextBox control, but it's good practice to provide a property with the return value(s) of the dialog, instead of directly accessing controls from outside the window. This also allows you to influence the return value before returning it, if needed.

Using the dialog

With all the above in place, we're now ready to actually use our dialog. It's a very simple task, so I've created a small application for testing it. Here's the code:

<Window x:Class="WpfTutorialSamples.Dialogs.InputDialogAppSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="InputDialogAppSample" Height="150" Width="300">
    <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
        <TextBlock>Hello, world. My name is:</TextBlock>
        <TextBlock Name="lblName" Margin="0,10" TextAlignment="Center" FontWeight="Bold">[No name entered]</TextBlock>
        <Button Name="btnEnterName" Click="btnEnterName_Click">Enter name...</Button>
    </StackPanel>
</Window>
using System;
using System.Windows;

namespace WpfTutorialSamples.Dialogs
{
	public partial class InputDialogAppSample : Window
	{
		public InputDialogAppSample()
		{
			InitializeComponent();
		}

		private void btnEnterName_Click(object sender, RoutedEventArgs e)
		{
			InputDialogSample inputDialog = new InputDialogSample("Please enter your name:", "John Doe");
			if(inputDialog.ShowDialog() == true)
				lblName.Text = inputDialog.Answer;
		}
	}
}

There's nothing special to it - just a couple of TextBlock controls and a Button for invoking the dialog. In the Click event handler, we instantiate the InputDialogSample window, providing a question and a default answer, and then we use the ShowDialog() method to show it - you should always use ShowDialog() method and not just Show() for a modal dialog like this.

If the result of the dialog is true, meaning that the user has activated the Ok button either by clicking it or pressing Enter, the result is assigned to the name Label. That's all there is to it!

This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!