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.