सवाल क्या सभी रूपों को अवरुद्ध किए बिना शोडियलॉग का उपयोग करना संभव है?


मुझे उम्मीद है कि मैं इसे स्पष्ट रूप से पर्याप्त समझा सकता हूं। मेरे पास मेरा मुख्य रूप है (ए) और यह फॉर्म का उपयोग करके 1 बच्चा फॉर्म (बी) खोलता है। शो () और फॉर्म का उपयोग करके दूसरा बच्चा फॉर्म (सी) दिखाएं। दिखाएं ()। अब मैं फॉर्म फॉर्म बी को फॉर्म (डी) फॉर्म खोलने के लिए चाहता हूं .ShDDialog ()। जब मैं ऐसा करता हूं, तो यह फॉर्म ए और फॉर्म सी को भी अवरुद्ध करता है। क्या एक मोडल डायलॉग खोलने का कोई तरीका है और केवल इसे खोलने वाले फॉर्म को अवरुद्ध कर दिया है?


44
2018-01-09 15:30


मूल


जानकारी के लिए, थ्रेडिंग उदाहरण जोड़ा गया - Marc Gravell♦
सवाल चिह्नित है WinForms लेकिन मैं यहां कुछ हद तक एक ही समस्या के साथ उतरा WPF। इस तरह की जानकारी की तलाश में लोगों के लिए सी तेज openfiledialog गैर-मोडल-संभव - NGI


जवाब:


यदि आप ए और सी से अलग थ्रेड पर फॉर्म बी चलाते हैं, तो ShowDialog कॉल केवल उस थ्रेड को अवरुद्ध कर देगा। जाहिर है, यह निश्चित रूप से काम का एक छोटा सा निवेश नहीं है।

आप अलग-अलग धागे पर फॉर्म डी के शोडियलॉग कॉल को चलाकर संवाद को किसी भी धागे को अवरुद्ध नहीं कर सकते हैं। इसके लिए एक ही तरह की काम की आवश्यकता होती है, लेकिन इसमें से बहुत कम, क्योंकि आपके पास केवल आपके फॉर्म के मुख्य थ्रेड से एक फॉर्म चल रहा होगा।


10
2018-01-09 15:36



मैंने सोचा कि सभी यूआई को एक ही धागे पर चलाना पड़ा था? - Jon Tackabury
जॉन टी - यह करने की ज़रूरत नहीं है, लेकिन आप बेहतर जानते होंगे कि आप क्या कर रहे हैं और उम्मीद है कि 2 के बीच कोई बातचीत नहीं है - मुझे परेशानी की तरह लगता है। - Sam Meldrum
मैं धागे और यूआई धागे के बीच invoking के बारे में पता है, मैंने काफी कुछ किया है। मैं बस उम्मीद कर रहा था कि इसे हल करने के लिए थ्रेडिंग का उपयोग करने से बचने का कोई तरीका था। ऐसा लगता है कि थ्रेडिंग हालांकि एकमात्र जवाब हो सकता है। - Jon Tackabury
यदि आप नहीं जानते कि आप क्या कर रहे हैं तो यह निश्चित रूप से परेशानी है। लेकिन मानते हैं कि दोनों संवाद नहीं करते हैं (या संचार बंद होने के बाद फॉर्म डी से कुछ डेटा पढ़ने के समान सरल है), यह लागू करने के लिए तुच्छ है। - TheSmurf
सभी यूआई को एक ही धागे पर चलाने की ज़रूरत नहीं है, आपको बस यह सुनिश्चित करने की आवश्यकता है कि आप उस फॉर्म के यूआई थ्रेड पर किसी फॉर्म की UI गुणों तक पहुंचें। इसलिए, यदि ए और बी विभिन्न धागे में चल रहे हैं, यदि ए बी को एक्सेस करता है, तो उसे एक आमंत्रण करने की आवश्यकता होगी। हमारे ऐप में, सभी फॉर्म अपने धागे पर चलते हैं। - Rob Prouse


एकाधिक जीयूआई थ्रेड का उपयोग करना मुश्किल व्यवसाय है, और यदि मैं ऐसा करने के लिए आपकी एकमात्र प्रेरणा हूं, तो मैं इसके खिलाफ सलाह दूंगा।

