WPF: एक डायलॉग / प्रांप्ट बनाएं


84

मुझे उपयोगकर्ता इनपुट के लिए TextBox सहित एक डायलॉग / प्रॉम्प्ट बनाने की आवश्यकता है। मेरी समस्या यह है कि संवाद की पुष्टि के बाद पाठ कैसे प्राप्त करें? आमतौर पर मैं इसके लिए एक क्लास बनाता हूं जो एक संपत्ति में पाठ को बचाएगा। हालाँकि मैं XAML का उपयोग करके डायलॉग डिज़ाइन करना चाहता हूँ। इसलिए मुझे किसी तरह एक संपत्ति में टेक्स्टबॉक्स की सामग्री को बचाने के लिए XAML कोड को सीमित करना होगा - लेकिन मुझे लगता है कि यह शुद्ध XAML के साथ संभव नहीं है। यह महसूस करने का सबसे अच्छा तरीका क्या होगा कि मैं क्या करना चाहूंगा? एक संवाद कैसे बनाया जाए जिसे XAML से परिभाषित किया जा सकता है लेकिन फिर भी किसी तरह इनपुट वापस कर सकता है? किसी भी संकेत के लिए धन्यवाद!

जवाबों:


143

"जिम्मेदार" उत्तर मेरे लिए होगा कि संवाद के लिए एक ViewModel बनाने का सुझाव दें और TextBox पर दो-तरफ़ा डेटाबाइंडिंग का उपयोग करें ताकि ViewModel के पास कुछ "ResponseText" संपत्ति हो या नहीं। यह करना काफी आसान है, लेकिन शायद ओवरकिल।

व्यावहारिक जवाब सिर्फ अपने पाठ बॉक्स को एक एक्स देना होगा: नाम ताकि यह एक सदस्य बन जाए और इस तरह से कक्षा के पीछे अपने कोड में एक संपत्ति के रूप में पाठ को उजागर करें:

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

बहुत बहुत धन्यवाद जोश और मेरे देर से जवाब के लिए खेद है! मैं शुरू में केवल आपके द्वारा दिखाए गए एक वर्ग बनाने के बजाय एक फ़ाइल से XAML लोड करने पर केंद्रित था।
stefan.at.wpf

7
आपको ओके बटन क्लिक इवेंट को हैंडल करना होगा और इसे सेट करना होगा। DialogResult = true; संवाद को बंद करने और संवाद करने के लिए। सचलॉग () == सच।
इरविन मेयर

यह अभी भी एक महान जवाब है।
tCoe

मुझे एक अच्छा सरल प्रॉम्प्ट डायलॉग मिला जो लिंक
vinsa

बस एक समस्या मैं यहाँ देख सकता हूँ, कि इस डायलॉग में अधिकतम बटन और न्यूनतम बटन भी है .... क्या इस बटन को अक्षम करना संभव है?
अलेक्सी टिमोशेंको

35

मैं इसे मैसेजबॉक्स की तरह कॉल करने के लिए सिर्फ एक स्टैटिक तरीका जोड़ता हूं:

<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-स्टाइल स्थैतिक विधि को लागू करने के लिए। संक्षिप्त, पुन: प्रयोज्य कोड!
एरोन ब्लेनकुश

2
जैसे ही मैंने "स्थिर" शब्द देखा, मैंने अन्य उत्तरों को नजरअंदाज कर दिया। धन्यवाद! :)
Maplemale

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

आपको (अपनी ग्रिड परिभाषा में xaml) 50 * और 50 * को * और * के साथ बदलना चाहिए क्योंकि 50 की कोई आवश्यकता नहीं है।
माफ़ी

युक्ति: WindowStyle="ToolWindow"विंडो पर सेटिंग करने से यह और भी अच्छा दिखने लगता है। इसके अलावा WindowStartupLocation="CenterOwner"और dialog.Owner = this;माता पिता के खिड़की के केंद्र में पदों यह
एकल

2

आपको इनमें से किसी भी अन्य फैंसी उत्तर की आवश्यकता नहीं है। नीचे एक सरल उदाहरण दिया गया है Margin, जिसमें XAML में सभी Height,, Widthगुण सेट नहीं हैं , लेकिन यह दिखाने के लिए पर्याप्त होना चाहिए कि इसे मूल स्तर पर कैसे प्राप्त किया जाए।

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;

फिर, ईवेंट हैंडलर फ़ंक्शंस के लिए ( 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ईवेंट हैंडलर को शामिल करें, और इसमें एक बदलाव करें 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 () के माध्यम से "पास" 'सही' करने के लिए DialogResult है; 3) एक बटन के लिए IsCancel विशेषता यह किसी भी अतिरिक्त कोड के बिना एक सच रद्द बटन बनाता है ...
AntonK

@AntonK 1) स्थैतिक वस्तुओं का उपयोग करना है कि आप अन्य कक्षाओं में चर को हर समय बिना बताए कैसे कॉल कर सकते हैं। मेरे लिए, स्थैतिक चर ने सभी को काट दिया और अब तक बेहतर है। उनके साथ कभी कोई समस्या नहीं थी, क्योंकि उन्हें कभी भी ऑब्जेक्ट (विंडो, पेज) रीसेट मिल जाएगा जो उनके पास है। यदि आप कई संवाद चाहते हैं, तो हर एक के लिए एक संवाद बनाएं - एक ही ओवर का उपयोग न करें या हाँ, यह समस्याग्रस्त है - लेकिन खराब कोडिंग भी है, क्योंकि आप एक ही संवाद 50 बार क्यों चाहते हैं?
वाप्गुगी

@AntonK 2) आप वापस पारित कर सकते हैं नहीं DialogResultWPF में, यह MessageBoxResultहै, जो मैंने पाया केवल एक पर मानक बटन से काम करता है MessageBox.Show()संवाद - नहीं एक एक कस्टम संवाद से के माध्यम से दिखाया .ShowDialog()- और केवल क्वेरी मानक ऑपरेटरों के लिए, MessageBoxResult.OK, MessageBoxResult.Cancel, "हाँ" , "नहीं", आदि - बूलियन या कस्टम मूल्य नहीं। 3) IsCancelइसे बूलियन में संग्रहीत करने की आवश्यकता होती है और वैसे भी उसे वापस भेजना होता है, इसलिए यह एक आकार-फिट-सभी समाधान था।
वाप्गुगी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.