I have a control in a WPF application that contains a text box and a submit button. The submit button is set as the "default" so that if the user presses Enter while the cursor is in the text box, the click handler for the button is run. The process kicked off by the click handler is lengthy, so I use a wait cursor coded like the following:
public class WaitCursor: IDisposable
{
private readonly System.Windows.Input.Cursor _oldCursor = null;
public WaitCursor()
{
_oldCursor = System.Windows.Input.Mouse.OverrideCursor;
System.Windows.Input.Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait;
// *** 1
}
~WaitCursor()
=> Dispose(false);
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void Dispose(bool unused)
{
System.Windows.Input.Mouse.OverrideCursor = _oldCursor;
// *** 2
}
}
If I type in the text box, the mouse cursor disappears. This is standard behaviour on Windows that I have observed in many applications. However, if I type in the text box and then press Enter without moving the mouse, then the mouse cursor is not shown while the application is busy - even if the user is moving it around. Effectively, the mouse cursor becomes invisible whenever it's over my application's windows, and remains that way until the application ceases being busy. This is undesirable.
I tried adding System.Windows.Forms.Cursor.Show() at the position marked with // *** 1 in my code above. This solved the problem of the cursor not being shown. But it introduced a new problem, in that the cursor no longer gets automatically hidden when the user types into text boxes in the application thereafter (for the lifetime of the application). The documentation page on Cursor.Show() says that calls to the Show() and Hide() methods should be paired, so I tried adding System.Windows.Forms.Cursor.Hide() at the position marked with // *** 2. This fixed all observed issues.
But I am not comfortable with this solution, for 2 reasons:
I am using a combination of the facilities provided by System.Windows.Forms.Cursor and System.Windows.Input.Cursor. This feels like it must be incorrect.
I am not comfortable instructing the application to "hide" the cursor when I do not in fact want the cursor to be hidden, even though the observed behaviour is that I merely undo the effect of the earlier call to Show(). It seems like something that isn't the intent of the framework designers (it really looks like what they had in mind was that you would Hide() the cursor and later Show() it) and might therefore break unpredictably.
What's the correct/proper way of solving this problem? If there is an officially sanctioned way to do this then I want to do that.
What about moving (simulated from code behind) the mouse before you start your process?
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
KeyDown += _OnKeyDown;
}
[DllImport("User32.dll")]
private static extern bool SetCursorPos(int X, int Y);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool GetCursorPos(ref Win32Point pt);
[StructLayout(LayoutKind.Sequential)]
internal struct Win32Point
{
public Int32 X;
public Int32 Y;
};
public static Point GetMousePosition()
{
Win32Point w32Mouse = new Win32Point();
GetCursorPos(ref w32Mouse);
return new Point(w32Mouse.X, w32Mouse.Y);
}
private void _OnKeyDown(object sender, KeyEventArgs keyEventArgs)
{
if (keyEventArgs.Key == Key.Enter)
{
Point pos = GetMousePosition();
SetCursorPos((int)pos.X + 1, (int)pos.Y); //move 1 pixel
SetCursorPos((int)pos.X - 1, (int)pos.Y); //move back to original position
//start your process afterwards ..
}
}
The problem I have is that when one switches from one child form to another a strange thing happens: the form to be shown appears in a strange way as if it has been minimized, restored and then maximized, causing an effect of like several drawing events at the same time.
The problem does not appear (ie, everything works) in these situations:
when one switches between forms using CTRL+TAB or CTRL+SHIFT+TAB
when child forms are not maximized and one simply changes the order/position of the form
Possibly related; there are a tonne of methods one can called for showing forms, including (and related):
child.Focus()
child.Show()
child.Activate()
child.Select()
child.BringToFront()
My question is, what exactly should I be calling?
Edit:
In my case, I have the following code that works, but still causes the weird effect I described above:
private void tabForms_MouseClick(object sender, MouseEventArgs e)
{
// handle middle-mouse-button click (close)
if (e.Button == System.Windows.Forms.MouseButtons.Middle)
{
// See: http://stackoverflow.com/a/745361
TabPage tab = tabForms.TabPages.Cast<TabPage>().Where((t, i) => tabForms.GetTabRect(i).Contains(e.Location)).FirstOrDefault();
if (tab != null && tab.Tag != null) (tab.Tag as Form).Close();
}
// handle left-mouse-button click (show)
if ((tabForms.SelectedTab != null) && (tabForms.SelectedTab.Tag != null) && (ActiveMdiChild != tabForms.SelectedTab.Tag))
{
(tabForms.SelectedTab.Tag as Form).Select();
(tabForms.SelectedTab.Tag as Form).Show();
}
}
PS: Without the .Select() it doesn't work. Although it seems that it still works if I replace .Select() and .Show() with .Focus().
This might be old now, but for the benefit of anyone else with this issue there's a simple solution to this. You can call the Win32 method LockWindowUpdate, providing the window handle to your form, create and open / maximise your form, then call LockWindowUpdate again and provide an IntPtr.Zero value (as shown below).
try
{
LockWindowUpdate(this.Handle);
// Open your form, maximise it etc
}
catch (Exception ex)
{
// Handle any errors
}
finally
{
LockWindowUpdate(IntPtr.Zero);
}
LockWindowUpdate disables drawing for whichever window handle you provide it, calling it a second time with a zero IntPtr resumes drawing the window. Only one window can be locked at a time.
You will need two other things; a DLL import, and a using reference for System.Runtime.InteropServices. Here's the DLL import:
[DllImport("user32.dll", EntryPoint = "LockWindowUpdate", SetLastError = true,
ExactSpelling = true, CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
public static extern long LockWindowUpdate(IntPtr hWndLock);
I'm trying to jump through some hoops at the moment in dealing with WPF's SizeChanged event on a Window. I have some custom code that I need executed after a user completes resizing the window, unfortunately there is no event that I have been able to come across for this so I have created a solution using Reactive Extensions to throttle the SizeChange events:
IObservable<SizeChangedEventArgs> ObservableSizeChanges = Observable
.FromEventPattern<SizeChangedEventArgs>(this, "SizeChanged")
.Select(x => x.EventArgs)
.Throttle(TimeSpan.FromMilliseconds(200));
IDisposable SizeChangedSubscription = ObservableSizeChanges
.ObserveOn(SynchronizationContext.Current)
.Subscribe(x => {
Size_Changed(x);
});
Basically what this does is ensures that 200 milliseconds of no SizeChanged events must pass before it will call my custom code. This works fine however I have run into a problem that if the user drags the window handle out and continues to hold the mouse button down the code will still be executed. I want to be able to make sure that the custom code cannot be executed while the mouse button is down. I tried plugging into PreviewMouseLeftButtonDown but it is not fired when the window handle is clicked, only when the mouse is clicked inside the window's frame. Is there any similar event I can plug into for a mouse down that applies to the window handle? Or can anyone think of a suitable workaround for the problem that I'm having?
Windows sends a dedicated message to notify the window that the modal size/move loop has exited. WM_EXITSIZEMOVE, fired when the user lets go of the mouse button or presses Escape. But yes, WPF doesn't expose it. Google "wpf wm_exitsizemove" to find the interop code you want. A good looking hit is this blog post
This is probably overkill, but to specifically address your "How can I figure out if the mouse button is down?" question, take a look at this P/Invoke wrapper:
public class ButtonObserver : IDisposable
{
public struct MouseButtons
{
public bool LeftButton;
public bool RightButton;
}
[DllImport("user32.dll")]
static extern short GetAsyncKeyState(int vKey);
private const int VK_LBUTTON = 0x01;
private const int VK_RBUTTON = 0x02;
private Task _pollTask = null;
private Subject<MouseButtons> _pollBuffer = new Subject<MouseButtons>();
private CancellationTokenSource _canceller;
public IObservable<MouseButtons> PollMouse(int pollDelayMs)
{
if(_pollTask == null)
{
_canceller = new CancellationTokenSource();
_pollTask = Task.Factory.StartNew(() =>
{
while(!_canceller.IsCancellationRequested)
{
var mbLeft = GetAsyncKeyState(VK_LBUTTON) != 0;
var mbRight = GetAsyncKeyState(VK_RBUTTON) != 0;
_pollBuffer.OnNext(new MouseButtons{ LeftButton = mbLeft, RightButton = mbRight});
Thread.Sleep(pollDelayMs);
}
});
}
return _pollBuffer;
}
public void Dispose()
{
_canceller.Cancel();
_pollTask.Wait();
_pollTask = null;
}
}
You can use it as:
void Main()
{
var buttonObs = new ButtonObserver();
var buttons = buttonObs.PollMouse(100).Where(mb => mb.LeftButton);
using(buttons.Subscribe(mb => Console.WriteLine("Left button down")))
{
Console.ReadLine();
}
buttonObs.Dispose();
}
I've written a IE Toolbar in C# and everything is working fine except that when I open a child Windows Form from my toolbar, the tab key doesn't work on the child form to allow me to move from field to field.
The interesting part is that when I open my child form using form.showDialog() instead of form.show() the tabs work like normal.
The toolbar I've created is based on this article and this article
I've implemented TranslateAcceleratorIO as mentioned in several articles, but still no luck.
Here are my implmentations of TranslateAcceleratorIO() and HasFocusIO() (implemented in my toolband class)
[DllImport("user32.dll")]
public static extern int TranslateMessage(ref MSG lpMsg);
[DllImport("user32", EntryPoint = "DispatchMessage")]
static extern bool DispatchMessage(ref MSG msg);
public int HasFocusIO()
{
return this.ContainsFocus ? 0 : 1; //S_OK : S_FALSE;
}
public int TranslateAcceleratorIO(ref MSG msg)
{
if (msg.message == 0x100)//WM_KEYDOWN
if (msg.wParam == (uint)Keys.Tab || msg.wParam ==(uint)Keys.F6)
{
if (SelectNextControl(
ActiveControl,
ModifierKeys == Keys.Shift ? false : true,
true,
true,
false)
)
{
return 0;//S_OK
}
}
else
{
TranslateMessage(ref msg);
DispatchMessage(ref msg);
return 0;//S_OK
}
return 1;//S_FALSE
}
I've also tried having TranslateAccelerator like this with no luck:
public int TranslateAcceleratorIO(ref MSG msg)
{
TranslateMessage(ref msg);
DispatchMessage(ref msg);
return 0;//S_OK
}
Has anybody else run into this issue?
Are you also implementing HasFocusIO? I believe your main toolbar class must also implement HasFocusIO and return true.
These types of problems with IE toolbars were the bane of my existence for a while. I think what I eventually ended up doing was creating separate UI threads and making my dialogs modal in those threads, which eliminated a bunch of weird issues. But I think implementing HasFocusIO and TranslateAcceleratorIO should work for this particular one.
Where are you implementing these? It's hard to tell from what you have there, are you implementing them in your Form or are you implementing them in your deskband class?
You need to implement them in your DeskBand implementation, and HasFocusIO needs to return true whenever one of your windows has focus (not just when the toolbar has focus). Then the messages for Tab, Delete, arrow keys, etc should be dispatched to the TranslateAcceleratorIO, also in your deskband, and from there you'll have to pass them along to your form.
The IE plugin framework is incredibly hacky that way.
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;.