WPF : 대화 / 프롬프트 만들기


84

사용자 입력을 위해 TextBox를 포함하는 Dialog / Prompt를 만들어야합니다. 내 문제는 대화 상자를 확인한 후 텍스트를 얻는 방법입니다. 일반적으로 나는 속성에 텍스트를 저장하는 클래스를 만들 것입니다. 그러나 XAML을 사용하여 대화 상자를 디자인하고 싶습니다. 그래서 어떻게 든 XAML 코드를 확장하여 TextBox의 콘텐츠를 속성에 저장해야하지만 순수 XAML에서는 불가능하다고 생각합니다. 내가하고 싶은 일을 실현하는 가장 좋은 방법은 무엇입니까? XAML에서 정의 할 수 있지만 여전히 입력을 반환 할 수있는 대화 상자를 만드는 방법은 무엇입니까? 힌트 주셔서 감사합니다!

답변:


143

"책임있는"대답은 대화 상자에 대한 ViewModel 빌드를 제안하고 TextBox에서 양방향 데이터 바인딩을 사용하여 ViewModel에 "ResponseText"속성이 있는지 여부를 제안하는 것입니다. 이것은 쉽게 할 수 있지만 아마도 과잉 일 것입니다.

실용적인 대답은 텍스트 상자에 x : Name을 지정하여 멤버가되고 다음과 같이 클래스 뒤에있는 코드의 속성으로 텍스트를 노출하는 것입니다.

<!-- Incredibly simplified XAML -->
<Window x:Class="MyDialog">
   <StackPanel>
       <TextBlock Text="Enter some text" />
       <TextBox x:Name="ResponseTextBox" />
       <Button Content="OK" Click="OKButton_Click" />
   </StackPanel>
</Window>

그런 다음 코드 뒤에 ...

partial class MyDialog : Window {

    public MyDialog() {
        InitializeComponent();
    }

    public string ResponseText {
        get { return ResponseTextBox.Text; }
        set { ResponseTextBox.Text = value; }
    }

    private void OKButton_Click(object sender, System.Windows.RoutedEventArgs e)
    {
        DialogResult = true;
    }
}

그런 다음 그것을 사용하려면 ...

var dialog = new MyDialog();
if (dialog.ShowDialog() == true) {
    MessageBox.Show("You said: " + dialog.ResponseText);
}

Josh 감사합니다. 답장이 늦어 죄송합니다! 처음에는 내가 보여준 것과 같은 클래스를 만드는 대신 파일에서 XAML을로드하는 데 너무 집중했습니다.
— stefan.at.wpf 2010-07-05

7
OK 버튼 클릭 이벤트를 처리하고 this.DialogResult = true로 설정해야합니다. 대화 상자를 닫고 dialog.ShowDialog () == true가됩니다.
— Erwin Mayer

이것은 여전히 ​​좋은 대답입니다.
— tCoe

나는 좋은 간단 프롬프트 사용 준비 대화 상자가 발견 링크
— vinsa

여기서 볼 수있는 한 가지 문제는이 대화 상자에도 최대화 버튼과 최소화 버튼이 있다는 것입니다 ....이 버튼을 비활성화 할 수 있습니까?
— Aleksey Timoshchenko

34

MessageBox처럼 호출하는 정적 메서드를 추가합니다.

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    x:Class="utils.PromptDialog"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    WindowStartupLocation="CenterScreen" 
    SizeToContent="WidthAndHeight"
    MinWidth="300"
    MinHeight="100"
    WindowStyle="SingleBorderWindow"
    ResizeMode="CanMinimize">
<StackPanel Margin="5">
    <TextBlock Name="txtQuestion" Margin="5"/>
    <TextBox Name="txtResponse" Margin="5"/>
    <PasswordBox Name="txtPasswordResponse" />
    <StackPanel Orientation="Horizontal" Margin="5" HorizontalAlignment="Right">
        <Button Content="_Ok" IsDefault="True" Margin="5" Name="btnOk" Click="btnOk_Click" />
        <Button Content="_Cancel" IsCancel="True" Margin="5" Name="btnCancel" Click="btnCancel_Click" />
    </StackPanel>
</StackPanel>
</Window>

그리고 뒤에있는 코드 :

public partial class PromptDialog : Window
{
    public enum InputType
    {
        Text,
        Password
    }

    private InputType _inputType = InputType.Text;

    public PromptDialog(string question, string title, string defaultValue = "", InputType inputType = InputType.Text)
    {
        InitializeComponent();
        this.Loaded += new RoutedEventHandler(PromptDialog_Loaded);
        txtQuestion.Text = question;
        Title = title;
        txtResponse.Text = defaultValue;
        _inputType = inputType;
        if (_inputType == InputType.Password)
            txtResponse.Visibility = Visibility.Collapsed;
        else
            txtPasswordResponse.Visibility = Visibility.Collapsed;
    }

    void PromptDialog_Loaded(object sender, RoutedEventArgs e)
    {
        if (_inputType == InputType.Password)
            txtPasswordResponse.Focus();
        else
            txtResponse.Focus();
    }

