Way to quickly show/hide WinForms GUI C# - c#

I'm creating an app that is threaded. I started GUI (Announce : Form) as separate thread.
That window will be very minimalistic with one input box and maybe a button. On another thread there will be Tcp Client running and when it gets info from TcpServer it should pass what it gets into that inputbox and show the gui (and topmost windows). After couple of seconds the gui should hide itself and wait for another tcp msg and so on.
public void setTextBox(string varText) {
if (InvokeRequired) {
textBox.BeginInvoke(new textBoxCallBack(setTextBox), new object[] {varText});
} else {
textBox.Text = varText;
}
}
This code is used to fill the textBox from the Tcp Thread. The only problem now is getting the window show and hide properly. Been trying many solutions and always something went wrong. Like:
private void windowStateChange(string varState) {
if (InvokeRequired) {
Invoke(new WindowStateChangeCallBack(windowStateChange), new object[] {varState});
} else {
if (varState == "Hide") {
//Hide();
// TopMost = false;
//TopMost = varState != FormWindowState.Minimized;
} else {
//Show();
//MessageBox.Show("TEST1");
}
}
}
public void windowStateChangeDiffrent(FormWindowState varState) {
if (InvokeRequired) {
Invoke(new WindowStateChangeCallBack(windowStateChange), new object[] {varState});
} else {
WindowState = varState;
// Hide();
TopMost = varState != FormWindowState.Minimized;
}
}
What would be best aproach to do this (and fastest, as time matters)?
Answer 1 which seems to work:
private static void windowStateChange(string varState) {
if (mainAnnounceWindow.InvokeRequired) {
mainAnnounceWindow.BeginInvoke(new StateCallBack(windowStateChange), new object[] {varState});
} else {
if (varState == "Hide") {
mainAnnounceWindow.Hide();
mainAnnounceWindow.TopMost = false;
} else {
mainAnnounceWindow.Show();
mainAnnounceWindow.TopMost = true;
}
}
}
Anything bad about it?

