I want to have a return value from my WPF window without close it.
I have an DLL with WPF usercontrol inside, I call it from my DLL code.
I have to call it, it returns me datas, then I send it datas.
But I don't want to create two different instance of the same window.
My code :
MP.UserControl1 a = new MP.UserControl1();
a.ShowDialog();
if (a.DialogResult.HasValue && a.DialogResult.Value == true)
{
a.Hide();
InitialDatas = a.inputData;
}
else
return 0;
Then I elaborate InitialDatas
And now I want to call a method inside my "a", and show it again, without create a new window.
Code :
a.SetValue(result, off1, InitialDatas);
a.ShowDialog();
I got error message : Cannot set visibility or call Show, ShowDialog or EnsureHandle after a window has been closed
Is it possible to solve?
I would solve this with an event model. You could do the following:
Create an event in the Form
Create an event handler in the caller
Subscribe to the event and do your logic
The called form:
namespace MyApplication
{
public delegate void MyEventHandler(object source, EventArgs e);
public class MyForm : Form
{
public event MyEventHandler OnInitialData;
private void btnOk_Click(object sender, EventArgs e)
{
OnInitialData?.Invoke(this, null);
}
}
}
In your other Form:
MP.UserControl1 a = new MP.UserControl1();
a.OnInitialData += UCA_OnInitialData;
private void UCA_OnInitialData(object sender, EventArgs e)
{
MP.UserControl1 a = sender as MP.UserControl1;
a.SetValue(result, off1, a.inputData);
}
a.ShowDialog();
As the error message states, you cannot close the window and then open it again.
Instead of closing a window you could hide it by calling the Hide() method and then showing it again by calling the Show() method.
But since the ShowDialog() method doesn't return until the window has been closed, this won't work for a dialog window though. If you require a modal window, you will have to create a new instance of the window and open this one. This shouldn't really be an issue though.
So I guess the answer to your question is simply no. You cannot re-open a closed dialog window.
Related
I have an application in which I need to make sure the form opened by click on a button on a user control using ShowDialog(), will be closed and disposed when I dispose the user control.
I'm calling userControl.Dispose() in my main form through a timer.
Is there a way I can do that ?
Thanks...
Here is more details about the flow of the forms:
The MainForm of my application is creating a UserControl which has a Button. Than when the user clicks on the button of the user control, it shows a model form using ShowDialog.
Meanwhile, and after a few minutes, a timer in the main form replaces the existing user control with another instance of the user control. The main form calls the Dispose method of the previous user control, and the shows the new on.
But the problem is the modal dialog is still open on screen, blocking the main form. I want to close it, and the code placed after the ShowDialog method should not be executed.
Short answer
You can subscribe Disposed event of your UserControl and close the form which it shows. Regarding to the comments under the question, it looks like you have a UserControl containing a Button and in Click event of the button, you show a Form using ShowDialog().
To close and dispose the form, you need to subscribe Disposed event of your UserControl before showing the form as dialog.
More details
If you want to decide to run some logic depending to the dialog result of the form, you can check the dialog result and if it's OK, run the custom logic which you need.
To enhance the flow a bit, you can define some events and properties in your user control and handle them in the main form:
OKSelected event, and you can raise it immediately after closing the dialog if the dialog result is OK. It will let you to handle this event in the main form, for example to stop the timer if the user clicked OK in dialog.
ProcessingFinished, and you can raise it after you finished some processing after closing the dialog when the dialog result is OK. You can handle this in main form, for example to start the timer again.
You can define some properties in case you want to communicate some values with the main form.
Here is an example of the code in main form:
MyUserControl uc = null;
private void timer1_Tick(object sender, EventArgs e)
{
if (!(uc == null || uc.IsDisposed || uc.Disposing))
{
this.Controls.Remove(uc);
uc.Dispose();
}
uc = new MyUserControl();
this.Controls.Add(uc);
uc.OKSelected += (obj, args) => { timer1.Stop(); };
uc.ProcessingFinished += (obj, args) =>
{
MessageBox.Show(uc.Info);
timer1.Start();
};
}
And here is an example of the user control:
public partial class MyUserControl : UserControl
{
public MyUserControl() { InitializeComponent(); }
public EventHandler OKSelected;
public EventHandler ProcessingFinished;
public string Info { get; private set; }
private void button1_Click(object sender, EventArgs e)
{
using (var f = new Form()) {
var button = new Button() { Text = "OK" };
f.Controls.Add(button);
button.DialogResult = DialogResult.OK;
this.Disposed += (obj, args) => {
if (!(f.IsDisposed || f.Disposing)) {
f.Close(); f.Dispose();
}
};
if (f.ShowDialog() == DialogResult.OK) {
//If you need, raise the OKSelected event
//So you can handle it in the main form, for example to stop timer
OKSelected?.Invoke(this, EventArgs.Empty);
//
//Do whatever you need to do after user closed the dialog by OK
//
//If you need, raise the ProcessingFinished event
//So you can handle it in the main form, for example to start timer
//You can also set some properties to share information with main form
Info = "something";
ProcessingFinished?.Invoke(this, EventArgs.Empty);
}
}
}
}
Can you modify the forms that you want to close automatically? If so, try adding the following to each form:
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
if (this.Owner != null)
this.Owner.HandleDestroyed += onOwnerHandleDestroyed;
}
void onOwnerHandleDestroyed(object sender, EventArgs e)
{
this.Close();
}
NOTE: You are already using Dispose() to close the main form, so this should work. If, however, you used Close() to close the main form, then it wouldn't work because Close() doesn't close a form if it is the parent of any modal dialog.
I have two forms - frm_Main and frm_Threshold. The threshold form contains a trackbar.
All I need to do is to open the frm_Threshold from the frm_Main and if the trackbar changes trigger an event in the frm_Main.
I have found the solution (see the code) that seems to work, however, only if the frm_Threshold is called as a modal dialog from the frm_Main.
frm_Threshold code:
//event to pass value of threshold if changed onto another form
public event Action<int> ThresholdValueChanged;
//trackbar value changed
private void trackBarThreshold_ValueChanged(object sender, EventArgs e)
{
//changing value in the textbox
textBoxThreshold.Text = trackBarThreshold.Value.ToString();
//assignig value to the event to pass onto another form
ThresholdValueChanged(trackBarThreshold.Value);
}
frm_Main code:
private void toolStripButtonThreshold_Click(object sender, EventArgs e)
{
frm_Threshold formThreshold = new frm_Threshold();
formThreshold.ThresholdValueChanged += new Action<int>(Threshold);
formThreshold.ShowDialog(); // if changed to .Show() throws exception
formThreshold.ThresholdValueChanged -= new Action<int>(Threshold);
}
private void Threshold(int value)
{
// do something
}
In case I call the frm_Threshold form using the Show() method, null reference exception on the
public event Action<int> ThresholdValueChanged
is thrown (in the frm_Threshold).
Any idea how to solve the issue? Thanks!
Delete this line:
formThreshold.ThresholdValueChanged -= new Action<int>(Threshold);
If you just call the form using .Show() you immediately remove your event again.
By the way, you don't need this line in any case.
I'm building a GUI application with C# and gtk#. I've encountered an issue recently and was looking for the best solution to this problem:
I have a modal window that pops up for the user to enter a number. This window is a separate window accessed from my main window and it's set up like this:
public class MainWindow()
{
public NumberEntry numEntry;
Whenever I need numerical input from the user, I call ShowAll() on the public Window property of NumberEntry like:
numEntry.win.ShowAll();
And all of this works fine. Afterwards, to get the value they entered, I call:
int entered = numEntry.valueEntered;
The issue is obviously that code continues executing immediately after the ShowAll() line is finished, and numEntry.valueEntered is always 0. What I'd like to do (and have been trying to do), is to suspend the main thread, and open up the number entry window in a second thread, and join back to the main thread when this is complete. Suspending the main thread seems to prevent GUI changes making the program freeze when I try to open the number entry window. I'd also like to avoid callback methods if at all possible, seeing as how this would get rather complicated after awhile. Any advice? Thanks!
Seems like when GTK window is closed all its child controls are cleared. So to get the result from the custom dialog window you may do the following (I am not gtk guru but its works for me):
1. Create a new dialog window with your controls (I used Xamarin studio). Add result properties, OK and Cancel handlers and override OnDeleteEvent method:
public partial class MyDialog : Gtk.Dialog
{
public string Results {
get;
private set;
}
public MyDialog ()
{
this.Build ();
}
protected override bool OnDeleteEvent (Gdk.Event evnt)
{
Results = entry2.Text; // if user pressed on X button..
return base.OnDeleteEvent (evnt);
}
protected void OnButtonOkClicked (object sender, EventArgs e)
{
Results = entry2.Text;
Destroy ();
}
protected void OnButtonCancelClicked (object sender, EventArgs e)
{
Results = string.Empty;
Destroy ();
}
}
2. In your main window create a dialog object and attach to its Destroyed event your event handler:
protected void OnButtonClicked (object sender, EventArgs e)
{
var dialog = new MyDialog ();
dialog.Destroyed += HandleClose;
}
3. Get the results when dialog is closed:
void HandleClose (object sender, EventArgs e)
{
var dialog = sender as MyDialog;
var textResult = dialog.Results;
}
If you whant you also may specify a dialog result property and etс.
I've looked at all the suggested answers and nothing seems to fit what I'm looking for. I want to call a second form from my main form, hide my main form while the second form is active, and then unhide the main form when the second form closes. Basically I want to "toggle" between the two forms.
So far I have:
In my main form:
private void countClick(object sender, EventArgs e)
{
this.Hide();
subForm myNewForm = new subForm();
myNewForm.ShowDialog();
}
and in my second form I have:
private void totalClick(object sender, EventArgs e)
{
this.Close();
}
How do I get the main form to show?
ShowDialog opens your secondary Form as Modal Dialog, meaning that the MainForm's code execution will stop at that point and your secondary Form will have the focus. so all that you need to do is put a this.Show after your ShowDialog call.
From above link:
You can use this method to display a modal dialog box in your application. When this method is called, the code following it is not executed until after the dialog box is closed.
private void countClick(object sender, EventArgs e)
{
this.Hide();
subForm myNewForm = new subForm();
myNewForm.ShowDialog();
this.Show();
}
Let's say in Form1 you click a Button to show Form2
Form2 frm2 = new Form2();
frm2.Activated += new EventHandler(frm2_Activated); // Handler when the form is activated
frm2.FormClosed += new FormClosedEventHandler(frm2_FormClosed); // Hander when the form is closed
frm2.Show();
Now, this one is when the Form2 is shown or is Activated you hide the calling form, in this case the Form1
private void frm2_Activated(object sender, EventArgs e)
{
this.Hide(); // Hides Form1 but it is till in Memory
}
Then when Form2 is Closed it will Unhide Form1.
private void frm2_FormClosed(object sender, FormClosedEventArgs e)
{
this.Show(); // Unhide Form1
}
This is difficult to do correctly. The issue is that you must avoid having no window at all that can get the focus. The Windows window manager will be forced to find another window to give the focus to. That will be a window of another application. Your window will disappear behind it.
That's already the case in your existing code snippet, you are hiding your main window before showing the dialog. That usually turns out okay, except when the dialog is slow to create. It will definitely happen when the dialog is closed.
So what you need to do is hide your window after you display the dialog and show it again before the dialog closes. That requires tricks. They look like this:
private void countClick(object sender, EventArgs e)
{
this.BeginInvoke(new Action(() => this.Hide()));
using (var dlg = new subForm()) {
dlg.FormClosing += (s, fcea) => { if (!fcea.Cancel) this.Show(); };
if (dlg.ShowDialog() == DialogResult.OK) {
// etc...
}
}
}
The BeginInvoke() call is a trick to get code to run after the ShowDialog() method runs. Thus ensuring your window is hidden after the dialog window is shown. The FormClosing event of the dialog is used to get the window to be visible again just before the dialog closes.
You need to find some way to pass a reference to the main form to the second form click event handler.
You can do this either by setting the form as a member variable of the second form class or pass it via the event arguments.
If you are working in the same namespace, you have the context, using mainform or the name you gave the "main form", try:
mainform.show();
I have a button click event handler with the following pseudo code:
private void btnSave_Click(object sender, EventArgs e)
{
if(txt.Text.length == 0)
this.Close();
else
// Do something else
// Some other code...
}
This is just some simple code, but the point is, when the text length equals zero, I want to close the form. But instead of closing the form the code executes the part // Some other code. After the click event handler is completely executed, then the form is closed.
I know, when I place return right after this.Close() the form will close, but I'd like to know WHY the form isn't direclty closed when you call this.Close(). Why is the rest of the event handler executed?
The rest of the event handler is executed because you did not leave the method. It is as simple as that.
Calling this.Close() does not immediately "delete" the form (and the current event handler). The form will be collected later on by the garbage collector if there are no more references to the form.
this.Close() is nothing than a regular method call, and unless the method throws an exception you will stay in the context of your current method.
Close only hides the form; the form is still alive and won't receive another Load event if you show it again.
To actually delete it from memory, use Dispose().
Answer is simple as you are executing your current method so this.Close() will be enqueued until either you explicitly returned or your current excuting method throws an exception.
Another possible solution is that if you open a new Form and want to close the current one: if you use newForm.ShowDialog() instead of newForm.Show() it doesn't close the currentForm with currentForm.Close() until the newForm is also closed.
Unless the Form is a modal form(opened with .ShowDialog()), Form.Close() disposes the form, as well. So, you cannot reopen it under any circumstances after that, despite of what others may have said. There is Form.Visible for this behavior(hiding/showing the form).
The point here is that .Close() does not return from the section it is called for several reasons. For example, you may call SomeForm.Close() from another form or a class or whatever.
Close() is just a method like any other. You have to explicitly return from a method that calls Close() if this is what you want.
Calling MessageBox.Show(frmMain,"a message","a title") adds the form "TextDialog" to the application's Application.OpenForms() forms collection, along-side the frmMain Main form itself. It remains after you close the Messagebox.
When this happens and you call the OK button delegate to close the main form, calling frmMain.Close() will not work, the main form will not disappear and the program will not terminate as it usually will after you exit the OK delegate. Only Application.Exit() will close all of the garbage messagebox "TextDialog"s.
private void btnCloseForm_Click(object sender, EventArgs e)
{
FirstFrm.ActiveForm.Close();
}
and if you want close first form and open secound form do this :
private void btnCloseForm_Click(object sender, EventArgs e)
{
FirstFrm.ActiveForm.Close();
}
private void FirstFrm_FormClosed(object sender, FormClosedEventArgs e)
{
SecounfFrm frm = new SecounfFrm ();
frm.ShowDialog();
}
or you can do somting like that :
private void btnCloseForm_Click(object sender, EventArgs e)
{
this.Hide();
}
private void FirstFrm_VisibleChanged(object sender, EventArgs e)
{
if(this.Visible == false)
{
this.Close();
}
}
private void FirstFrm_FormClosed(object sender, FormClosedEventArgs e)
{
SecounfFrm frm = new SecounfFrm ();
frm.ShowDialog();
}