    public static string Prompt(string question, string title, string defaultValue = "", InputType inputType = InputType.Text)
    {
        PromptDialog inst = new PromptDialog(question, title, defaultValue, inputType);
        inst.ShowDialog();
        if (inst.DialogResult == true)
            return inst.ResponseText;
        return null;
    }

    public string ResponseText
    {
        get
        {
            if (_inputType == InputType.Password)
                return txtPasswordResponse.Password;
            else
                return txtResponse.Text;
        }
    }

    private void btnOk_Click(object sender, RoutedEventArgs e)
    {
        DialogResult = true;
        Close();
    }

    private void btnCancel_Click(object sender, RoutedEventArgs e)
    {
        Close();
    }
}

따라서 다음과 같이 부를 수 있습니다.

string repeatPassword = PromptDialog.Prompt("Repeat password", "Password confirm", inputType: PromptDialog.InputType.Password);

6
+1 MessageBox스타일의 정적 메서드 를 구현합니다 . 간결하고 재사용 가능한 코드!
— Aaron Blenkush 2013-08-20

2
"정적"이라는 단어를 보자 마자 다른 대답을 무시했습니다. 감사합니다! :)
— maplemale

16

Josh의 훌륭한 대답, 그에게 모든 신용을 부여했지만 약간 수정했습니다.

MyDialog Xaml

    <StackPanel Margin="5,5,5,5">
        <TextBlock Name="TitleTextBox" Margin="0,0,0,10" />
        <TextBox Name="InputTextBox" Padding="3,3,3,3" />
        <Grid Margin="0,10,0,0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <Button Name="BtnOk" Content="OK" Grid.Column="0" Margin="0,0,5,0" Padding="8" Click="BtnOk_Click" />
            <Button Name="BtnCancel" Content="Cancel" Grid.Column="1" Margin="5,0,0,0" Padding="8" Click="BtnCancel_Click" />
        </Grid>
    </StackPanel>

MyDialog 코드 뒤에

    public MyDialog()
    {
        InitializeComponent();
    }

    public MyDialog(string title,string input)
    {
        InitializeComponent();
        TitleText = title;
        InputText = input;
    }

    public string TitleText
    {
        get { return TitleTextBox.Text; }
        set { TitleTextBox.Text = value; }
    }

    public string InputText
    {
        get { return InputTextBox.Text; }
        set { InputTextBox.Text = value; }
    }

    public bool Canceled { get; set; }

    private void BtnCancel_Click(object sender, System.Windows.RoutedEventArgs e)
    {
        Canceled = true;
        Close();
    }

    private void BtnOk_Click(object sender, System.Windows.RoutedEventArgs e)
    {
        Canceled = false;
        Close();
    }

그리고 다른 곳으로 불러

var dialog = new MyDialog("test", "hello");
dialog.Show();
dialog.Closing += (sender,e) =>
{
    var d = sender as MyDialog;
    if(!d.Canceled)
        MessageBox.Show(d.InputText);
}

(그리드 정의 xaml에서) 50 * 및 50 *을 * 및 *로 바꿔야합니다. 50이 필요하지 않기 때문입니다.
— Mafii

팁 : WindowStyle="ToolWindow"창에서 설정 하면 더 멋지게 보입니다. 또한 WindowStartupLocation="CenterOwner"및 dialog.Owner = this;부모 윈도우의 중앙에 위치하여
— 솔로

2

당신은 필요하지 않습니다 어떤 이 다른 멋진 답변의. 다음은 모든이없는 단순한 예는 Margin, Height, WidthXAML에 속성을 설정하지만,이 기본적인 수준에서 수행 얻는 방법을 보여 충분합니다.

XAML
빌드 Window당신이 일반적으로과에 필드를 추가하는 것처럼 페이지를하는 말을 Label하고 TextBox, 안쪽 제어 StackPanel:

<StackPanel Orientation="Horizontal">
    <Label Name="lblUser" Content="User Name:" />
    <TextBox Name="txtUser" />
</StackPanel>

그런 다음 Button제출 표준 ( "확인"또는 "제출")과 원하는 경우 "취소"버튼을 만듭니다 .

<StackPanel Orientation="Horizontal">
    <Button Name="btnSubmit" Click="btnSubmit_Click" Content="Submit" />
    <Button Name="btnCancel" Click="btnCancel_Click" Content="Cancel" />
</StackPanel>

코드 비하인드 코드 비하인드
에 Click이벤트 처리기 함수를 추가 하지만, 거기에 가면 먼저 텍스트 상자 값을 저장할 공용 변수를 선언합니다.

public static string strUserName = String.Empty;

그런 다음 이벤트 처리기 함수 ( ClickXAML 단추 의 함수를 마우스 오른쪽 단추로 클릭하고 "정의로 이동"을 선택하면 자동으로 생성됨)의 경우 상자가 비어 있는지 확인해야합니다. 그렇지 않은 경우 변수에 저장하고 창을 닫습니다.

