WPF:ダイアログ/プロンプトを作成する


84

ユーザー入力用のTextBoxを含むダイアログ/プロンプトを作成する必要があります。私の問題は、ダイアログを確認した後にテキストを取得する方法ですか?通常、私はこのためのクラスを作成し、プロパティにテキストを保存します。ただし、XAMLを使用してダイアログを設計したいと思います。したがって、TextBoxのコンテンツをプロパティに保存するためにXAMLコードを拡張する必要がありますが、純粋な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

7
OKボタンクリックイベントを処理し、this.DialogResult = true;を設定する必要があります。ダイアログを閉じてdialog.ShowDialog()== trueにします。
アーウィンメイヤー

これはまだ素晴らしい答えです。
TCOE

私が使用する準備ができて素敵なシンプルなプロンプトダイアログたリンクを
vinsa

ここで確認できる問題の1つは、このダイアログに最大化ボタンと最小化ボタンもあることです。このボタンを無効にすることはできますか?
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
+1MessageBoxスタイルの静的メソッドを実装するため。簡潔で再利用可能なコード!
Aaron Blenkush 2013

2
「静的」という言葉を見るやいなや、他の答えは無視しました。ありがとうございました!:)
maplemale 2018年

16

ジョシュの素晴らしい答え、彼の功績ですが、私はそれを少し修正しました:

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

50の必要がないので、あなたは(あなたのグリッドの定義XAMLで)50 * 50 * *とし、*を交換する必要があります
Mafii

ヒント:WindowStyle="ToolWindow"ウィンドウを設定すると、見栄えがさらに良くなります。また、WindowStartupLocation="CenterOwner"そしてdialog.Owner = this;親ウィンドウの中央に位置して
ソロ

2

あなたが必要としない、いかなるこれらの他の空想の回答。以下はすべて持っていない単純化した例であるMarginHeightWidthXAMLで設定されたプロパティを、これは基本的なレベルで行わ取得する方法を示すために十分なはずです。

XAML
ビルドしWindow、通常あなたのようなページを考え、それに自分のフィールドを追加し、言うLabelTextBox内部コントロールをStackPanel

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

次に、Button送信の標準(「OK」または「送信」)と、必要に応じて「キャンセル」ボタンを作成します。

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

次に、イベントハンドラー関数(Click[XAML]ボタンの関数を右クリックし、[定義に移動]を選択すると、関数が作成されます)の場合、ボックスが空かどうかを確認する必要があります。そうでない場合は変数に格納し、ウィンドウを閉じます。

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イベントハンドラーを含めて、次のように1つの変更を加えましょう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」を「渡す」DialogResultがあります。3)ボタンのIsCancel属性は真...余分なコードなしでキャンセルボタンを作る
AntonK

@AntonK 1)静的オブジェクトを使用すると、他のクラスの変数を常にインスタンス化せずに呼び出すことができます。私にとって、静的変数はそれらすべてを切り取っており、はるかに好ましいです。それらを含むオブジェクト(ウィンドウ、ページ)が開かれるといつでもリセットされるため、問題は発生しませんでした。複数のダイアログが必要な場合は、それぞれにダイアログを作成します。同じダイアログを何度も使用しないでください。問題がありますが、コーディングも不適切です。同じダイアログを50回使用するのはなぜですか。
vapcguy 2017年

あなたが戻って渡すことはできません)2を@AntonK DialogResult、それはだWPFでMessageBoxResult私だけに、標準のボタンから働く見つけた、MessageBox.Show()ないて示したカスタムダイアログから1 -ダイアログ.ShowDialog()、および標準の演算子のためにできるだけのクエリ- MessageBoxResult.OKMessageBoxResult.Cancel「はい」、 、「いいえ」など-ブール値やカスタム値ではありません。3)IsCancelとにかく、ブール値で保存して送り返す必要があるため、これは万能のソリューションでした。
vapcguy 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.