Caching mouse events during an invoke of showdialog - c#

There are external windows programs that have a button which can call my COM app and it opens a WPF window. The code below allows my window to open. The calling window goes inactive, but its still registering clicks. When my window closes, it starts executing all the cached clicks. I don't have any control over the applications calling my window. If I change the dispatcher to BeginInvoke it doesn't deactivate the app window and just opens multiple new instances with each button click. How can I stop the cached clicks on the deactive window?
public void DoSetupDialog()
{
Dispatcher.Invoke(() =>
{
if (SetupWindow != null) return;
SetupWindow = new SetupWindow {Topmost = true};
SetupWindow.ShowDialog();
if (ObjectsCount <= 1)
{
Close();
}
});
}

Related

How to properly wait for input from modeless window

I have an application that has two mode-less windows. The first window, has a button to take input from the other window. My question is what is (is there?) the right way to call the second window for input and block the caller until user provides an input inside the text box. Here is a visual of what I'm trying to explain here:
App starts. Main window opens
User clicks on first button in main window -> second "modeless" window opens. User switches back to main window
User clicks on second button in the main window -> second "modeless" window is activated and focused
Second window now waits for input into the text box. This is where the question is: How to block the call from the main window, wait for input in the textbox, and return to caller only when user has entered input into the textbox, while not freezing the windows
I have this sudo-code as the solution for now but the loop is happening inside the main app code and it uses too much cpu just looping. Not sure if there is a better/right way to do this in C# and WPF specifically:
// input control mechanism
private object _inputLock = new object();
private bool _waiting = false;
// public string ReadInput() method starts waiting
do {
// pass control to dispatcher to update ui
inputTb.Dispatcher.Invoke(
() => { },
System.Windows.Threading.DispatcherPriority.Background
);
lock (_inputLock) {
if (!_waiting)
break;
}
} while (true);
// input text box handler turns off waiting
private void SendInput() {
lock (_inputLock) {
_waiting = false;
}
}

C# wpf multiple windows on task bar

I created a C# project which have multiple windows. When I do some other stuff, some of the windows are lost focus. Then I have to bring them to front by clicking the task bar one by one.
I am wondering is there are OnTaskBarClick Event on C# wpf window?
Then What I need to do is to set all sub windows with "ShowInTaskbar="False"". Then when ever my mainwindow is clicked on the task bar, I bring all the windows to the front.
You'll want to use the Window.Activated event to detect when your application's window is brought into focus:
From the documentation:
A window is activated (becomes the foreground window) when:
The window is first opened.
A user switches to a window by selecting it with the mouse, pressing ALT+TAB, or from Task Manager.
A user clicks the window's taskbar button.
Or you could use the Application.Activated event.
Clicking on a control of an already active window can also cause the Window.Activated event to fire, so if the issue is that it's firing too often, you'll probably want to watch for when the application toggles between being active and deactive.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Application.Current.Activated += CurrentOnActivated;
Application.Current.Deactivated += CurrentOnDeactivated;
}
private bool isDeactivated = true;
private void CurrentOnDeactivated(object sender, EventArgs eventArgs)
{
isDeactivated = true;
//handle case where another app gets focus
}
private void CurrentOnActivated(object sender, EventArgs eventArgs)
{
if (isDeactivated)
{
//Ok, this app was in the background but now is in the foreground,
isDeactivated = false;
//TODO: bring windows to forefont
MessageBox.Show("activated");
}
}
}
I think what you are experiencing is the window Owner not being set on your child window.
Please refer to Window.Owner Property
When a child window is opened by a parent window by calling
ShowDialog, an implicit relationship is established between both
parent and child window. This relationship enforces certain behaviors,
including with respect to minimizing, maximizing, and restoring.
-
When a child window is created by a parent window by calling Show,
however, the child window does not have a relationship with the parent
window. This means that:
The child window does not have a reference to the parent window.
The behavior of the child window is not dependent on the behavior of the parent window; either window can cover the other, or be
minimized, maximized, and restored independently of the other.
You can easily fix this by setting the Owner property in the child window when before calling Show() or ShowDialog()
Window ownedWindow = new Window();
ownedWindow.Owner = this; // this being the main or parent window
ownedWindow.Show();
Note : if conforming to an MVVM pattern, this can become a little
more cumbersome, however there is plenty of resources on how to link owner and parent windows.

Need a way to determine the main form of the application is brought on top of the other windows from the task bar

