फ़ोकस चुराने के बिना कोई फ़ॉर्म दिखाएं?


140

मैं सूचनाओं को दिखाने के लिए एक फॉर्म का उपयोग कर रहा हूं (यह स्क्रीन के नीचे दाईं ओर दिखाई देता है), लेकिन जब मैं इस फॉर्म को दिखाता हूं तो यह मुख्य फॉर्म से फोकस चुरा लेता है। क्या ध्यान केंद्रित किए बिना इस "अधिसूचना" फॉर्म को दिखाने का कोई तरीका है?

जवाबों:


165

हम्म, बस फॉर्म को ओवरराइड नहीं कर रहा है।

protected override bool ShowWithoutActivation
{
  get { return true; }
}

और यदि आप नहीं चाहते कि उपयोगकर्ता इस अधिसूचना विंडो पर क्लिक करें, तो आप CreateParams को ओवरराइड कर सकते हैं:

protected override CreateParams CreateParams
{
  get
  {
    CreateParams baseParams = base.CreateParams;

    const int WS_EX_NOACTIVATE = 0x08000000;
    const int WS_EX_TOOLWINDOW = 0x00000080;
    baseParams.ExStyle |= ( int )( WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW );

    return baseParams;
  }
}

3
ShowWithoutActivation, विश्वास नहीं कर सकता कि मुझे यह नहीं मिला, एक पूरी दोपहर बर्बाद कर दी!
deerchao

2
मुझे form1.Enabled = falseआंतरिक नियंत्रण पर ध्यान केंद्रित करने से रोकने के लिए सेट करने की भी आवश्यकता थी
Jader Dias

23
और टॉपमोस्ट को छोड़ दें।
मैकलिन

4
और यदि आप TopMost चाहते हैं, तो अन्य उत्तर देखें ।
रोमन स्टार्कोव

2
के मूल्यों WS_EX_NOACTIVATEऔर WS_EX_TOOLWINDOWकर रहे हैं 0x08000000और 0x00000080क्रमशः।
जुआन

69

PInvoke.net की ShowWindow विधि से चोरी :

private const int SW_SHOWNOACTIVATE = 4;
private const int HWND_TOPMOST = -1;
private const uint SWP_NOACTIVATE = 0x0010;

