WPF Create sibling window and close current one - c#

What I need is such an event handler in my window class.
void someEventHandler(object sender, RoutedEventArgs e)
{
MyNewWindow mnw = new MyNewWindow();
mnw.Owner = Window.GetWindow(this);
mnw.ShowDialog();
this.Close();
}
Window.GetWindow(this) returns the parent window of the current window.
I had thought when the owner of the new window is the parent window of the current one, it would wait for the parent; and not the current one. But it did not work that way. Current window waits for the execution of the new and closes only after.
If I use Show() instead of ShowDialog() for some reason the window is not shown at all.
Probably I need some delegate methods but I am not sure where to start.
Edit: I guess I need to improve the question for future references:
The new window should be a dialog to the parent window. If I use Show() the parent window becomes accesible and I dont want that. If I use ShowDialog() it becomes a dialog to the current window, meaning that the current window does not close until the new window is closed, and I dont want that either.

Closing a window causes any windows that it owns to be closed.
If you just want the owner window to not be visible, try this;
void someEventHandler(object sender, RoutedEventArgs e)
{
MyNewWindow mnw = new MyNewWindow();
mnw.Owner = this;
this.Hide(); // not required if using the child events below
mnw.ShowDialog();
}
You'll likely want to hook up some event in the parent window that acts accordingly when you close the child window depending on your requirements.
EDIT
You could perhaps control the hiding of the (multiple parents) from the child;
void OnLoad(object sender, RoutedEventArgs e)
{
this.Owner.Hide();
}
void Closed(object sender, RoutedEventArgs e)
{
this.Owner.Show();
}

If I understand what you're trying to do you want to close the current window and replace it with a MyNewWindow that is a child of the window that was the original window's parent (probably the app's main window).
To do that you should be using:
mnw.Owner = this.Owner;
instead of calling GetWindow, which gives you back the current Window instance. The purpose of GetWindow is to obtain the Window which contains some other UIElement, like a Button farther down the tree. When passing in a Window instance, you just get back what you passed in.

Calling ShowDialog() blocks. That means, the method returns only when mnw is closed and only then is the original window closed.
If you change that to Show(), mnw is closed as soon as you call Close() on the original window. because Window.GetWindow(this) returns this. Thus, you set the owner to this and when you close this, mnw gets closed too. That leaves us with:
MyNewWindow mnw = new MyNewWindow();
mnw.Owner = this.Owner; // may not be necessary
mnw.Show();
this.Close();
This code seems to work for me.

Related

Is ShowDialog handled differently in WPF than Winforms?

I have another issue in converting my Winforms program to a WPF program. In my first program, I had a smaller window open to allow the user to adjust some data, and then when it closed, the other form was activated again with the new data.
I used form2.ShowDialog(); to open the form, which automatically makes the parent form deactivated in Winforms. This way when I closed form2, the parent form was activated, and I was able to use an event handler form1_Activated to reload and re-initialize some of the settings successfully.
However, now when I attempt to do the same thing with WPF, I am still able to open form2 using form2.ShowDialog();, but then when I close the form, it does not register the form1_Activated event handler. Instead, in order to reload the settings, I must click on another window, and then come back into my program to register the form1_Activated event handler.
Am I just doing something wrong, or is there another event handler that I should be using in WPF to achieve the same thing I was able to do in Winforms?
Calling ShowDialog() causes the dialog box top appear in modal mode so I don't understand why you would need an event handler to process the results after the dialog box is closed. Keep in mind that you can access public variables in the DialogBox, as well. If I understand your question, this should do what you are asking:
MainWindow:
My_DialogBox dlg = new My_DialogBox();
dlg.Owner = this;
dlg.MyPublicVariable = ''; //some value that you might need to pass to the dialog
dlg.ShowDialog(); //exection of MainWindow is suspended until dialog box is closed
if (dlg.DialogResult == true)
{
//dlg.MyPublicVariable is still accessible
//call whatever routines you need in order to refresh the main form's data
}
DialogBox:
private void OK_Button_Click(object sender, RoutedEventArgs e)
{
MyPublic variable = something; //accessible after the dialog has closed.
this.DialogResult = true;
}
private void Cancel_Button_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = false;
}
The MSDN write-up on dialog boxes is pretty good. There may be some tips that might help you even more:
http://msdn.microsoft.com/en-us/library/aa969773.aspx
Good luck!