उपयोग करने के लिए एक और अधिक उपयुक्त दृष्टिकोण है Show() के बजाय ShowDialog(), और पॉपअप फॉर्म रिटर्न तक मालिक फॉर्म को अक्षम करें। केवल चार विचार हैं:

  1. कब ShowDialog(owner) प्रयोग किया जाता है, पॉपअप फॉर्म अपने मालिक के शीर्ष पर रहता है। जब आप उपयोग करते हैं तो वही सच है Show(owner)। वैकल्पिक रूप से, आप सेट कर सकते हैं Owner एक ही प्रभाव के साथ स्पष्ट रूप से संपत्ति।

  2. यदि आप मालिक का फॉर्म सेट करते हैं Enabled संपत्ति के लिए false, फॉर्म एक अक्षम राज्य दिखाता है (बाल नियंत्रण "ग्रेड आउट" होते हैं), जबकि कब ShowDialog उपयोग किया जाता है, मालिक प्रपत्र अभी भी अक्षम हो जाता है, लेकिन एक अक्षम स्थिति नहीं दिखाता है।

    जब तुमने फोन किया ShowDialog, मालिक फॉर्म Win32 कोड-अक्षम में अक्षम हो जाता है WS_DISABLED स्टाइल बिट सेट हो जाता है। इससे फोकस हासिल करने और क्लिक करने पर "डिंग" करने की क्षमता कम हो जाती है, लेकिन यह खुद को भूरे रंग में नहीं खींचती है।

    जब आप एक फॉर्म सेट करते हैं Enabled संपत्ति के लिए false, एक अतिरिक्त ध्वज सेट किया गया है (ढांचे में, अंतर्निहित Win32 उपप्रणाली नहीं) कि कुछ नियंत्रण नियंत्रण करते हैं जब वे खुद को आकर्षित करते हैं। यह ध्वज एक अक्षम राज्य में खुद को आकर्षित करने के लिए नियंत्रण बताता है।

    तो अनुकरण करने के लिए क्या होगा ShowDialog, हमें मूल सेट करना चाहिए WS_DISABLED फॉर्म को सेट करने के बजाय सीधे स्टाइल बिट Enabled संपत्ति के लिए false। यह एक छोटे से इंटरऑप के साथ पूरा किया जाता है:

    const int GWL_STYLE   = -16;
    const int WS_DISABLED = 0x08000000;
    
    [DllImport("user32.dll")]
    static extern int GetWindowLong(IntPtr hWnd, int nIndex);
    
    [DllImport("user32.dll")]
    static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
    
    void SetNativeEnabled(bool enabled){
        SetWindowLong(Handle, GWL_STYLE, GetWindowLong(Handle, GWL_STYLE) &
            ~WS_DISABLED | (enabled ? 0 : WS_DISABLED));
    }
    
  3. ShowDialog() जब तक संवाद खारिज नहीं किया जाता है तब तक कॉल वापस नहीं आता है। यह आसान है, क्योंकि जब तक संवाद ने अपना व्यवसाय नहीं किया है तब तक आप अपने मालिक के रूप में तर्क को निलंबित कर सकते हैं। Show() कॉल, जरूरी है, इस तरह से व्यवहार नहीं करता है। इसलिए, यदि आप उपयोग करने जा रहे हैं Show() के बजाय ShowDialog(), आपको अपने तर्क को दो हिस्सों में तोड़ने की आवश्यकता होगी। संवाद के बाद चलने वाला कोड खारिज कर दिया जाता है (जिसमें स्वामी के फॉर्म को पुन: सक्षम करना शामिल होगा), एक द्वारा चलाया जाना चाहिए Closed आयोजन प्रबंधकर्ता।

  4. जब एक फॉर्म को एक संवाद के रूप में दिखाया जाता है, तो इसे सेट किया जाता है DialogResult संपत्ति स्वचालित रूप से इसे बंद कर देता है। यह संपत्ति जब भी एक बटन के साथ सेट हो जाता है DialogResult संपत्ति के अलावा अन्य None क्लिक किया गया है एक फार्म के साथ दिखाया गया है Showस्वचालित रूप से इस तरह बंद नहीं होगा, इसलिए इसे स्पष्ट रूप से बंद करना होगा जब इसके बर्खास्तगी बटनों में से एक क्लिक किया जाता है। नोट, हालांकि, कि DialogResult संपत्ति अभी भी बटन द्वारा उचित रूप से सेट हो जाता है।