[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
static extern bool SetWindowPos(
     int hWnd,             // Window handle
     int hWndInsertAfter,  // Placement-order handle
     int X,                // Horizontal position
     int Y,                // Vertical position
     int cx,               // Width
     int cy,               // Height
     uint uFlags);         // Window positioning flags

[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

static void ShowInactiveTopmost(Form frm)
{
     ShowWindow(frm.Handle, SW_SHOWNOACTIVATE);
     SetWindowPos(frm.Handle.ToInt32(), HWND_TOPMOST,
     frm.Left, frm.Top, frm.Width, frm.Height,
     SWP_NOACTIVATE);
}

(एलेक्स लाइमन ने इसका उत्तर दिया, मैं सीधे कोड को पेस्ट करके इसका विस्तार कर रहा हूं। संपादित अधिकारों वाले कोई व्यक्ति इसे वहां पर कॉपी कर सकता है और मैं इसे सभी देखभाल के लिए हटा सकता हूं;)


मैं सोच रहा था, क्या उसे वास्तव में ज़रूरत है कि अगर वह अपनी स्क्रीन के निचले बाएँ में प्रदर्शित करता है तो यह एक दूसरे धागे में है?
पैट्रिक डेसजार्डिन्स

50
मुझे यह अविश्वसनीय लगता है कि हमें अभी भी रूपों के साथ बातचीत करने के लिए बाहरी DLL फ़ाइलों से लिंक करने की आवश्यकता है। हम .NET फ्रेमवर्क संस्करण 4 पर हैं !! इसे लपेटने का समय Microsoft।
मल्ट्रैप

9
स्वीकृत उत्तर गलत है। ShowWithoutActivation के लिए देखो
mklein

बस frm.Hide जोड़ें (); ShowInactiveTopmost फ़ंक्शन की शुरुआत में यदि आप चाहते हैं कि आपका फ़ॉर्म सीधे अप्रमाणित हो। मत भूलना: System.Runtime.InteropServices का उपयोग करना; इस कोड को बनाने के लिए
Zitun

1
@ ताल इस कोड का लोड घटना से कोई लेना देना नहीं है। लोड घटना आग लग जाती है जब फ़ॉर्म लोड किया जा रहा है, न कि जब यह दिखाया जा रहा है।
theSoftwareJedi

14

यदि आप Win32 P / Invoke का उपयोग करने के लिए तैयार हैं , तो आप ShowWindow विधि का उपयोग कर सकते हैं (पहला कोड नमूना वही करता है जो आप चाहते हैं)।


12

इसी से मेरा काम बना है। यह टॉपमोस्ट प्रदान करता है लेकिन फ़ोकस-चोरी के बिना।

    protected override bool ShowWithoutActivation
    {
       get { return true; }
    }

    private const int WS_EX_TOPMOST = 0x00000008;
    protected override CreateParams CreateParams
    {
       get
       {
          CreateParams createParams = base.CreateParams;
          createParams.ExStyle |= WS_EX_TOPMOST;
          return createParams;
       }
    }

दृश्य स्टूडियो डिजाइनर, या कहीं और में TopMost सेटिंग को छोड़ना याद रखें।

यह चोरी, गलती, उधार, यहाँ से (Workarounds पर क्लिक करें):

https://connect.microsoft.com/VisualStudio/feedback/details/401311/showwithoutactivation-is-not-supported-with-topmost


1
सबसे ऊपर + अनफोकस्ड काम करता है, और यह सभी उत्तरों में सबसे साफ दिखता है।
फोस

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

9

ऐसा करना एक हैक की तरह लगता है, लेकिन यह काम करने लगता है:

this.TopMost = true;  // as a result the form gets thrown to the front
this.TopMost = false; // but we don't actually want our form to always be on top

संपादित करें: ध्यान दें, यह केवल ध्यान केंद्रित किए बिना पहले से ही बनाए गए फॉर्म को बढ़ाता है।


लगता है यहाँ काम नहीं करता ... हो सकता है क्योंकि यह "अधिसूचित फ़ॉर्म" दूसरे धागे में खोला गया है?
मटियास

1
संभवतः, उस स्थिति में आपको यह करने की आवश्यकता है। इंवोक () कॉल को सही थ्रेड के रूप में फिर से कॉल करने के लिए। आमतौर पर गलत थ्रेड के रूपों के साथ काम करने पर अपवाद को फेंक दिया जाता है।
मैथ्यू शार्ले

हालांकि यह काम करता है, यह उल्लेखित विधि है और कुछ शर्तों के तहत मेरे लिए बीएसओडी का कारण है, इसलिए इससे सावधान रहें।
राफेल स्मिट

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

9

Alex Lyman / TheSoftwareJedi के उत्तरों में pinvoke.net का नमूना कोड खिड़की को "सबसे ऊपरी" विंडो बना देगा, जिसका अर्थ है कि आप इसे पॉप अप करने के बाद सामान्य खिड़कियों के पीछे नहीं रख सकते। माटिया के विवरण को देखते हुए कि वह इसके लिए क्या उपयोग करना चाहता है, वही हो सकता है जो वह चाहता है। लेकिन अगर आप चाहते हैं कि आपके द्वारा इसे पॉप अप करने के बाद उपयोगकर्ता आपकी विंडो को अन्य विंडो के पीछे रख सके, तो नमूने में केवल HWND_TOPMOST (-1) के बजाय HWND_TOP (0) का उपयोग करें।


6

WPF में आप इसे इस तरह से हल कर सकते हैं:

विंडो में ये विशेषताएँ डालें:

<Window
    x:Class="myApplication.winNotification"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Title="Notification Popup" Width="300" SizeToContent="Height"
  WindowStyle="None" AllowsTransparency="True" Background="Transparent" ShowInTaskbar="False" Topmost="True" Focusable="False" ShowActivated="False" >
</Window>

अंतिम एक विशेषता वह है जिसे आपको ShowActivated = "गलत" की आवश्यकता है।


4

मेरे पास कुछ ऐसा ही है, और मैं केवल अधिसूचना फॉर्म दिखाता हूं और फिर करता हूं

this.Focus();

मुख्य रूप पर ध्यान वापस लाने के लिए।


सामान्य लेकिन प्रभावी!
टॉम

3

नोटिफिकेशन फॉर्म को एक अलग थ्रेड में बनाएँ और शुरू करें और फॉर्म खुलने के बाद फ़ोकस को वापस अपने मुख्य फॉर्म में रीसेट करें। नोटिफिकेशन फॉर्म में एक OnFormOpened ईवेंट प्रदान करें जो इवेंट से निकाल दिया गया है Form.Shown। कुछ इस तरह:

private void StartNotfication()
{
  Thread th = new Thread(new ThreadStart(delegate
  {
    NotificationForm frm = new NotificationForm();
    frm.OnFormOpen += NotificationOpened;
    frm.ShowDialog();
  }));
  th.Name = "NotificationForm";
  th.Start();
} 

private void NotificationOpened()
{
   this.Focus(); // Put focus back on the original calling Form
}

आप अपने NotifcationForm ऑब्जेक्ट के चारों ओर एक हैंडल भी रख सकते हैं ताकि इसे मुख्य रूप ( frm.Close()) द्वारा प्रोग्रामेटिक रूप से बंद किया जा सके ।

कुछ विवरण गायब हैं, लेकिन उम्मीद है कि यह आपको सही दिशा में जा रहा है।


यह केवल तभी काम करेगा जब आपका फॉर्म मूल रूप से सक्रिय रूप था। इस तरह का नोटिफिकेशन इस तरह के मुख्य उद्देश्य के खिलाफ जाता है।
एलेक्स लिमैन

1
है ना? यह अधिसूचना का उद्देश्य है - इसे लागू करना और मूल रूप से सक्रिय रूप में वापस ध्यान केंद्रित करना।
बॉब नडलर

2
यह केवल आपके आवेदन में एक फॉर्म पर ध्यान केंद्रित करता है - क्या होगा यदि कोई अन्य कार्यक्रम उस समय सक्रिय है? सूचना विंडो दिखाना (आमतौर पर उपयोगकर्ता को आपके एप्लिकेशन की स्थिति पर अपडेट देने के लिए) केवल तब ही उपयोगी होता है जब वे आपके एप्लिकेशन को नहीं देख रहे हों।
एलेक्स लीमैन

3

आप इस पर विचार करना चाहते हैं कि आप किस प्रकार की अधिसूचना प्रदर्शित करना चाहते हैं।

यदि उपयोगकर्ता को किसी घटना के बारे में बताने के लिए यह पूरी तरह से महत्वपूर्ण है, तो Messagebox.Show का उपयोग अनुशंसित तरीका होगा, इसकी प्रकृति के कारण किसी भी अन्य घटनाओं को मुख्य विंडो पर ब्लॉक करने के लिए, जब तक उपयोगकर्ता इसकी पुष्टि नहीं करता। हालांकि पॉप-अप ब्लाइंडनेस से अवगत रहें।

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


2
- बैलून टिप्स एक विकल्प नहीं है क्योंकि इसे निष्क्रिय किया जा सकता है - स्टेटबार को छिपाया जा सकता है यदि आपके पास कार्यक्रम को अपने पुनर्संबंधों के लिए वैसे भी धन्यवाद कम से कम हो
Matías

3

यह अच्छा काम करता है।

देखें: OpenIcon - MSDN और SetForegroundWindow - MSDN

using System.Runtime.InteropServices;

[DllImport("user32.dll")]
static extern bool OpenIcon(IntPtr hWnd);

[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);

public static void ActivateInstance()
{
    IntPtr hWnd = IntPtr hWnd = Process.GetCurrentProcess().MainWindowHandle;

    // Restore the program.
    bool result = OpenIcon(hWnd); 
    // Activate the application.
    result = SetForegroundWindow(hWnd);

    // End the current instance of the application.
    //System.Environment.Exit(0);    
}

1

आप इसे अकेले तर्क द्वारा भी संभाल सकते हैं, हालांकि मुझे यह स्वीकार करना होगा कि ऊपर दिए गए सुझाव जहां आप लाते हैं, वहां पर बिना फोकस के चोरी करने के लिए लाया गया एक तरीका है।

किसी भी तरह, मैं इस में भाग गया और इसे पहले से ही हाल ही में किए गए कॉल को आगे लाने के लिए DateToFront कॉल की अनुमति न देने के लिए डेटटाइम प्रॉपर्टी का उपयोग करके हल किया।

एक कोर क्लास मान लीजिए, 'कोर', जो उदाहरण के लिए तीन रूपों को संभालता है, 'फॉर्म 1, 2 और 3'। प्रत्येक फॉर्म को एक डेटटाइम प्रॉपर्टी और एक सक्रिय घटना की आवश्यकता होती है जो विंडोज़ को सामने लाने के लिए कोर कहते हैं:

internal static DateTime LastBringToFrontTime { get; set; }

private void Form1_Activated(object sender, EventArgs e)
{
    var eventTime = DateTime.Now;
    if ((eventTime - LastBringToFrontTime).TotalMilliseconds > 500)
        Core.BringAllToFront(this);
    LastBringToFrontTime = eventTime;
}

और फिर कोर क्लास में काम बनाएँ:

internal static void BringAllToFront(Form inForm)
{
    Form1.BringToFront();
    Form2.BringToFront();
    Form3.BringToFront();
    inForm.Focus();
}

साइड नोट पर, यदि आप एक न्यूनतम विंडो को उसकी मूल स्थिति (अधिकतम नहीं) पर पुनर्स्थापित करना चाहते हैं, तो उपयोग करें:

inForm.WindowState = FormWindowState.Normal;

फिर से, मुझे पता है कि यह एक SendToFrontWithoutFocus की कमी में सिर्फ एक पैच समाधान है। यह एक सुझाव के रूप में है यदि आप DLL फ़ाइल से बचना चाहते हैं।


1

मुझे नहीं पता कि इसे नेक्रो-पोस्टिंग के रूप में माना जाता है, लेकिन यह वही है जो मैंने तब से किया है जब मैंने इसे उपयोगकर्ता के "शोविंडो" और "सेटविंडो पोस" विधियों के साथ काम करने के लिए नहीं दिया। और नहीं, "ShowWithoutActivation" को ओवरराइड करने से इस मामले में काम नहीं होता है क्योंकि नई विंडो हमेशा ऑन-टॉप होनी चाहिए। वैसे भी, मैंने एक सहायक विधि बनाई जो पैरामीटर के रूप में एक रूप लेती है; जब बुलाया जाता है, तो यह प्रपत्र दिखाता है, इसे सामने लाता है और वर्तमान विंडो के फोकस को चुराने के बिना इसे TopMost बनाता है (जाहिर है यह करता है, लेकिन उपयोगकर्ता ध्यान नहीं देगा)।

    [DllImport("user32.dll")]
    static extern IntPtr GetForegroundWindow();

    [DllImport("user32.dll")]
    static extern IntPtr SetForegroundWindow(IntPtr hWnd);

    public static void ShowTopmostNoFocus(Form f)
    {
        IntPtr activeWin = GetForegroundWindow();

        f.Show();
        f.BringToFront();
        f.TopMost = true;

        if (activeWin.ToInt32() > 0)
        {
            SetForegroundWindow(activeWin);
        }
    }

0

मुझे पता है कि यह बेवकूफ लग सकता है, लेकिन यह काम किया:

this.TopMost = true;
this.TopMost = false;
this.TopMost = true;
this.SendToBack();

यदि आप सामने की खिड़की को पीछे भेजते हैं, तो यह अब दिखाई नहीं दे सकता है यदि पृष्ठभूमि खिड़कियां नए अग्रभूमि को ओवरलैप करती हैं।
TamusJRoyce

0

मुझे अपनी खिड़की TopMost के साथ ऐसा करने की आवश्यकता थी। मैंने ऊपर PInvoke मेथड लागू किया, लेकिन पाया कि मेरे लोड इवेंट को तलहा की तरह नहीं बुलाया जा रहा था। मैं आखिरकार सफल हुआ। शायद यह किसी की मदद करेगा। यहाँ मेरा समाधान है:

        form.Visible = false;
        form.TopMost = false;
        ShowWindow(form.Handle, ShowNoActivate);
        SetWindowPos(form.Handle, HWND_TOPMOST,
            form.Left, form.Top, form.Width, form.Height,
            NoActivate);
        form.Visible = true;    //So that Load event happens

-4

जब आप एक नया फॉर्म बनाते हैं

Form f = new Form();
f.ShowDialog();

यह फ़ोकस चुराता है क्योंकि आपका कोड मुख्य फ़ॉर्म पर निष्पादन जारी नहीं रख सकता है जब तक कि यह फ़ॉर्म बंद न हो।

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


हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.