How do I return to a window after opening a second?

My application is of such a nature that I need to jump around many windows consecutively. From my menu window I need to open another window (from the selection) and the disable or close the menu window.
What I'm currently using is window.show and then this.close() method to close the menu window.
Ex:
private void MainMenuControl_Link1MouseDown(object sender, RoutedEventArgs e)
{
// Utilities
UtilitiesMenyWindow UtilitiesMenyWindow = new UtilitiesMenyWindow(); // Assign Variable to window
UtilitiesMenyWindow.Show(); // Open window
this.Close(); // close current window
}
Then from within the new windows I just reopen the MainMenu window using the same method.
private void Utilities_Link3MouseDown(object sender, RoutedEventArgs e)
{
// Return to Main
MainMenuWindow MainMenu = new MainMenuWindow(); // Assign Variable to window
MainMenu.Show(); // Open Main window
this.Close(); // close login window
}
I then also keep a public variable class with static variables to store all the variables that are generic to all the windows.
All this is working fine for me except for one snag. If I were to call the UtilitiesMenyWindow from another window (not MainWindow) it's going to return to the MainMenu instead of the window I opened it from.
Is there a easier more generic way to return to the window that opened the secondary window without having to tell it to close itself and open a specific window (in this case it's "hardcoded" to MainMenu) (Obviously I first open and then close)
I was looking at the Unloaded event but how do I get the original window to stay hidden until this event occurs without it having to sit there and wait in a loop which is not a good idea.
Maybe somebody can guide me in a way to set it up as an automatic event that "fires" the event-handler, which in turn then activates the previous window?
Rather than closing windows, you could consider hiding them. That way, you could pass a reference to the calling window whenever you create a new window.
i.e.
UtilitiesMenyWindow UtilitiesMenyWindow = new UtilitiesMenyWindow();
UtilitiesMenyWindow.CallingWindow = this;
UtilitiesMenyWindow.Show();
this.Hide();
then, when you want to close the new window and return:
this.Hide();
this.CallingWindow.Show();
You could just close the original window - since all your windows are probably inheriting from Window class you just need to store the current window in a 'Window' typed variable on the utilities menu
This way you can continue doing what you are doing:
e.g.
private void MainMenuControl_Link1MouseDown(object sender, RoutedEventArgs e)
{
// Utilities
UtilitiesMenyWindow UtilitiesMenyWindow = new UtilitiesMenyWindow(); // Assign Variable to window
UtilitiesMenyWindow.ReturnWindow = this;
UtilitiesMenyWindow.Show(); // Open window
this.Hide(); // hide current window
}
And add
Window _returnWindow;
on your utility window class
Then in that class on the close method you can call the original window type:
private void Utilities_Link3MouseDown(object sender, RoutedEventArgs e)
{
// Return to original
_returnWindow.Show();
this.Close(); // close login window
}
This is of course assuming you don't kill the original window

Closing a secondary window completely

It appears that second windows are not closing. Here is what I am doing....
I have created a new WPF project.
I placed a button in the main window.
I put the following code in the button to launch a second window and hide the main.
private void button1_Click(object sender, RoutedEventArgs e)
{
var projectWindow = new NewProjectInfo();
this.Hide();
projectWindow.Show();
}
-The new window is a blank window with nothing on it.
-In the "close" event of the new window I put the code to show the main window again.
private void Window_Closed(object sender, EventArgs e)
{
var mainWindow = new MainWindow();
mainWindow.Show();
}
If I run the program and close the main window without opening the second window, the programs ends like I would like it to.
If I click the button on the main window, taking me to the second window, then close that window, taking me back to the main window, then close the main window the program does not end. (meaning I have to hit the stop button in visual studio to get it to end)
It's like visiting the second window leaves some kind of process running.
So, when I close the main window I can just run the:
Application.Current.Close();
But is that safe? Do I run the chance of leaving something hanging? Or is there a better way to close that second window so when I close the main the program will end?
These lines
var mainWindow = new MainWindow();
mainWindow.Show();
create a new MainWindow and show it. The original MainWindow is still hidden.
To resolve your problem, you need a reference to the original MainWindow instance.
Perhaps you could pass this reference when you build your secondary window
// Create a NewProjectInfo instance and pass this
var projectWindow = new NewProjectInfo(this);
this.Hide();
projectWindow.Show();
And in the constructor of the projectWindow, save the reference passed in a global var
var MainWindow _originalReference;
public NewProjectInfo(MainWindow original)
{
_originalReference = original;
}
now the window close event could use the referenced window
private void Window_Closed(object sender, EventArgs e)
{
_originalReference.Show();
}
Instead of creating a new Main window, can you simply call Application.Current.MainWindow.Show(); in your closed event handler?

Controls disposed second time form is opened

The first time I open one of my child forms from the main form it opens normally. If I close the first instance of the child form and then reopen it however I get a crash the first time I try to call CreateGraphics() outside of the OnPaint() method. The exception I get is: "Cannot access a disposed object. Object name: 'MyControlClass'."
I've set breakpoints to monitor what's going on. Dispose() is called as expected the first time I close the form. When I start the form the second time MyControlClass's constructor is called, and the Dispose method isn't called prior to the exception. At the point of the exception this is still valid. Because of that I'm wondering if somehow it's actually the static component of MyControlClass that ended up being disposed; not the instance object.
I am creating a new copy of the form each time the button to show it is called. MyChildForm is a member held by my mt parentform and is also used to prevent multiple copies of the form from being opened at once.
ShowMyForm()
{
myChildForm = new myChildForm Form();
myChildForm.FormClosed += myChildFormFormClosed;
myChildForm.Show();
}
private void myChildFormFormClosed(object sender, FormClosedEventArgs e)
{
myChildForm = null;
}
The line of code that crashes: MyControlClass inherits from MyControlClassBase, which in turn inherits from MyControlClassBaseBase. This line of code is triggered by a mouse event in MyControlClassBase and is in MyControlClassBaseBase. The code after this would take a cached image of MyControl, display it using the newly created Graphics object, and then draw an overlay based on the mouse cursor position.
Graphics g = CreateGraphics();
PS Since I'm sure someone will ask: The rube goldberg in question is due to the utter fail that is fake 'transparency' in winforms in any but the most trivial cases and the fact that MyControlClass takes too long to paint to keep up with the mouse cursor; but that's a separate question entirely.
After a form is closed, it is disposed - meaning that it exists just to read fields.
If you want to show the same form again, create another instance or just hide it instead of closing.
MyForm f = new MyForm();
f.Show();
// After closed, it will be disposed.
So we need to do the same steps to show it again:
f = new MyForm();
f.Show();
Now you will get a brand new and identical form.
But to hide it when closed, you might need this code:
private void MyForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true;
Hide();
}
}
Note that it will not work with modal forms. (ShowDialog();)
(Thanks to Sorax) This will also not work with MDI children.