इन चार चीजों को कार्यान्वित करना, आपका कोड कुछ ऐसा हो जाता है:

class FormB : Form{
    void Foo(){
        SetNativeEnabled(false); // defined above
        FormD f = new FormD();
        f.Closed += (s, e)=>{
            switch(f.DialogResult){
            case DialogResult.OK:
                // Do OK logic
                break;
            case DialogResult.Cancel:
                // Do Cancel logic
                break;
            }
            SetNativeEnabled(true);
        };
        f.Show(this);
        // function Foo returns now, as soon as FormD is shown
    }
}

class FormD : Form{
    public FormD(){
        Button btnOK       = new Button();
        btnOK.DialogResult = DialogResult.OK;
        btnOK.Text         = "OK";
        btnOK.Click       += (s, e)=>Close();
        btnOK.Parent       = this;

        Button btnCancel       = new Button();
        btnCancel.DialogResult = DialogResult.Cancel;
        btnCancel.Text         = "Cancel";
        btnCancel.Click       += (s, e)=>Close();
        btnCancel.Parent       = this;

        AcceptButton = btnOK;
        CancelButton = btnCancel;
    }
}

74
2018-01-09 16:37



मेरे मुकाबले एक बहुत अधिक पूरा जवाब +1 - लेकिन अनिवार्य रूप से एक ही दृष्टिकोण! मेरा से छुटकारा पड़ेगा क्योंकि तुम्हारा बहुत पूरा हो गया है। - Sam Meldrum
जब आप ShowDialog () के साथ एक फॉर्म खोलते हैं और फिर पैरेंट फॉर्म पर क्लिक करने का प्रयास करते हैं, तो बच्चा फॉर्म चमक रहा है और एक डिंग ध्वनि खेला जाता है। लेकिन आपके कोड के साथ, ऐसा नहीं होता है, यानी आप माता-पिता के रूप में ध्यान केंद्रित नहीं कर सकते हैं, हां, लेकिन बाल रूप चमक नहीं रहा है और कोई आवाज नहीं खेला जाता है। तो नया व्यवहार किसी उपयोगकर्ता को भ्रमित कर रहा है। - nightcoder
@nightcoder: मुझे पता है कि यह एक साल हो गया है, लेकिन मैंने अभी आपकी टिप्पणी देखी है। मैं जो नमूना देता हूं वह वास्तव में अग्रभूमि रूप (फॉर्मडी) को फ्लैश करने का कारण बनता है और डिंग ध्वनि खेला जाता है। शायद आपके कोड में, आपने फॉर्म डी पर मालिक संपत्ति सेट नहीं की है (मेरे नमूने में, जो गुजरने से किया जाता है this सेवा मेरे f.Show(), लेकिन आप भी सेट कर सकते हैं f.Owner = this)। स्वामित्व वाली विंडो फ्लैश करने के लिए यह आवश्यक है। इसके बावजूद, इसे डिंग करना चाहिए, हालांकि, और यह मेरे लिए करता है। - P Daddy
@ पी-डैडी: कोड के इस बिट के लिए धन्यवाद। यह मेरी आवश्यकताओं के लिए एक समान समाधान को लागू करने में सहायक था: stackoverflow.com/a/16088711/654244 - KyleK
मैंने इस समाधान को लागू किया और यह बहुत अच्छा काम किया। धन्यवाद। हालांकि मैं जोड़ूंगा कि मेरा फॉर्म अभी भी ऐप के सभी अन्य रूपों के शीर्ष पर आएगा यदि माता-पिता वर्तमान में सक्रिय नहीं थे। जो मैं नहीं चाहता था। तो मैंने इसे केवल तभी निकाल दिया ActiveForm मूल रूप था। यदि नहीं तो मैंने पैरेंट फॉर्म में फॉर्म खोलने के लिए मूल रूप से एक संपत्ति सेट की है Activated घटना। - jaredbaszler


आप एक अलग थ्रेड (नीचे के रूप में) का उपयोग कर सकते हैं, लेकिन यह खतरनाक क्षेत्र में हो रहा है - यदि आप थ्रेडिंग (सिंक्रनाइज़ेशन, क्रॉस-थ्रेड एक्सेस इत्यादि) के प्रभाव को समझते हैं तो आपको केवल इस विकल्प के पास जाना चाहिए:

[STAThread]
static void Main() {
    Application.EnableVisualStyles();
    Button loadB, loadC;
    Form formA = new Form {
        Text = "Form A",
        Controls = {
            (loadC = new Button { Text = "Load C", Dock = DockStyle.Top}),
            (loadB = new Button { Text = "Load B", Dock = DockStyle.Top})
        }
    };
    loadC.Click += delegate {
        Form formC = new Form { Text = "Form C" };
        formC.Show(formA);
    };
    loadB.Click += delegate {
        Thread thread = new Thread(() => {
            Button loadD;
            Form formB = new Form {
                Text = "Form B",
                Controls = {
                    (loadD = new Button { Text = "Load D",
                        Dock = DockStyle.Top})
                }
            };
            loadD.Click += delegate {
                Form formD = new Form { Text = "Form D"};
                formD.ShowDialog(formB);
            };
            formB.ShowDialog();  // No owner; ShowDialog to prevent exit
        });
        thread.SetApartmentState(ApartmentState.STA);
        thread.Start();
    };
    Application.Run(formA);
}

(जाहिर है, आप वास्तव में उपर्युक्त जैसा कोड नहीं बनायेंगे - यह व्यवहार दिखाने का सबसे छोटा तरीका है; वास्तविक कोड में आपके पास प्रति वर्ग एक वर्ग होगा, आदि)


9
2018-01-09 15:45



उत्कृष्ट उदाहरण - धन्यवाद। मैंने थ्रेडेड रोड पर जाने का फैसला किया है, क्योंकि यह सबसे अच्छा विकल्प लगता है। - Jon Tackabury


मैं संभावित समाधानों को सारांशित करना चाहता हूं और एक नए विकल्प (3 ए और 3 बी) जोड़ना चाहता हूं। लेकिन सबसे पहले मैं यह स्पष्ट करना चाहता हूं कि हम किस बारे में बात कर रहे हैं:

हमारे पास एक ऐसा एप्लिकेशन है जिसमें कई रूप हैं। मोडल डायलॉग दिखाने की आवश्यकता है जो हमारे फॉर्मों के केवल कुछ सबसेट को अवरुद्ध करेगी लेकिन दूसरों को नहीं। मॉडल संवाद केवल एक सबसेट (परिदृश्य ए) या एकाधिक सबसेट (परिदृश्य बी) में दिखाए जा सकते हैं।

