This article is currently in the process of being translated into Korean (~15% done).
맞춤형 입력 대화창 만들기
지난 몇몇 글들에서,WPF의 내재된 dialog들을 살펴 보았는데 자신만을 위한 dialog를 만드는 것도 그것만큼 쉽습니다. 사실상 Window를 만들고, 필요한 control들을 배치하고 보여주는 것만으로도 충분합니다.
그렇지만, 대화창을 만드는데 반드시 기억해야할 몇가지 사항이 있는데,그건 당신의 application이 다른 Window application처럼 동작하게 하는 것입니다. 이글에서, 당신이 따라야할 여러 좋은 관례를 토론하면서, 사용자에게 질문을 하고 그 답을 되돌려 주는 매우 간단한 대화창을 만들어 볼까 합니다.
대화창 디자인 하기
이 특별한 대화창을 위해,우리는 우리가 어떤 정보를 필요로 하는지를 사용자에게 알려주는 Lable과 , 답을 입력하는 TextBox, 그리고 일반적인 OK와 취소 버튼이 필요합니다. 멋있게 보이기 위해 대화창에 icon도 추가하기로 결졍했습니다. 여기에 그 결과가 있습니다.
여기에 대화 상자의 코드가 있습니다.
<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; }
}
}
}
코드는 매우 간단하지만, 특별히 주의해야 할 사항이 있습니다.
XAML
In the XAML part, I've used a Grid for layout of the controls - nothing fancy here. I've removed the Width and Height properties of the Window and instead set it to automatically resize to match the content - this makes sense in a dialog, so you don't have to fine tune the size to make everything look alright. Instead, use margins and minimum sizes to ensure that things look the way you want them to, while still allowing the user to resize the dialog.
Another property which I've changed on the Window is the WindowStartupLocation property. For a dialog like this, and probably for most other non-main windows, you should change this value to CenterScreen or CenterOwner, to change the default behavior where your window will appear in a position decided by Windows, unless you manually specify Top and Left properties for it.
Also pay special attention to the two properties I've used on the dialog buttons: IsCancel and IsDefault. IsCancel tells WPF that if the user clicks this button, the DialogResult of the Window should be set to false which will also close the window. This also ensures that the user can press the Esc key on their keyboard to close the window, something that should always be possible in a Windows dialog.
The IsDefault property gives focus to the Ok button and also ensures that if the user presses the Enter key on their keyboard, this button is activated. An event handler is needed to set the DialogResult for this though, as described later.
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!