-1

I need to show form that will be always on a top level.
I use TopMost and TopLevel flags and call Activate method after Show. But another window might steal Activate flag.

How I can fix it so that after creating a window, other windows cannot become active until this window is closed?

upd: it work only if execute app from output folder and don't work if run app with debug from IDE.

  • " other windows cannot become active " are you talking about other forms that your programm will open? or other programms in general as well? – Mong Zhu Dec 21 '20 at 13:07
  • @MongZhu other program. Or user can click in another program and my form lost focus. – Igor Lukashenya Dec 21 '20 at 13:37
  • Use "ShowDialog" instead of "Show". – Tu deschizi eu inchid Dec 21 '20 at 13:41
  • Look for "kiosk mode" (I haven't used it myself, it may not be entirely trivial. Mostly involves setting up a user with special policies) – KekuSemau Dec 21 '20 at 13:48
  • @user9938 `ShowDialog` block application and messages. I can't use it. – Igor Lukashenya Dec 21 '20 at 13:52
  • @KekuSemau could you share link about it? – Igor Lukashenya Dec 21 '20 at 13:52
  • [Microsoft-Page](https://learn.microsoft.com/en-us/windows/configuration/kiosk-methods), but I don't even know if it works with a winforms application. – KekuSemau Dec 21 '20 at 13:59
  • @KekuSemau thanks, but we can't change customers pc settings. – Igor Lukashenya Dec 21 '20 at 14:17
  • 1
    You can't change customers pc settings, but you want to prevent them reaching other windows on their own system?! What are you writing here?... – Idle_Mind Dec 21 '20 at 16:26
  • @Idle_Mind I don't want to prevent them reaching other windows. I want that my form have active flag on the start. You can try it if create simple app with button with will show new form. Build it and execute from output folder. After button click you need fast click on another program and your new form will showed without active flag even you call `Active` method after `Show`. – Igor Lukashenya Dec 21 '20 at 17:02
  • "After button click you need fast click on another program and your new form will showed without active flag even you call Active method after Show" Sure, because the user switched apps by their choice, so your app is no longer the "active one". How are you determining "active" state for your app? – Idle_Mind Dec 21 '20 at 17:07
  • 2
    The standard problem here is, what if I wrote the same program? Who wins? Windows prevents that from happening. You will have to think of a different solution. – LarsTech Dec 21 '20 at 17:12
  • @LarsTech our customers required this form from another application that integrated with our app. They want they want that form will be active, and close when they click outside form. – Igor Lukashenya Dec 21 '20 at 19:54
  • @Idle_Mind I tried to use different ways: methods from user32.dll (as `SetActiveWindow`, `SetCapture`, `SetForegroundWindow` and etc), override process messages in my form for skip no active messages, handle all standards events for keep activation, add timer with sort interval for force activate window. But nothing help me. – Igor Lukashenya Dec 21 '20 at 19:58
  • 1
    That information should be in your question. – LarsTech Dec 21 '20 at 19:59
  • @LarsTech I update question when will be sure that all ways really can't help me. – Igor Lukashenya Dec 21 '20 at 20:03
  • See [Is it possible to keep a Form on top of another, but not TopMost?](https://stackoverflow.com/a/45901729/719186) – LarsTech Dec 21 '20 at 20:09

2 Answers2

1

The following code will open a form (TestForm) when the program is started. TestForm contains a button, that when clicked, will create a new form (a new instance of TestForm in the code below, but it could be a different form, if desired)--which won't be visible until the current form is closed. When the current form is closed, the new form will become visible and the original form will be disposed.

Try the following to see if it gives you the desired result:

Create a new class (TestFormEventArgs)

  • In Visual Studio menu, click Project
  • Select Add New Item
  • Select Class (Name: TestFormEventArgs.cs)
  • Click Add

TestFormEventArgs.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Activate2ndFormWhen1stFormCloses
{
    public delegate void TestFormNewFormRequestedEventHandler(object sender, TestFormEventArgs e);

    public class TestFormEventArgs : System.EventArgs
    {
        public int CurrentFormNumber { get; private set; } = 1;
        public TestForm Frm { get; private set; } = null;
        public TestFormEventArgs(TestForm frm, int currentFormNumber)
        {
            this.Frm = frm;
            this.CurrentFormNumber = currentFormNumber;
        }
    }
}

Create a new Form (TestForm)

  • In Visual Studio menu, click Project
  • Select Add New Item
  • Select Form (Windows Forms) (Name: TestForm.cs)
  • Click Add

Add button to TestForm (btnOpenNewForm)

  • In Visual Studio menu, click View
  • Select Toolbox
  • Click Button
  • Drag mouse over the top of TestForm, and click the mouse to add the button to TestForm
  • In Visual Studio menu, click View
  • Select Properties Window
  • Click the button on the form
  • In the Properties Window, set the following properties: (Name): btnOpenNewForm; Text: Open New Form
  • On TestForm, double-click btnOpenNewForm which will create btnOpenNewForm_Click event handler.

Double-click TestForm to go to the code. Modify the code for TestForm.cs:

TestForm.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Activate2ndFormWhen1stFormCloses
{
    public partial class TestForm : Form
    {
        public event TestFormNewFormRequestedEventHandler NewFormRequested;

        private int _currentFormNumber = 1;
        TestForm _frmOther = null;


        public TestForm()
        {
            InitializeComponent();

            //set value
            this.Text = "TestForm 1";
        }

        public TestForm(string frmText, int currentFormNumber)
        {
            InitializeComponent();

            //set value
            this.Text = frmText;
            this._currentFormNumber = currentFormNumber;
        }
       

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void SendUpdates(TestForm frm, int currentFormNumber)
        {
            //check if there are subscribers
            if (NewFormRequested != null)
            {
                //create a new instance of TestFormEventArgs
                TestFormEventArgs valueArgs = new TestFormEventArgs(frm, currentFormNumber);

                //raise event
                NewFormRequested(this, valueArgs);
            }//if
        }

        private void btnOpenNewForm_Click(object sender, EventArgs e)
        {
           
            string frmText = String.Format("TestForm {0}", _currentFormNumber + 1);

            //create new instance
            _frmOther = new TestForm(frmText, _currentFormNumber + 1);

            //set properties
            _frmOther.StartPosition = FormStartPosition.CenterScreen;
            _frmOther.Visible = false;

            SendUpdates(_frmOther, _currentFormNumber);

        }     
    }
}

Change Program.cs code to the following:

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;

namespace Activate2ndFormWhen1stFormCloses
{
    static class Program
    {
        static TestForm _currentFrm = null;
        static Queue<TestForm> _frmQ = new Queue<TestForm>();

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            //place form in Queue
            _frmQ.Enqueue(new TestForm());


            while(_frmQ.Count > 0)
            {

                //dequeue
                _currentFrm = _frmQ.Dequeue();

                //subscribe to events
                _currentFrm.FormClosed += CurrentFrm_FormClosed;
                _currentFrm.NewFormRequested += CurrentFrm_NewFormRequested;

                Application.Run(_currentFrm);
            }  
        }

        private static void CurrentFrm_NewFormRequested(object sender, TestFormEventArgs e)
        {
            Debug.WriteLine("CurrentFrm_NewFormRequested: " + e.Frm.Text);

            //add form to Queue
            _frmQ.Enqueue(e.Frm);
        }

        private static void CurrentFrm_FormClosed(object sender, FormClosedEventArgs e)
        {
            TestForm frm = (TestForm)sender;
            Debug.WriteLine("CurrentFrm_FormClosed: " + frm.Text);

            try
            {
                //unsubscribe from events
                _currentFrm.FormClosed -= CurrentFrm_FormClosed;
                _currentFrm.NewFormRequested -= CurrentFrm_NewFormRequested;

                _currentFrm.Dispose();
                _currentFrm = null;
            }
            catch(Exception ex)
            {
                Debug.WriteLine("Error: " + ex.Message);
            }
        }
    }
}
Tu deschizi eu inchid
  • 4,117
  • 3
  • 13
  • 24
0

Try ShowDialog() instead of Show() method.

ShowDialog() will make the other form that is open Disabled and the current form is the only one that is Enabled.

Andrei Solero
  • 802
  • 1
  • 4
  • 12