और अब संभावित समाधानों का सारांश:

  1. के माध्यम से दिखाए गए मोडल फॉर्म का उपयोग न करें ShowDialog() बिलकुल

    अपने आवेदन के डिजाइन के बारे में सोचो। क्या आपको वास्तव में उपयोग करने की ज़रूरत है ShowDialog() तरीका? यदि आपको मोडल फॉर्म रखने की आवश्यकता नहीं है तो यह जाने का सबसे आसान और सबसे साफ तरीका है।

    बेशक यह समाधान हमेशा उपयुक्त नहीं है। कुछ विशेषताएं हैं जो ShowDialog() हमें देता है। सबसे उल्लेखनीय यह है कि यह मालिक को अक्षम करता है (लेकिन बाहर नहीं निकलता है) और उपयोगकर्ता इसके साथ बातचीत नहीं कर सकता है। बहुत थकाऊ जवाब प्रदान किया गया पी डैडी

  2. अनुकरण करना ShowDialog() व्यवहार

    उस मैथोड के व्यवहार को अनुकरण करना संभव है। फिर मैं पढ़ने की सलाह देते हैं पी डैडी का जवाब

    ए) उपयोग करें का संयोजन Enabled संपत्ति पर Form और फॉर्म को गैर-मोडल के रूप में दिखा रहा है Show()। नतीजतन अक्षम फॉर्म ग्रे हो जाएगा। लेकिन यह किसी भी इंटरऑप की आवश्यकता के बिना पूरी तरह से प्रबंधित समाधान है।

    ख) माता-पिता को भूरे रंग के रूप में पसंद नहीं करते हैं? संदर्भ कुछ देशी तरीकों और बंद करें WS_DISABLED पैरेंट फॉर्म पर थोड़ा सा (एक बार फिर से - जवाब देखें पी डैडी)।

    उन दो समाधानों की आवश्यकता है कि आपके पास संभालने के लिए आवश्यक सभी संवाद बॉक्स पर आपका पूरा नियंत्रण हो। आपको "आंशिक रूप से अवरुद्ध संवाद" दिखाने के लिए विशेष निर्माण का उपयोग करना होगा और इसके बारे में नहीं भूलना चाहिए। आपको अपने तर्क को समायोजित करने की आवश्यकता है क्योंकि Show() गैर-अवरुद्ध है और ShowDialog() अवरुद्ध है सिस्टम संवाद से निपटना (फ़ाइल चयनकर्ता, रंग पिकर इत्यादि) समस्या हो सकती है। दूसरी ओर आपको उन फॉर्मों पर कोई अतिरिक्त कोड की आवश्यकता नहीं है जिन्हें संवाद द्वारा अवरुद्ध नहीं किया जाएगा।

  3. की सीमाओं को खत्म करो ShowDialog()

    ध्यान दें कि वहाँ हैं Application.EnterThreadModal तथा Application.LeaveThreadModal आयोजन। जब भी मोडल संवाद दिखाया जाता है तो यह घटना उठाई जाती है। सावधान रहें कि घटनाएं वास्तव में थ्रेड-चौड़ी हैं, आवेदन-व्यापी नहीं।

    ए) सुनो Application.EnterThreadModal घटना रूपों में जो संवाद द्वारा अवरुद्ध नहीं किया जाएगा और चालू करो WS_DISABLED बिट उन रूपों में। आपको केवल उन फ़ॉर्म को समायोजित करने की आवश्यकता है जिन्हें मोडल संवाद द्वारा अवरुद्ध नहीं किया जाना चाहिए। आपको दिखाए जा रहे मोडल फॉर्म की पैरेंट-चेन का निरीक्षण करने और स्विच करने की भी आवश्यकता हो सकती है WS_DISABLED इस शर्त के आधार पर (आपके उदाहरण में यदि आपको फॉर्म ए और सी द्वारा संवाद खोलने की आवश्यकता है लेकिन फॉर्म बी और डी को अवरुद्ध नहीं करना है)।

    बी) फॉर्म छुपाएं और फिर से दिखाएं जिन्हें अवरुद्ध नहीं किया जाना चाहिए। ध्यान दें कि जब आप मॉडल संवाद दिखाए जाने के बाद नया फॉर्म दिखाते हैं तो यह अवरुद्ध नहीं होता है। इसका लाभ उठाएं और जब मोडल डायलॉग दिखाया जाए, तो वांछित रूपों को छुपाएं और दिखाएं ताकि वे अवरुद्ध न हों। हालांकि यह दृष्टिकोण कुछ झटकेदार ला सकता है। इसे विन एपीआई में फॉर्मों के पुनर्विक्रय को सक्षम / अक्षम करके सैद्धांतिक रूप से तय किया जा सकता है लेकिन मैं इसकी गारंटी नहीं देता हूं।

    सी) सेट करें Owner संवाद फार्म के लिए संपत्ति उन रूपों पर जिन्हें संवाद दिखाया जाता है जब अवरुद्ध नहीं किया जाना चाहिए। मैंने इसका परीक्षण नहीं किया।

    डी) एकाधिक जीयूआई धागे का प्रयोग करेंTheSmurf से जवाब


6
2018-01-20 15:18



बहुत अच्छा। मुझे लगता है कि यह सबसे अच्छा जवाब होना चाहिए। - Xan-Kun Clark-Davis


मैं बस अपना समाधान यहां जोड़ना चाहता था क्योंकि यह मेरे लिए अच्छा काम करता प्रतीत होता है, और इसे एक सरल विस्तार विधि में encapsulated किया जा सकता है। केवल एक चीज जो मुझे करने की ज़रूरत है वह फ्लैशिंग से निपटती है क्योंकि @ नाइटकोडर ने @ पीडीएडी के जवाब पर टिप्पणी की।

public static void ShowWithParentFormLock(this Form childForm, Form parentForm)
{
  childForm.ShowWithParentFormLock(parentForm, null);
}

