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;
}
}
Related
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();
}
});
}
I would like to show a wait gif, while verifying a file and this is what I have tried so far.
There is a form - Form1, where user clicks a button to verify a file, and there is another form - Wait, with just a picturebox showing a gif image.
button_click()
{
Wait wait = new Wait();
wait.ShowDialog();
VerifyFile();
wait.Close();
}
The Wait form does show up, but it doesn't close. Also, the verification is also not done. It continues only when I manually close the Wait form.
How to auto close the wait form, once VerifyFile() is complete.
The problem with your code is that Form.ShowDialog() method is synchronous and it waits for the result from the "Form" dialog. This means that the code execution is hold up untill the "wait" dialog will be closed.
Consider moving the VerifyFile() method into Wait dialog:
class Wait: Form
{
public Wait() : base()
{
System.Threading.Tasks.Task.Factory.StartNew(() => VerifyFile());
}
}
You can close this dialog when after VerifyFile execute's over.
Within the application I am writing for testing/learning C#, I use the hidden/visible property to open and close windows.
It is a WPF application.
In the main window, I have a "close" button that triggers this method:
public void buttonQuit_Click(object sender, RoutedEventArgs e)
{
var message = exitmessage;
var title = exitTitle;
var result = MessageBox.Show(
message, // the message to show
title, // the title for the dialog box
MessageBoxButton.YesNo, // show two buttons: Yes and No
MessageBoxImage.Question); // show a question mark icon
// lets see what has been pressed
switch (result)
{
case System.Windows.MessageBoxResult.Yes: // Yes button pressed
CloseAllWindows();
break;
case System.Windows.MessageBoxResult.No: // No button pressed
break;
default: // Neither Yes nor No pressed (just in case)
MessageBox.Show("Oh noes! What did you press?!?!");
break;
}
}
This way I make sure that all windows get closed, including the hidden ones.
But now is the catch; when the user presses (in the main window) the top right red X in toolbar to close, only that main window gets closed, but in the background the hidden ones are still there.
So in fact it is 2 questions:
Is CloseAllWindows(); really sufficient to get the app 100% closed down?
How do I "catch" the event when the user presses that red X in the toolbar, and make this also trigger the right closing event?
You should be handling either the Closing or Closed event for your window(s). The former allows you to cancel the close, while the latter just allows you to perform necessary cleanup in response to the window being closed.
So, in this case, you should place the code from your buttonQuit_Click method into a handler method attached to the Closing event so that it gets triggered regardless of how the window is closed.
Then, your buttonQuit_Click method can simply call the window's Close method. That will close the window, in turn raising the Closing event, and running your code in the attached handler method.
As far as your other question, CloseAllWindows will do exactly what it says: it will close all of the windows that your application has opened. In most cases, that should be sufficient to close the application, but it might not be, especially if you've created non-background threads or depending on the ShutdownMode setting.
App.Current.Shutdown will work unconditionally.
You could use the Closing event of the window for that.
Some more info
http://msdn.microsoft.com/en-us/library/system.windows.window.closing.aspx
I have a WinForms application, And somewhere in the program user can bring up another form like pop up window for example an About Us form. I want the main form to be locked (eg User can not do anything in the UI of main form). And when that pop-up window is closed the main form would be return to normal state.
This is my code (I think I only miss the way of locking my main form)
private void buttonAbout_Click(Object sender, EventArgs e)
{
AboutUS abUs = new AboutUS();
abUS.Show()
this.LOCK!!! /* How to lock current form? */
abUS.FormClosing += delegate { /* How to Unlock main form */ };
}
Use Form.ShowDialog() instead of Form.Show().
Also see a related question.
I want to show messagebox to the user, such that the user cannot refuse to confirm the message box. User should not be allowed to do anything else in the screen until he confirms the messagebox.
This is a windows based c# application.
The main thing is, even if i use windows message box. Some times it is hiding behind some screen. But for my case, i want message box to be on top most whenever it appears.
I am using some other third party applications, which over rides my message box. I want to overcome this.
How to do this...
You will have to create your own form, make it modal, change the z-order to make it always on top, and capture all keystrokes and mouse clicks.
Always on top: http://www.codeguru.com/cpp/w-d/dislog/article.php/c1857
Take a look at this article
MessageBox.Show Examples in Windows Forms C#
Edit:
You can also use the topmost property of a form to make it on top of all windows in a given application.
How to: Keep a Windows Form on Top
To display a form as a modal dialog call the ShowDialog method.
Form frmAbout = new Form();
frmAbout.ShowDialog();
If standard implementation of MessageBox doesn't do what you need, you will have to create your own form and use ShowDialog() method.
It sounds like the messagebox is being displayed on another thread. You need to make sure that you call MessageBox.Show on the main UI thread. Below is a code snippet that illustrates a way to achieve this:
public class FooForm: Form
{
//This is just a button click handler that calls ShowMessage from another thread.
private void ButtonShowMessage_Click(object sender,EventArgs e)
{
//Use this to see that you can't interact with FooForm before closing the messagebox.
ThreadPool.QueueUserWorkItem(delegate{ ShowMessage("Hello World!");});
//Use this (uncomment) to see that you can interact with FooForm even though there is a messagebox.
//ThreadPool.QueueUserWorkItem(delegate{ MessageBox.Show("Hello World!");});
}
private void ShowMessage(string message)
{
if( InvokeRequire)
{
BeginInvoke(new MethodInvoker( () => MessageBox.Show(message)));
}
else
{
MessageBox.Show(message);
}
}
}
I am assuming that you don't have a scenario where you have multiple UI threads and when one of them pops a messagebox, you want that messagebox to be modal for the entire UI. That's a more complicated scenario.