TOC

This article has been localized into Polish by the community.

Okna dialogowe:

Tworzenie własnego okna dialogowego

W ostatnich kilku artykułach przyjrzeliśmy się jak używać okien dialogowych dostępnych w WPF. Tworzenie własnych okien dialogowych jest niemal równie łatwe. W rzeczywistości wystarczy utworzyć okno, umieścić w nim wymagane elementy WPF, a następnie je pokazać.

Jest jednak kilka rzeczy, o których należy pamiętać podczas tworzenia własnych okien dialogowych, aby mieć pewność, że twoja aplikacja będzie działać tak samo, jak inne aplikacje w systemie Windows. W tym artykule utworzymy bardzo proste okno dialogowe, które zada użytkownikowi pytanie, a następnie zwróci nam jego odpowiedź. W trakcie jego tworzenia omówione zostaną różne dobre praktyki godne naśladowania.

Tworzenie okna

W tworzonym oknie dialogowym chciałem mieć tylko etykietę informującą użytkownika jakiej informacji od niego oczekujemy, pole tekstowe do wpisania odpowiedzi oraz zwykłe przyciski OK i Anuluj. Postanowiłem również dodać ikonę do okna dialogowego, aby lepiej wyglądało. Oto wynik końcowy:

A oto kod naszego okna dialogowego:

<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; }
		}
	}
}

Kod jest dość prosty, ale jest kilka rzeczy, na które należy zwrócić szczególną uwagę:

Kod XAML

W kodzie XAML użyłem panelu "Grid" dla rozmieszczenia kontrolek - nic nadzwyczajnego. Usunąłem sztywne ustawienie właściwości Szerokość i Wysokość okna, a zamiast tego ustawiłem automatyczną zmianę rozmiaru okna w celu jego elastycznego dopasowywania się do zawartości - ma to sens w zmieniającej się treści okna dialogowego, więc nie trzeba za każdym razem ręcznie dostosowywać rozmiaru okna, aby wszystko dobrze wyglądało. Zamiast takiego rozwiązania można użyć marginesów i wymiarów minimalnych okna, aby upewnić się, że rzeczy wyglądają tak, jak chcesz, jednocześnie umożliwiając użytkownikowi zmianę rozmiaru okna dialogowego.

Kolejną właściwością jaką zmieniłem w oknie, jest właściwość WindowStartupLocation. W przypadku naszego okna dialogowego, i prawdopodobnie w przypadku większości innych pomocniczych okien dialogowych, należy ustawić wartość tej właściwości na "CenterScreen" lub "CenterOwner". Zmienia to domyślne zachowanie systemu operacyjnego, przy którym to okno dialogowe byłoby wyświetlane w pozycji określonej przez system Windows. Można też ewentualnie ręcznie określić pozycję wyświetlania się okna poprzez ustawienie jego właściwości "Top" i "Left".

Zwróć również szczególną uwagę na dwie właściwości, których użyłem w przyciskach okna dialogowego: "IsCancel" oraz "IsDefault". "IsCancel" informuje WPF, że jeśli użytkownik kliknie ten przycisk, wartość parametru "DialogResult" zwracana przez okno dialogowe powinna być ustawiona na false, co spowoduje również zamknięcie okna. Sprawia to również, że użytkownik może nacisnąć klawisz Esc na klawiaturze, aby zamknąć okno dialogowe. Jest to możliwość, która zawsze powinno być dostępna w oknach dialogowych systemu Windows.

Właściwość IsDefault ustawia przycisk OK jako domyślnie wybrany (focus), a także sprawia, że jeśli użytkownik naciśnie klawisz Enter na klawiaturze, to przycisk ten zostanie aktywowany. Jednak do ustawienia właściwości "DialogResult" jest potrzebna metoda obsługująca zdarzenie kliknięcia przycisku, jak opisano to poniżej.

Kod obsługujący UI

W kodzie obsługującym UI (zwanym Code-behind) zmieniłem konstruktora, aby przyjmował dwa parametry, z których jeden jest opcjonalny. Dzięki temu możemy w wyznaczonych kontrolkach interfejsu użytkownika umieścić pytanie i domyślną odpowiedź użytkownika, jeśli zostanie przez nas podana.

Przycisk Ok posiada metodę obsługującą zdarzenie jego kliknięcia, która zapewnia, że ​​specjalna właściwość "DialogResult" okna dialogowego jest ustawiana na wartość true, aby zasygnalizować inicjatorowi okna dialogowego, że użytkownik zaakceptował wprowadzoną wartość. Nie mamy takiej metody dla przycisku Anuluj, ponieważ WPF obsługuje to zdarzenie samodzielnie, gdy tylko ustawimy właściwość IsCancel na true, jak opisano powyżej.

Aby skupić się na kontrolce TextBox, zawierającej odpowiedź użytkownika, po wyświetleniu okna dialogowego, zaimplementowałem metodę obsługującą zdarzenie Window_ContentRendered. W metodzie tej zaznaczam cały tekst w kontrolce, a następnie ustawiam ją jako aktywną. Gdybym chciał tylko ustawić kontrolkę jako aktywną, mógłbym użyć dołączanej właściwości "FocusManager.FocusedElement" w oknie dialogowym, ale w tym przypadku chcę również zaznaczyć cały tekst kontrolki, aby umożliwić użytkownikowi natychmiastowe nadpisanie domyślnej odpowiedzi (jeśli taka istnieje ).

Ostatni element to właściwość Answer, którą zaimplementowałem. Zwyczajnie zapewnia nam ona dostęp do wprowadzonej przez użytkownika odpowiedzi wewnątrz kontrolki TextBox. Zalecaną i dobrą praktyką jest tworzenie właściwości ze zwracanymi wartościami okna dialogowego, zamiast bezpośredniego umożliwiania dostępu do kontrolek z zewnątrz okna dialogowego. Pozwala to również wpływać na zwracaną wartość przed jej zwróceniem, jeśli jest to potrzebne.

Korzystanie z okna

Skoro mamy wszystko przygotowane, jesteśmy teraz gotowi do skorzystania z naszego własnego okna dialogowego. To bardzo proste zadanie. Stworzyłem w tym celu małą aplikację. Oto jej kod:

<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;
		}
	}
}

Nie ma w niej nic nadzwyczajnego - tylko kilka kontrolek "TextBlock" i przycisk do wywoływania naszego okna dialogowego. W kodzie obsługi zdarzenia kliknięcia przycisku tworzymy nasze okno dialogowe InputDialogSample, podając treść pytania oraz domyślną treść odpowiedzi. Następnie używamy metody ShowDialog(), aby wyświetlić nasze okno. Dla takich modalnych okien dialogowych jak nasze, zawsze należy używać metody ShowDialog(), a nie metody Show().

Jeżeli wartość zwracana przez metodę ShowDialog() okna dialogowe jest równa "true", co oznacza, że użytkownik kliknął przycisk OK, odpowiedź udzielona przez użytkownika staje się treścią kontrolki "TextBlock" przeznaczonej do wyświetlenia imienia. To wszystko czego potrzeba!


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!