public static void ShowWithParentFormLock(this Form childForm, Form parentForm, Action actionAfterClose)
{
  if (childForm == null)
    throw new ArgumentNullException("childForm");
  if (parentForm == null)
    throw new ArgumentNullException("parentForm");
  EventHandler activatedDelegate = (object sender, EventArgs e) =>
  {
    childForm.Focus();
    //To Do: Add ability to flash form to notify user that focus changed
  };
  childForm.FormClosed += (sender, closedEventArgs) =>
    {
      try
      {
        parentForm.Focus();
        if(actionAfterClose != null)
          actionAfterClose();
      }
      finally
      {
        try
        {
          parentForm.Activated -= activatedDelegate;
          if (!childForm.IsDisposed || !childForm.Disposing)
            childForm.Dispose();
        }
        catch { }
      }
    };
  parentForm.Activated += activatedDelegate;
  childForm.Show(parentForm);
}

4
2018-05-23 17:12



+1 साझा करने के लिए धन्यवाद!! तुमने सचमुच मेरा दिन बचाया !! - Anne
@ एनी मुझे लगता है कि आप वास्तव में +1 पर क्लिक करना भूल गए :) - Justin Pihony
घी, वह मूर्खतापूर्ण है, अब किया! :) - Anne
यह निकलता है, जब आप एक मूल रूप का चयन करने का प्रयास करते हैं तो एक बच्चा फॉर्म फ्लैश बनाने की आवश्यकता होती है parentForm.Enabled = false; से पहले childForm.Show(parentForm);। बस जोड़ने के लिए मत भूलना parentForm.Enabled = true; पहले और बादमे parentForm.Focus();। @JustinPihony, आपके समाधान के लिए धन्यवाद, सरल और प्रभावी। - Korli


फॉर्मए में एक नए धागे में फॉर्मबी शुरू करें:

        (new System.Threading.Thread(()=> {
            (new FormB()).Show();
        })).Start();

अब, ShowDialog () का उपयोग करके नए धागे में खोले गए किसी भी फॉर्म केवल फॉर्मबी को ब्लॉक करेंगे और फॉर्म फॉर्म या फॉर्मसी को ब्लॉक नहीं करेंगे


3
2018-01-09 16:12





मैं जिस एप्लिकेशन को लिख रहा था उसमें मुझे एक ही समस्या का सामना करना पड़ रहा था। मेरा मुख्य यूआई मुख्य धागे पर चल रहा एक फॉर्म था। मेरे पास एक मदद संवाद था जिसे मैं एक मॉडलस संवाद के रूप में चलाने के लिए चाहता था। यह कार्यान्वित करना आसान था, यहां तक ​​कि यह सुनिश्चित करने के बिंदु पर कि मेरे पास कभी भी सहायता संवाद का एक उदाहरण था। दुर्भाग्यवश, मेरे द्वारा उपयोग किए जाने वाले किसी भी मॉडल संवाद ने फोकस को खोने के लिए सहायता संवाद का कारण बना दिया - जब यह था कि इनमें से कुछ मोडल संवाद चल रहे थे, जिसमें सहायता संवाद था, वहां सबसे उपयोगी होगा।

यहां उल्लिखित विचारों का उपयोग करके, और अन्य स्थानों पर, मैं इस बग को दूर करने में कामयाब रहा।

मैंने अपने मुख्य यूआई के अंदर एक धागा घोषित किया।

Thread helpThread;

निम्न कोड सहायता संवाद को खोलने के लिए निकाल दिए गए ईवेंट से संबंधित है।

private void Help(object sender, EventArgs e)
{
    //if help dialog is still open then thread is still running
    //if not, we need to recreate the thread and start it again
    if (helpThread.ThreadState != ThreadState.Running)
    {
        helpThread = new Thread(new ThreadStart(startHelpThread));
        helpThread.SetApartmentState(ApartmentState.STA);
        helpThread.Start();
    }
}

void startHelpThread()
{
    using (HelpDialog newHelp = new HelpDialog(resources))
    {
        newHelp.ShowDialog();
    }
}

मुझे यह सुनिश्चित करने के लिए कि मैं इस कोड को चलाने के लिए पहली बार एक नल ऑब्जेक्ट का संदर्भ नहीं दे रहा था, मेरे कन्स्ट्रक्टर में जोड़े गए धागे की शुरुआत की भी आवश्यकता थी।

public MainWindow()
{
    ...
    helpThread = new Thread(new ThreadStart(startHelpThread));
    helpThread.SetApartmentState(ApartmentState.STA);
    ...
}