My application when not in focus or minimized or behind some other windows need to show a notification window to bring attention. And need to dismiss the notification window when the user brings the application upfront.
I am able to determine whether the main form(i.e my application) is active by the combination of
FormWindowState.Minimized and this.Handle != activeWindow
Now if the user brings the application upfront by himself, I have to remove the notification window.
To determine that i am using the Form_Activated inside the main form of the application and inside the Form_Activated, I am trying to find the main form of the window is active.
I tried the following but not working in all the scenarios in which the user can bring the application upfront.
subscribe the Form.ActiveForm and in side that determine it is the main form - Form.ActiveForm is MainForm
When the user minimizes the application and restors it - works fine
2.When the user uses Alt+Tab to bring that application upfront - works fine
3.When the user clicks the application icon up from the task bar - not working
Use the IntPtr GetForegroundWindow()
When the user minimizes the application and restors it - works fine
When the user uses Alt+Tab to bring that application upfront - not working as the handle is not retrieved
3.When the user clicks the application icon up from the task bar - not working as the handle is not retrieved
Using the this.Focused - Is false in the above cases
using IntPtr GetTopWindow(IntPtr hwnd) like GetTopWindow((sender as MainForm).Handle).ToString() != "0".this is true even if the notification window is shown which is not I want.
If I just subscribe the Form_Activated , when the notification window is shown, then also the mainForm_Activated is fired.Hence I need to do some additional checks here and all the ways I tried above, did not turn out success for all the ways in which the user can bring the application to foreground.
Any help would be greatly appreciated.
The problem was that repeated click on the task bar button will fire the activated event when the click hides the application and will not fire the event when the click shows the application.So OnResize () also maintained.
protected override void OnActivated(EventArgs e)
{
IntPtr activeWindow = Engine.GetForegroundWindow();
if ((this).Handle == activeWindow)
{
MainFormActive?.Invoke(this, EventArgs.Empty);
}
}
Resize
protected override void OnResize (EventArgs e)
{
if (previousState == FormWindowState.Minimized && this.WindowState == FormWindowState.Normal)
// raise OnActivated
}
Also I saw the following handy - handling WM_NCACTIVATE in the WndProc
if (m.Msg == Engine.WM_NCACTIVATE)
{
if ((this).Handle == Engine.GetForegroundWindow())
{
// Do what ever
}
}
WM_NCACTIVATE = 0x0086
Taskbar Minimize C# Windows Form Problem
Is there Windows system event on active window changed?

How to close an application or modal dialog via the taskbar when the dialog's ShowInTaskBar = false?

I have an application (mainApp) that opens a modal dialog (collector) to ask for login details. The dialog has a cancel button and a standard close button in the top-right corner, and has FormBorderStyle = FixedDialog.
If I set collector.ShowInTaskBar = true I can right-click the dialog box in the taskbar and close it. The dialog disappears and the main app is still running. I can also right-click the whole group and choose 'Close all windows', which closes both the dialog and the application.
If I set collector.ShowInTaskBar = false I can right-click the application in the taskbar and click close, but nothing happens.
I would prefer not to show the dialog in the taskbar, but I would like the entire application to close when it is closed from the taskbar. How can I do this? If this is not possible I would settle for just closing the dialog.
Edit: the main form's FormClosing event does not get called when ShowInTaskBar = false
Does the MainForm's Closing event get fired when you click Close in the taskbar? If it does, and the app is being forced to stay open by the presence of the dialog windows, you could try programatically closing the dialog in the Closing event, and then letting the event run its course.
NOTE : This is all speculation, and it is a long time since I did any WinForms work so I may have the event names wrong.
When you close your forms that way, the message WM_SYSCOMMAND will be sent to your form window. We can catch this message with some informative params to perform according actions. Try this code:
public partial class Form1 : Form {
public Form1(){
InitializeComponent();
}
bool shownModal;//This flag will be used to determine if there is some
//modal dialog opening.
protected override void WndProc(ref Message m) {
if (m.Msg == 0x112)//WM_SYSCOMMAND
{
//SC_CLOSE = 0xf060
if (m.WParam.ToInt32() == 0xf060 &&
m.LParam.ToInt32() == 0 && shownModal)
{
//Your own code here
//You can close the main form or close the modal dialog
Close();
}
}
base.WndProc(ref m);
}
}
NOTE: You have to turn on the flag shownModal before showing your dialog and turn off after that. It's just a way to deal with it, you can try another way of your own.
You have to store reference to your login window in mainApp. Then you can write something like this:
loginWindow.Close();
which closes dialog window. This action can take place also inside loginwindow, for example user clicks button Close and window closes.

software screen disappears when i click to open a dialog box in wpf

i have a WPF applicaton. when i click the button from my main screen of software or the shell UI to open a Dialog box the software screen disappears and it shows me the screen of previous process that i have opened before using the software screen like the code or explorer. and then to go to the screen i have to click the software from task bar.
this is the code to show this dialog box.
public void ShowView()
{
this.Owner = (Window)Shell;
this.ShowDialog();
}
Your dialog must be set with an owner window and should be opened dispatched on UI thread of the owner.
Application.Current.Dispatcher.BeginInvoke(
new Action(
() =>
{
DialogWindow.Owner = Application.Current.MainWindow;
DialogWindow.ShowDialog();
} ));
Does this help?

Categories

Resources