private void btnSubmit_Click(object sender, RoutedEventArgs e)
{        
    if (!String.IsNullOrEmpty(txtUser.Text))
    {
        strUserName = txtUser.Text;
        this.Close();
    }
    else
        MessageBox.Show("Must provide a user name in the textbox.");
}

다른 페이지에서 불러 오기
당신은 내가 this.Close()거기에 내 창을 닫으면 내 가치가 사라진다고 생각하고 있습니다. 아니!! 나는 이것을 다른 사이트에서 발견했다 : http://www.dreamincode.net/forums/topic/359208-wpf-how-to-make-simple-popup-window-for-input/

그들은 Window다른 것에서 당신을 열고 값을 검색하는 방법에 대한 이와 유사한 예를 가지고 있습니다 (조금 정리했습니다) .

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void btnOpenPopup_Click(object sender, RoutedEventArgs e)
    {
        MyPopupWindow popup = new MyPopupWindow();  // this is the class of your other page

        //ShowDialog means you can't focus the parent window, only the popup
        popup.ShowDialog(); //execution will block here in this method until the popup closes

        string result = popup.strUserName;
        UserNameTextBlock.Text = result;  // should show what was input on the other page
    }
}

취소 버튼
당신은 생각하고 있는데요, 취소 버튼은 어떨까요? 따라서 팝업 창 코드 숨김에 또 다른 공용 변수를 다시 추가합니다.

public static bool cancelled = false;

그리고 우리의 btnCancel_Click이벤트 핸들러를 포함시키고 다음을 변경 해보자 btnSubmit_Click:

private void btnCancel_Click(object sender, RoutedEventArgs e)
{        
    cancelled = true;
    strUserName = String.Empty;
    this.Close();
}

private void btnSubmit_Click(object sender, RoutedEventArgs e)
{        
    if (!String.IsNullOrEmpty(txtUser.Text))
    {
        strUserName = txtUser.Text;
        cancelled = false;  // <-- I add this in here, just in case
        this.Close();
    }
    else
        MessageBox.Show("Must provide a user name in the textbox.");
}

그런 다음 MainWindow btnOpenPopup_Click이벤트 에서 해당 변수를 읽습니다 .

private void btnOpenPopup_Click(object sender, RoutedEventArgs e)
{
    MyPopupWindow popup = new MyPopupWindow();  // this is the class of your other page
    //ShowDialog means you can't focus the parent window, only the popup
    popup.ShowDialog(); //execution will block here in this method until the popup closes

    // **Here we find out if we cancelled or not**
    if (popup.cancelled == true)
        return;
    else
    {
        string result = popup.strUserName;
        UserNameTextBlock.Text = result;  // should show what was input on the other page
    }
}

긴 응답이지만 public static변수를 사용하는 것이 얼마나 쉬운 지 보여주고 싶었습니다 . 아니요 DialogResult, 반환 값이 없습니다. 창을 열고 팝업 창에서 버튼 이벤트와 함께 값을 저장 한 다음 나중에 기본 창 기능에서 검색하면됩니다.


제공된 코드를 개선 할 수있는 많은 방법이 있습니다. 1) 데이터를 저장하는 데 정적을 사용하지 마십시오. 그렇지 않으면 때때로 여러 대화 상자에서 문제가 발생할 수 있습니다. 2) ShowDialog ()를 통해 'true'를 "pass"하는 DialogResult가 있습니다. 3) 버튼 IsCancel 속성은 ... 그것은 진정한 여분의 코드없이 버튼을 취소합니다
— AntonK

@AntonK 1) 정적 개체를 사용하면 항상 인스턴스화하지 않고도 다른 클래스의 변수를 호출 할 수 있습니다. 나에게 정적 변수는 모든 것을 잘라내어 훨씬 바람직합니다. 그것들을 가지고있는 객체 (Window, Page)가 열릴 때마다 리셋 될 것이기 때문에 그들에게 문제가 없었습니다. 여러 개의 대화 상자를 원할 경우 각 대화 상자를 만듭니다. 동일한 대화 상자를 반복해서 사용하지 마십시오. 그렇지 않으면 문제가됩니다. 그러나 잘못된 코딩도 마찬가지입니다. 동일한 대화 상자를 50 번 원하는 이유는 무엇입니까?
— vapcguy

@AntonK 2) 다시 전달할 수 없습니다 DialogResult, 그건 WPF에서 MessageBoxResult만에 표준 단추에서 작동, 내가 찾은하는 MessageBox.Show()없습니다 하나의 사용자 정의 대화 상자에서 통해 표시 - 대화 .ShowDialog()- 그리고 수 만 쿼리 표준 운영자, MessageBoxResult.OK, MessageBoxResult.Cancel, "예" , "아니오"등-부울 또는 사용자 정의 값이 아닙니다. 3) IsCancel부울에 저장하고 어쨌든 되돌려 보내야하므로 이것은 모든 것에 적합한 솔루션이었습니다.
— vapcguy
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.