Making the form hide with form.Hide() should pose no problems.
However I've experienced making the form show again does not always work.
So if you're encountering the same problem, you could use something like this:
string RunningProcess = Process.GetCurrentProcess().ProcessName;
Process[] processes = Process.GetProcessesByName(RunningProcess);
int SW_SHOW = 5, SW_HIDE = 0, SW_RESTORE = 9, SW_SHOWNORMAL = 1;
for (int a = 0; a < processes.Length; a++)
{
IntPtr hWnd = processes[a].MainWindowHandle;
ShowWindowAsync(hWnd, SW_RESTORE);
ShowWindowAsync(hWnd, SW_SHOWNORMAL);
ShowWindowAsync(hWnd, SW_SHOW);
SetForegroundWindow((int)hWnd);
}
//Required Win32 API imports
[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
static extern bool ShowWindowAsync(IntPtr windowHandle, int cmd);
[System.Runtime.InteropServices.DllImportAttribute("User32.dll")]
private static extern IntPtr SetForegroundWindow(int hWnd);

you might try
form.Hide();
but make sure that you show/hide the form from the same thread that created them

this.Invoke(new MethodInvoker(this.hide()));

Another approach would be to expose events on your TCP thread object. It could define an event such as RecievedData(...) then the GUI could subscribe to that event and update itself without having to do any InvokeRequired checks etc.
Update: link to C# events tutorial
http://msdn.microsoft.com/en-us/library/aa645739%28VS.71%29.aspx

Form.Hide() is the right method to hide the form. I remember having issues with Form.Show(), I have a vague memory of having to use Form.Activate() as well to get the form to restore correctly.
You're already dealing with thread marshalling correctly (InvokeRequired and Invoke). You could also use Form.BeginInvoke(), which is an async version of Form.Invoke. That might be faster.

Related

Application.UseWaitCursor is delayed sometimes [duplicate]

Is there a difference between Cursor.Current and this.Cursor (where this is a WinForm) in .Net? I've always used this.Cursor and have had very good luck with it but I've recently started using CodeRush and just embedded some code in a "Wait Cursor" block and CodeRush used the Cursor.Current property. I've seen on the Internet and at work where other programmers have had some problems with the Cursor.Current property. It just got me to wondering if there is a difference in the two. Thanks in advance.
I did a little test. I have two winforms. I click a button on form1, set the Cursor.Current property to Cursors.WaitCursor and then show form2. The cursor doesn't change on either form. It remains Cursors.Default (pointer) cursor.
If I set this.Cursor to Cursors.WaitCursor in the button click event on form1 and show form2, the wait cursor only shows on form1 and the default cursor is on form2 which is expected. So, I still don't know what Cursor.Current does.
Windows sends the window that contains the mouse cursor the WM_SETCURSOR message, giving it an opportunity to change the cursor shape. A control like TextBox takes advantage of that, changing the cursor into a I-bar. The Control.Cursor property determines what shape will be used.
The Cursor.Current property changes the shape directly, without waiting for a WM_SETCURSOR response. In most cases, that shape is unlikely to survive for long. As soon as the user moves the mouse, WM_SETCURSOR changes it back to Control.Cursor.
The UseWaitCursor property was added in .NET 2.0 to make it easier to display an hourglass. Unfortunately, it doesn't work very well. It requires a WM_SETCURSOR message to change the shape and that won't happen when you set the property to true and then do something that takes a while. Try this code for example:
private void button1_Click(object sender, EventArgs e) {
this.UseWaitCursor = true;
System.Threading.Thread.Sleep(3000);
this.UseWaitCursor = false;
}
The cursor never changes. To whack that into shape, you'll need to use Cursor.Current as well. Here is a little helper class to make it easy:
using System;
using System.Windows.Forms;
public class HourGlass : IDisposable {
public HourGlass() {
Enabled = true;
}
public void Dispose() {
Enabled = false;
}
public static bool Enabled {
get { return Application.UseWaitCursor; }
set {
if (value == Application.UseWaitCursor) return;
Application.UseWaitCursor = value;
Form f = Form.ActiveForm;
if (f != null && f.Handle != IntPtr.Zero) // Send WM_SETCURSOR
SendMessage(f.Handle, 0x20, f.Handle, (IntPtr)1);
}
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
}
And use it like this:
private void button1_Click(object sender, EventArgs e) {
using (new HourGlass()) {
System.Threading.Thread.Sleep(3000);
}
}
I believe that Cursor.Current is the mouse cursor currently being used (regardless of where it is on the screen), while this.Cursor is the cursor it will be set to, when the mouse passes over your window.
this.Cursor is the cursor that will be used when the mouse is over the window referred to by this. Cursor.Current is the current mouse cursor, which might be different from this.Cursor if the mouse is over a different window.
Actually if you would like to use HourGlass from another thread that will give you back cross-threading exception because you are trying to access f.Handle from different thread than form was originally created. Use GetForegroundWindow() instead from user32.dll.
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
and then
public static bool Enabled
{
get
{
return Application.UseWaitCursor;
}
set
{
if (value == Application.UseWaitCursor)
{
return;
}
Application.UseWaitCursor = value;
var handle = GetForegroundWindow();
SendMessage(handle, 0x20, handle, (IntPtr)1);
}
}
I have noticed an interesting thing about setting cursors, so I would like to clear some misunderstandings that I myself had before and I hope it may help others too:
When you try to set a form's cursor by using
this.cursor = Cursors.Waitcursor
you actually set the cursor for the control and not the whole form since cursor is property of the Control class.
Also of course the cursor will only be changed to the given cursor when the mouse is actually over the actual control (explicitly the form's area)
As Hans Passant has already stated that:
Windows sends the window that contains the mouse cursor the
WM_SETCURSOR message, giving it an opportunity to change the cursor
shape
I don't know if windows sends messages directly to controls or if the form relays those messages to it's child controls based on mouse position, I'd most likely guess on the first method since when i fetched the messages with overriding WndProc of the form control, when i was over the textbox for example, the form didn't process any messages. (please someone give clarity on this)
Basically my suggestion would be to reside from using this.cursor also and stick to this.usewaitcursor, since that changes the cursor property to waitcursor for all child controls.
The problem with this is also the same as with the application level Application.usewaitcursor, while you are not over the form/forms with your cursor no WM_SETCURSOR message is being sent by windows, so if you start a time consuming synchronous operation before moving your mouse over the form's area, the form can only process such message when the time consuming synchronous operation finishes.
(I would not suggest running time consuming tasks in the UI thread at all, mainly this is what is causing the issue here)
I made a little improvement on Hans Passant's answer, so the hourglass can be either set on application level or form level, also avoiding InvalidOperationException from cross threaded operation calls:
using System;
using System.Windows.Forms;
public class HourGlass : IDisposable
{
public static bool ApplicationEnabled
{
get{ return Application.UseWaitCursor; }
set
{
Form activeFrom = Form.ActiveForm;
if (activeFrom == null || ApplicationEnabled == value) return;
if (ApplicationEnabled == value)return;
Application.UseWaitCursor = (bool)value;
if (activeFrom.InvokeRequired)
{
activeFrom.BeginInvoke(new Action(() =>
{
if (activeFrom.Handle != IntPtr.Zero)
SendMessage(activeFrom.Handle, 0x20, activeFrom.Handle, (IntPtr)1); // Send WM_SETCURSOR
}));
}
else
{
if (activeFrom.Handle != IntPtr.Zero)
SendMessage(activeFrom.Handle, 0x20, activeFrom.Handle, (IntPtr)1); // Send WM_SETCURSOR
}
}
}
private Form f;
public HourGlass()
{
this.f = Form.ActiveForm;
if (f == null)
{
throw new ArgumentException();
}
Enabled = true;
}
public HourGlass(bool enabled)
{
this.f = Form.ActiveForm;
if (f == null)
{
throw new ArgumentException();
}
Enabled = enabled;
}
public HourGlass(Form f, bool enabled)
{
this.f = f;
if (f == null)
{
throw new ArgumentException();
}
Enabled = enabled;
}
public HourGlass(Form f)
{
this.f = f;
if (f == null)
{
throw new ArgumentException();
}
Enabled = true;
}
public void Dispose()
{
Enabled = false;
}
public bool Enabled
{
get { return f.UseWaitCursor; }
set
{
if (f == null || Enabled == value) return;
if (Application.UseWaitCursor == true && value == false) return;
f.UseWaitCursor = (bool)value;
if(f.InvokeRequired)
{
f.BeginInvoke(new Action(()=>
{
if (f.Handle != IntPtr.Zero)
SendMessage(f.Handle, 0x20, f.Handle, (IntPtr)1); // Send WM_SETCURSOR
}));
}
else
{
if (f.Handle != IntPtr.Zero)
SendMessage(f.Handle, 0x20, f.Handle, (IntPtr)1); // Send WM_SETCURSOR
}
}
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
}
To use it on application level:
try
{
HourGlass.ApplicationEnabled = true;
//time consuming synchronous task
}
finally
{
HourGlass.ApplicationEnabled = false;
}
For using it on form level you can either use for the current active form:
using (new HourGlass())
{
//time consuming synchronous task
}
or you can initialize a local variable in the form like this:
public readonly HourGlass hourglass;
public Form1()
{
InitializeComponent();
hourglass = new HourGlass(this, false);
}
and use it later in a try catch finally block
This works great for me when the LongRunningOperation() is processing messages.
private void btnDoLongRunningOperation_Click(object sender, System.EventArgs e)
{
this.Cursor = Cursors.WaitCursor;
LongRunningOperation();
this.Cursor = Cursors.Arrow;
}
From VB.net VS 2012
Windows.Forms.Cursor.Current = Cursors.Default

C# Pause After Bringing Application to Foreground for Input

I have a method that gets called into a new thread like so:
if (!_isPlaying)
{
_playBackThread = new Thread(PlayMacroEvents);
_playBackThread.Start();
...
}
The method looks like:
Process proc = Process.GetProcessesByName("notepad").FirstOrDefault();
if (proc != null)
{
SetForegroundWindow(proc.MainWindowHandle);
}
int loopCount = this.dsUserInput.Tables[0].Rows.Count;
for (int i = 0; i < loopCount; i++)
{
foreach(MacroEvent macroEvent in _events)
{
Thread.Sleep(macroEvent.TimeSinceLastEvent);
switch (macroEvent.MacroEventType)
{
...
The problem I'm having is that if notepad is not already up (not minimized) there is enough delay between setting the foreground window and the macro output that often the first series of commands is not shown. How can I put enough of a pause to make sure that the window is up before the the macros start kicking in? A Thread.Sleep() between SetForegroundWindow() and the for loop does not seem to do the trick. Ideas?
The reason the first series of inputs were being dropped is because I also had to include the command to ShowWindow like so..
in the class header:
private const int SW_RESTORE = 9;
[DllImport("user32")]
private static extern int ShowWindow(IntPtr hwnd, int nCmdShow);
...
In the macro thread method I changed
if (proc != null)
{
SetForegroundWindow(proc.MainWindowHandle);
}
to look like:
if (proc != null)
{
ShowWindow(proc.MainWindowHandle, SW_RESTORE);
SetForegroundWindow(proc.MainWindowHandle);
}
Use some api to get the active window, and wait until the window belonging to notepad is the active one

Cursor.Current vs. this.Cursor

Is there a difference between Cursor.Current and this.Cursor (where this is a WinForm) in .Net? I've always used this.Cursor and have had very good luck with it but I've recently started using CodeRush and just embedded some code in a "Wait Cursor" block and CodeRush used the Cursor.Current property. I've seen on the Internet and at work where other programmers have had some problems with the Cursor.Current property. It just got me to wondering if there is a difference in the two. Thanks in advance.
I did a little test. I have two winforms. I click a button on form1, set the Cursor.Current property to Cursors.WaitCursor and then show form2. The cursor doesn't change on either form. It remains Cursors.Default (pointer) cursor.
If I set this.Cursor to Cursors.WaitCursor in the button click event on form1 and show form2, the wait cursor only shows on form1 and the default cursor is on form2 which is expected. So, I still don't know what Cursor.Current does.
Windows sends the window that contains the mouse cursor the WM_SETCURSOR message, giving it an opportunity to change the cursor shape. A control like TextBox takes advantage of that, changing the cursor into a I-bar. The Control.Cursor property determines what shape will be used.
The Cursor.Current property changes the shape directly, without waiting for a WM_SETCURSOR response. In most cases, that shape is unlikely to survive for long. As soon as the user moves the mouse, WM_SETCURSOR changes it back to Control.Cursor.
The UseWaitCursor property was added in .NET 2.0 to make it easier to display an hourglass. Unfortunately, it doesn't work very well. It requires a WM_SETCURSOR message to change the shape and that won't happen when you set the property to true and then do something that takes a while. Try this code for example:
private void button1_Click(object sender, EventArgs e) {
this.UseWaitCursor = true;
System.Threading.Thread.Sleep(3000);
this.UseWaitCursor = false;
}
The cursor never changes. To whack that into shape, you'll need to use Cursor.Current as well. Here is a little helper class to make it easy:
using System;
using System.Windows.Forms;
public class HourGlass : IDisposable {
public HourGlass() {
Enabled = true;
}
public void Dispose() {
Enabled = false;
}
public static bool Enabled {
get { return Application.UseWaitCursor; }
set {
if (value == Application.UseWaitCursor) return;
Application.UseWaitCursor = value;
Form f = Form.ActiveForm;
if (f != null && f.Handle != IntPtr.Zero) // Send WM_SETCURSOR
SendMessage(f.Handle, 0x20, f.Handle, (IntPtr)1);
}
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
}
And use it like this:
private void button1_Click(object sender, EventArgs e) {
using (new HourGlass()) {
System.Threading.Thread.Sleep(3000);
}
}
I believe that Cursor.Current is the mouse cursor currently being used (regardless of where it is on the screen), while this.Cursor is the cursor it will be set to, when the mouse passes over your window.
this.Cursor is the cursor that will be used when the mouse is over the window referred to by this. Cursor.Current is the current mouse cursor, which might be different from this.Cursor if the mouse is over a different window.
Actually if you would like to use HourGlass from another thread that will give you back cross-threading exception because you are trying to access f.Handle from different thread than form was originally created. Use GetForegroundWindow() instead from user32.dll.
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
and then
public static bool Enabled
{
get
{
return Application.UseWaitCursor;
}
set
{
if (value == Application.UseWaitCursor)
{
return;
}
Application.UseWaitCursor = value;
var handle = GetForegroundWindow();
SendMessage(handle, 0x20, handle, (IntPtr)1);
}
}
I have noticed an interesting thing about setting cursors, so I would like to clear some misunderstandings that I myself had before and I hope it may help others too:
When you try to set a form's cursor by using
this.cursor = Cursors.Waitcursor
you actually set the cursor for the control and not the whole form since cursor is property of the Control class.
Also of course the cursor will only be changed to the given cursor when the mouse is actually over the actual control (explicitly the form's area)
As Hans Passant has already stated that:
Windows sends the window that contains the mouse cursor the
WM_SETCURSOR message, giving it an opportunity to change the cursor
shape
I don't know if windows sends messages directly to controls or if the form relays those messages to it's child controls based on mouse position, I'd most likely guess on the first method since when i fetched the messages with overriding WndProc of the form control, when i was over the textbox for example, the form didn't process any messages. (please someone give clarity on this)
Basically my suggestion would be to reside from using this.cursor also and stick to this.usewaitcursor, since that changes the cursor property to waitcursor for all child controls.
The problem with this is also the same as with the application level Application.usewaitcursor, while you are not over the form/forms with your cursor no WM_SETCURSOR message is being sent by windows, so if you start a time consuming synchronous operation before moving your mouse over the form's area, the form can only process such message when the time consuming synchronous operation finishes.
(I would not suggest running time consuming tasks in the UI thread at all, mainly this is what is causing the issue here)
I made a little improvement on Hans Passant's answer, so the hourglass can be either set on application level or form level, also avoiding InvalidOperationException from cross threaded operation calls:
using System;
using System.Windows.Forms;
public class HourGlass : IDisposable
{
public static bool ApplicationEnabled
{
get{ return Application.UseWaitCursor; }
set
{
Form activeFrom = Form.ActiveForm;
if (activeFrom == null || ApplicationEnabled == value) return;
if (ApplicationEnabled == value)return;
Application.UseWaitCursor = (bool)value;
if (activeFrom.InvokeRequired)
{
activeFrom.BeginInvoke(new Action(() =>
{
if (activeFrom.Handle != IntPtr.Zero)
SendMessage(activeFrom.Handle, 0x20, activeFrom.Handle, (IntPtr)1); // Send WM_SETCURSOR
}));
}
else
{
if (activeFrom.Handle != IntPtr.Zero)
SendMessage(activeFrom.Handle, 0x20, activeFrom.Handle, (IntPtr)1); // Send WM_SETCURSOR
}
}
}
private Form f;
public HourGlass()
{
this.f = Form.ActiveForm;
if (f == null)
{
throw new ArgumentException();
}
Enabled = true;
}
public HourGlass(bool enabled)
{
this.f = Form.ActiveForm;
if (f == null)
{
throw new ArgumentException();
}
Enabled = enabled;
}
public HourGlass(Form f, bool enabled)
{
this.f = f;
if (f == null)
{
throw new ArgumentException();
}
Enabled = enabled;
}
public HourGlass(Form f)
{
this.f = f;
if (f == null)
{
throw new ArgumentException();
}
Enabled = true;
}
public void Dispose()
{
Enabled = false;
}
public bool Enabled
{
get { return f.UseWaitCursor; }
set
{
if (f == null || Enabled == value) return;
if (Application.UseWaitCursor == true && value == false) return;
f.UseWaitCursor = (bool)value;
if(f.InvokeRequired)
{
f.BeginInvoke(new Action(()=>
{
if (f.Handle != IntPtr.Zero)
SendMessage(f.Handle, 0x20, f.Handle, (IntPtr)1); // Send WM_SETCURSOR
}));
}
else
{
if (f.Handle != IntPtr.Zero)
SendMessage(f.Handle, 0x20, f.Handle, (IntPtr)1); // Send WM_SETCURSOR
}
}
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
}
To use it on application level:
try
{
HourGlass.ApplicationEnabled = true;
//time consuming synchronous task
}
finally
{
HourGlass.ApplicationEnabled = false;
}
For using it on form level you can either use for the current active form:
using (new HourGlass())
{
//time consuming synchronous task
}
or you can initialize a local variable in the form like this:
public readonly HourGlass hourglass;
public Form1()
{
InitializeComponent();
hourglass = new HourGlass(this, false);
}
and use it later in a try catch finally block
This works great for me when the LongRunningOperation() is processing messages.
private void btnDoLongRunningOperation_Click(object sender, System.EventArgs e)
{
this.Cursor = Cursors.WaitCursor;
LongRunningOperation();
this.Cursor = Cursors.Arrow;
}
From VB.net VS 2012
Windows.Forms.Cursor.Current = Cursors.Default

Richtextbox.invoke, C#, Form Still hanging

I've written a c# application to run an external program and i've redirectet it's output to a richtextbox in my form. I've created the process using the following settings
p1.StartInfo.RedirectStandardOutput = true;
p1.OutputDataReceived += new DataReceivedEventHandler(outputreceived);
and in the outputreceived event
void outputreceived(object sender, DataReceivedEventArgs e)
{
if (!string.IsNullOrEmpty(e.Data))
{
richTextBox1.Invoke(new UpdateOutputCallback(this.updateoutput),
new object[] { e.Data });
}
}
void updateoutput(string text)
{
int len = text.Length;
int start = richTextBox1.Text.Length;
richTextBox1.Text += text + Environment.NewLine;
richTextBox1.Select(start, len);
richTextBox1.SelectionColor = System.Drawing.Color.White;
richTextBox1.Select(richTextBox1.Text.Length, 0);
richTextBox1.ScrollToCaret();
}
Now the thing is though it is working, but my main form which contains the textbox, hangs if the output is huge from the application. I think each time the invoke call leads to repainting of the form, which happens very frequently. Is there any alternative so that i can see the updates to the textbox as they happen and also keep the form completely active?
Update:
I think I got my answer, I used BeginInvoke when I should have used Invoke.
Update 1:
I tried both BeginInvoke and Suspendlayout but it is not giving me the desired functionality, what happens is that the process has returened all the standardoutput to the string, but the thread which is responsible for updating the text is taking it's own time to print the data. Can i do any thing to it?
Since you've already solved your problem, I'll just note that it will be faster if you use rtb.AppendText (instead of Text += ...) and use pinvoke to scroll to the bottom:
private const int WM_VSCROLL = 0x115;
private const int SB_BOTTOM = 7;
[DllImport("user32.dll", CharSet=CharSet.Auto)]
private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam,
IntPtr lParam);
// ...
// Scroll to the bottom, but don't move the caret position.
SendMessage(rtb.Handle, WM_VSCROLL, (IntPtr) SB_BOTTOM, IntPtr.Zero);
You might want to try
richTextBox1.BeginInvoke()
rather than
richTextBox1.Invoke()
That will at least make the call Asynchronous. Still not sure if that will cause the UI thread to lock while the updates are being painted.
Try to suspend and resume layout of richTextBox1
void updateoutput(string text)
{
try
{
richTextBox1.SuspendLayout();
int len = text.Length;
int start = richTextBox1.Text.Length;
richTextBox1.Text += text + Environment.NewLine;
richTextBox1.Select(start, len);
richTextBox1.SelectionColor = Color.White;
richTextBox1.Select(richTextBox1.Text.Length, 0);
richTextBox1.ScrollToCaret();
}
finally
{
richTextBox1.ResumeLayout();
}
}
Is there any alternative so that i can see the updates to the textbox as they happen and also keep the form completely active?
I think you should use Debug.Print to view what's going on instead.
It is an old post, but maybe somebody still looking for it like I did.
You also can do, like "for(writeToTextbox % 10 == 0)" then invoke.
In this case it will be updated only every 10 times.
UPDATE: sorry for the misspelling! (wirte -> write) and thanks for "HaveNoDisplayName" to show it to me!

Show a Form without stealing focus?

I'm using a Form to show notifications (it appears at the bottom right of the screen), but when I show this form it steals the focus from the main Form. Is there a way to show this "notification" form without stealing focus?
Hmmm, isn't simply overriding Form.ShowWithoutActivation enough?
protected override bool ShowWithoutActivation
{
get { return true; }
}
And if you don't want the user to click this notification window either, you can override 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;
}
}
Stolen from PInvoke.net's ShowWindow method:
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);
}
(Alex Lyman answered this, I'm just expanding it by directly pasting the code. Someone with edit rights can copy it over there and delete this for all I care ;) )
This is what worked for me. It provides TopMost but without focus-stealing.
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;
}
}
Remember to omit setting TopMost in Visual Studio designer, or elsewhere.
This is stolen, err, borrowed, from here (click on Workarounds):
https://connect.microsoft.com/VisualStudio/feedback/details/401311/showwithoutactivation-is-not-supported-with-topmost
If you're willing to use Win32 P/Invoke, then you can use the ShowWindow method (the first code sample does exactly what you want).
Doing this seems like a hack, but it seems to work:
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
Edit: Note, this merely raises an already created form without stealing focus.
The sample code from pinvoke.net in Alex Lyman/TheSoftwareJedi's answers will make the window a "topmost" window, meaning that you can't put it behind normal windows after it's popped up. Given Matias's description of what he wants to use this for, that could be what he wants. But if you want the user to be able to put your window behind other windows after you've popped it up, just use HWND_TOP (0) instead of HWND_TOPMOST (-1) in the sample.
In WPF you can solve it like this:
In the window put these attributes:
<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>
The last one attribute is the one you need ShowActivated="False".
I have something similar, and I simply show the notification form and then do
this.Focus();
to bring the focus back on the main form.
Create and start the notification Form in a separate thread and reset the focus back to your main form after the Form opens. Have the notification Form provide an OnFormOpened event that is fired from the Form.Shown event. Something like this:
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
}
You can also keep a handle to your NotifcationForm object around so that it can be programmatically closed by the main Form (frm.Close()).
Some details are missing, but hopefully this will get you going in the right direction.
This works well.
See: OpenIcon - MSDN and 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);
}
You might want to consider what kind of notification you would like to display.
If it's absolutely critical to let the user know about some event, using Messagebox.Show would be the recommended way, due to its nature to block any other events to the main window, until the user confirms it. Be aware of pop-up blindness, though.
If it's less than critical, you might want to use an alternative way to display notifications, such as a toolbar on the bottom of the window. You wrote, that you display notifications on the bottom-right of the screen - the standard way to do this would be using a balloon tip with the combination of a system tray icon.
You can handle it by logic alone too, although I have to admit that the suggestions above where you end up with a BringToFront method without actually stealing focus is the most elegant one.
Anyhow, I ran into this and solved it by using a DateTime property to not allow further BringToFront calls if calls were made already recently.
Assume a core class, 'Core', which handles for example three forms, 'Form1, 2, and 3'. Each form needs a DateTime property and an Activate event that call Core to bring windows to front:
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;
}
And then create the work in the Core Class:
internal static void BringAllToFront(Form inForm)
{
Form1.BringToFront();
Form2.BringToFront();
Form3.BringToFront();
inForm.Focus();
}
On a side note, if you want to restore a minimized window to its original state (not maximized), use:
inForm.WindowState = FormWindowState.Normal;
Again, I know this is just a patch solution in the lack of a BringToFrontWithoutFocus. It is meant as a suggestion if you want to avoid the DLL file.
I don't know if this is considered as necro-posting, but this is what I did since I couln't get it working with user32's "ShowWindow" and "SetWindowPos" methods. And no, overriding "ShowWithoutActivation" doesn't work in this case since the new window should be always-on-top.
Anyway, I created a helper method that takes a form as parameter; when called, it shows the form, brings it to the front and makes it TopMost without stealing the focus of the current window (apparently it does, but the user won't notice).
[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);
}
}
I know it may sound stupid, but this worked:
this.TopMost = true;
this.TopMost = false;
this.TopMost = true;
this.SendToBack();
I needed to do this with my window TopMost. I implemented the PInvoke method above but found that my Load event wasn't getting called like Talha above. I finally succeeded. Maybe this will help someone. Here is my solution:
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
You don't need to make it anywhere near as complicated.
a = new Assign_Stock();
a.MdiParent = this.ParentForm;
a.Visible = false; //hide for a bit.
a.Show(); //show the form. Invisible form now at the top.
this.Focus(); //focus on this form. make old form come to the top.
a.Visible = true; //make other form visible now. Behind the main form.
Github Sample
Form.ShowWithoutActivation Property
Add this in your child form class
protected override bool ShowWithoutActivation
{
get { return true; }
}
Working Code
Form2
public partial class Form2 : Form
{
Form3 c;
public Form2()
{
InitializeComponent();
c = new Form3();
}
private void textchanged(object sender, EventArgs e)
{
c.ResetText(textBox1.Text.ToString());
c.Location = new Point(this.Location.X+150, this.Location.Y);
c .Show();
//removethis
//if mdiparent 2 add this.focus() after show form
c.MdiParent = this.MdiParent;
c.ResetText(textBox1.Text.ToString());
c.Location = new Point(this.Location.X+150, this.Location.Y);
c .Show();
this.Focus();
////-----------------
}
}
Form3
public partial class Form3 : Form
{
public Form3()
{
InitializeComponent();
//ShowWithoutActivation = false;
}
protected override bool ShowWithoutActivation
{
get { return true; }
}
internal void ResetText(string toString)
{
label2.Text = toString;
}
}
When you create a new form using
Form f = new Form();
f.ShowDialog();
it steals focus because your code can't continue executing on the main form until this form is closed.
The exception is by using threading to create a new form then Form.Show(). Make sure the thread is globally visible though, because if you declare it within a function, as soon as your function exits, your thread will end and the form will disappear.
Figured it out: window.WindowState = WindowState.Minimized;.

Categories

Resources