Communication between parent and child window in wpf

I have a parent window which launches a child window, after doing some selection/operation in the child window is closed and I want to send some info back to the parent window (a custom class object), what's the best way to accomplish this in WPF using the features provided by WPF?
You have many options:
You could use a custom event in your child window that the parent window listens to
You could define a delegate in the child window that references a method in the parent window
You could change the constructor for the child window to take a reference to the parent window and call a method on the parent window using that reference
You could possibly use the VisualTreeHelper class to get the parent window and call a method on that reference
Extracted from this link:
The easiest way I have found to pass data from a child window to a
parent window is to use an application wide property. This property is
an object, and is not the most elegant form to pass data from a child
window to a parent, but it's the least amount of programming. The best
way to do this is using get and set accessor properties.
Create a main window (mainWindow) Create a child window (in this case,
Password)
In the main window, the child window must be shown, say, within a
button click. This window would have a button to do something, in this
case, it's to delete a record from the database.
private void btnDelete_Click(object sender, RoutedEventArgs e)
{
Password passwordentry = new Password();
passwordentry.ShowDialog();
if (Application.Current.Properties["PassGate"].ToString() == "mypassword")
{
Code, or call to delete the record;
}
Application.Current.Properties["PassGate"] = "";
}
In the child window (Password), the property for the application is
set using a textbox. This is a simple window that has a textbox called
PasswordTextBox and a couple of buttons, like Accept and Cancel.
private void AcceptButton_Click(object sender, RoutedEventArgs e)
{
Application.Current.Properties["PassGate"] = PasswordTextBox.Text;
this.Close();
}

Categories

Resources