यह सुनिश्चित करता है कि किसी भी समय थ्रेड में केवल एक उदाहरण होगा। धागा स्वयं संवाद चलाता है, और संवाद बंद होने के बाद बंद हो जाता है। चूंकि यह एक अलग धागे पर चलता है, मुख्य यूआई के भीतर से एक मोडल संवाद बनाने से मदद संवाद लटका नहीं जाता है। मुझे जोड़ने की ज़रूरत थी

helpDialog.Abort();

यह सुनिश्चित करने के लिए कि मेरे द्वारा समाप्त किए जाने पर सहायता संवाद बंद हो जाता है, यह सुनिश्चित करने के लिए मेरे मुख्य यूआई के फॉर्म को बंद करने के लिए फॉर्म।

अब मेरे पास एक मॉडलस हेल्प डायलॉग है जो मेरे मुख्य यूआई के भीतर से उत्पन्न किसी भी मोडल डायलॉग से प्रभावित नहीं है, जो वही है जो मैं चाहता था। यह सुरक्षित है क्योंकि मुख्य यूआई और सहायता संवाद के बीच कोई संचार की आवश्यकता नहीं है।


2
2018-03-29 01:59





इस प्रश्न के कुछ उत्तरों के आधार पर गैर संवाद विंडो को अवरुद्ध करने से संवाद को रोकने के लिए मैं WPF में उपयोग कर रहा हूं सहायक:

public static class WindowHelper
{
    public static bool? ShowDialogNonBlocking(this Window window)
    {
        var frame = new DispatcherFrame();

        void closeHandler(object sender, EventArgs args)
        {
            frame.Continue = false;
        }

        try
        {
            window.Owner.SetNativeEnabled(false);
            window.Closed += closeHandler;
            window.Show();

            Dispatcher.PushFrame(frame);
        }
        finally
        {
            window.Closed -= closeHandler;
            window.Owner.SetNativeEnabled(true);
        }
        return window.DialogResult;
    }

    const int GWL_STYLE = -16;
    const int WS_DISABLED = 0x08000000;

    [DllImport("user32.dll")]
    static extern int GetWindowLong(IntPtr hWnd, int nIndex);

    [DllImport("user32.dll")]
    static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

    static void SetNativeEnabled(this Window window, bool enabled)
    {
        var handle = new WindowInteropHelper(window).Handle;
        SetWindowLong(handle, GWL_STYLE, GetWindowLong(handle, GWL_STYLE) &
            ~WS_DISABLED | (enabled ? 0 : WS_DISABLED));
    }
}

उपयोग:

if(true == window.ShowDialogNonBlocking())
{
    // Dialog result has correct value
}

2
2018-03-16 07:10





उदाहरण का उपयोग करना:

(new NoneBlockingDialog((new frmDialog()))).ShowDialogNoneBlock(this);

सोर्स कोड:

class NoneBlockingDialog
{
    Form dialog;
    Form Owner;

    public NoneBlockingDialog(Form f)
    {
        this.dialog = f;
        this.dialog.FormClosing += new FormClosingEventHandler(f_FormClosing);
    }

    void f_FormClosing(object sender, FormClosingEventArgs e)
    {
        if(! e.Cancel)
            PUtils.SetNativeEnabled(this.Owner.Handle, true);
    }

    public void ShowDialogNoneBlock(Form owner)
    {
        this.Owner = owner;
        PUtils.SetNativeEnabled(owner.Handle, false);
        this.dialog.Show(owner);
    }
}

partial class PUtils
{
            const int GWL_STYLE = -16;
    const int WS_DISABLED = 0x08000000;


    [DllImport("user32.dll")]
    static extern int GetWindowLong(IntPtr hWnd, int nIndex);


    [DllImport("user32.dll")]
    static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);


    static public void SetNativeEnabled(IntPtr hWnd, bool enabled)
    {
        SetWindowLong(hWnd, GWL_STYLE, GetWindowLong(hWnd, GWL_STYLE) & ~WS_DISABLED | (enabled ? 0 : WS_DISABLED));
    }
}

0
2018-03-22 14:23





शायद एक बच्चा खिड़की (देखें ChildWindow विवरण के लिए) एक और अधिक सुरुचिपूर्ण समाधान होगा, और यह जीयूआई के लिए अलग-अलग धागे के साथ सभी समस्याओं से बच जाएगा।


0
2017-12-29 11:31