WPF application is not closing correctly - wpf

I am calling Application.Current.Shutdown() from a class that is bound to xaml windows with ObjectDataProvider, but the application is not closing. Can anyone help me to understand why? My application is not closing completely after my main window is closed, it doesn't disappear from task manager's process list.

Try Environment.Exit(0) instead

Have you created any threads to do background processing? If you have, make sure to set the .IsBackground property on them, or they can keep the app running

Don't forget to add this:
private void Window_Closed(object sender, EventArgs e)
{
Application.Current.Shutdown();
}
Hope this helps.

If you have multiple windows or dialogs in your application, you may need to close each one explicitly.
Close dialogs with:
_myDialog.Close();
Close all windows:
foreach(var window in Application.Current.Windows.ToList())
{
window.Close();
}

I had a problem where the application would not shut down even when main window was closed. It turned out I had done Hide() on the splash screen instead of Close() so it was still lurking in the background keeping the application alive.

I had the same problem, the application process doesn't stop although the application closed.
In my case I opened a window from a BackgroundWorker (code below)
BackgroundWorker BG = new BackgroundWorker();
BG.DoWork += new DoWorkEventHandler(BG_DoWork);
StockMinWindow MinWindow = new StockMinWindow(null); -------- this is the problem
BG.RunWorkerAsync();
instanciate the window before running the BackgroundWorker seem not being the problem but by erasing the line the application closed correctly
I open my window from the BackgroundWorker but using the principal Thread (code below)
View.Dispatcher.BeginInvoke(new Action(delegate()
{
StockMinWindow MinWindow = new StockMinWindow(StockMinList);
MinWindow.Owner = View;
MinWindow.ShowDialog();
}));
Hope it helps.

Related

How to re-open the closed window?

i've seen so many samples that in order to open closed window i should hide the window in closing event, but this is not fair for me if i close window in middle of my work and again open same window it showing me content where i left because i'm hiding window previously. So how can i start freshly my window after closed or hide the window.
currently i'm calling winload method which is to show fresh window after calling the show method of a hide window.
private PurgeData data=new PurgeData();
private void MenuPurgeData_Click(object sender, RoutedEventArgs e)
{
try
{
if (PurgeData == null)
{
PurgeData = new PurgeData();
PurgeData.Show();
}
else
{
PurgeData.WinLoad();
PurgeData.Show();
}
}
Thanks,
#nagaraju.
If you want the behaviour of hide/show, you should not call Window.Close() on the window at all, but hide it by calling Window.Hide(). If the user has closed it though and a close is unavoidable, you can try the following. Override OnClosing inside the Window and set e.Cancelled to true, then call .Hide(). This should allow the window to be hidden/shown even if the user closes the window.
// Disclaimer, untested!
protected override void OnClosing(CancelEventArgs e)
{
e.Cancel = true; // cancels the window close
this.Hide(); // Programmatically hides the window
}
EDIT:
Ok I've now read your question properly ;-)
So how can i start freshly my window after closed or hide the window.
When you re-show the window using the above, it will of course be the same instance as the one that was previously hidden, hence will have the same data and state. If you want completely new contents you need to create a new Window() and call Window.Show() on that. If you hide/show as above then you'll get the window back in exactly the same state before it was hidden.
Are you using the MVVM pattern in your WPF application? If so, you could try the following. By having all the data in your ViewModel and bound to by the View (ie: no business logic or data in the code behind of the Window), then you could invoke a method on the ViewModel to reset all data when the window is shown. Your bindings will refresh and the window state will be reset. Note this will only work if you have correctly followed MVVM and bound all elements on the main form to ViewModel properties (including sub controls).
Best regards,
It really depends on the structure of your app. Since you're not maintaining state, you only need to save the actual type of window that was closed. Depending on what type of window you're using, you can assign it an ID (e.g. in its Tag property) so that it can be recognized later. You can then push this ID during the Closing event in a Stack. Then, if the user reopens it, pop the stack to get the ID and check what window that corresponds to. You can then reopen that window.
Of course, Stack is just one data structure and it may or may not be suitable for you. Using a Stack means that user can reopen all the past windows they closed, but maybe you might just want the one window instead.
Edit - basic code:
//create an enum to make it easy to recognise the type of window that was open
enum WindowType { Profile, Settings };
//create a stack to hold the list of past windows
Stack<WindowType> pastWindows = new Stack<WindowType>();
//give the window type a particular id
profileWindow.Tag = WindowType.Profile;
//open the window
profileWindow.Show();
//in the closing event, if you want the user to be able to reopen this window, push it to the stack
protected override void OnClosing(CancelEventArgs e)
{
pastWindows.Push(WindowType.Profile); //or whatever type it was
base.OnClosing(e);
}
//to reopen the last window
void ReopenLastWindow()
{
WindowType lastType = pastWindows.Pop();
switch(lastType)
{
case WindowType.Profile:
profileWindow.Show();
break;
case WindowType.Settings:
settingsWindow.Show();
break;
default:
break;
}
}
this.Opacity = 0
to "close the window"
this.Opacity = 1
to "re-open it"
A remark concerning the Hide() method: from another class, the window will in fact be considered as closed and the code will continue after a ShowDialog() method usage. Using the "Opacity" property overrides the problem.

wpf BackgroundWorker - Regarding updating UI

I use a browse for files dialog to allow a user to select multiple images. If a lot of images are selected, as expected it takes a bit. Below is an example of what I do with the selected images. I loop through the filepaths to images and create an instance of a user control, the user control has an Image control and a few other controls. I create the instance of this control then add it to a existing stackPanel created in the associating window xaml file. The example just below works fine, but I'm trying to understand BackGroundWorker better, I get the basics of how to set it up, with it's events, and pass back a value that could update a progress bar, but because my loop that takes up time below adds the usercontrol instance to an existing stackPanel, It won't work, being in a different thread. Is BackGroundWorker something that would work for an example like this? If so, what's the best way to update the ui (my stackpanel) that is outside the thread. I'm fairly new to wpf and have never used the BackGroundWorker besides testing having it just update progress with a int value, so I hope this question makes sense, if I'm way off target just let me know. Thanks for any thoughts.
Example of how I'm doing it now, which does work fine.
protected void myMethod(string[] fileNames) {
MyUserControl uc;
foreach (String imagePath in fileNames) {
uc = new MyUserControl();
uc.setImage(imagePath);
stackPanel.Children.Add(uc);
progressBar.Value = ++counter;
progressBar.Refresh();
}
}
below this class i have this so I can have the progressBar refresh:
public static class extensionRefresh {
private static Action EmptyDelegate = delegate() { };
public static void Refresh(this UIElement uiElement) {
uiElement.Dispatcher.Invoke(DispatcherPriority.Background, EmptyDelegate);
}
}
Check out this article on
Building more responsive apps with the Dispatcher
Now that you have a sense of how the Dispatcher works, you might be surprised to know that you will not find use for it in most cases. In Windows Forms 2.0, Microsoft introduced a class for non-UI thread handling to simplify the development model for user interface developers. This class is called the BackgroundWorker
In WPF, this model is extended with a DispatcherSynchronizationContext class. By using BackgroundWorker, the Dispatcher is being employed automatically to invoke cross-thread method calls. The good news is that since you are probably already familiar with this common pattern, you can continue using BackgroundWorker in your new WPF projects
Basically the approach is
BackgroundWorker _backgroundWorker = new BackgroundWorker();
// Set up the Background Worker Events
_backgroundWorker.DoWork += _backgroundWorker_DoWork;
_backgroundWorker.RunWorkerCompleted += _backgroundWorker_RunWorkerCompleted;
// Run the Background Worker
_backgroundWorker.RunWorkerAsync(5000);
// Worker Method
void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
// Do something
}
// Completed Method
void _backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Doing UI stuff
if (e.Cancelled)
{
statusText.Text = "Cancelled";
}
else if (e.Error != null)
{
statusText.Text = "Exception Thrown";
}
else
{
statusText.Text = "Completed";
}
}
Using a BackgroundWorker alone won't solve your issue since elements created during the DoWork portion will still have originated from a non-UI thread. You must call Freeze on any objects you intend to use on another thread. However only certain UI objects will be freezable. You may have to load in the images as BitmapImages on the background thread, then create the rest of your user control on the UI thread. This may still accomplish your goals, since loading in the image is probably the most heavyweight operation.
Just remember to set BitmapImage.CacheOption to OnLoad, so it actually loads up the image when you create the object rather than waiting until it needs to be displayed.

My application loses focus when a window is closed

I have a simple two forms, one that contains a grid and a button. When I click the button, my application starts doing a long operation. While it is working, I show another form that contains a progress bar
I open it like this:
_busyWindow.ShowDialog();
And defined
public partial class BusyWindow : DevExpress.XtraEditors.XtraForm
{
public BusyWindow()
{
InitializeComponent();
}
private void BusyWindow_FormClosing(object sender, FormClosingEventArgs e)
{
this.Hide();
e.Cancel = true; // this cancels the close event.
}
}
When the operation is finished, I hide the form like this
if (ended)
_busyWindow.Hide();
It works fine. The problem is that when I close the second form (same closing code), it also closes fine but my main GUI loses the focus. For example, if I have the Firefox opened behind the application, then the Firefox gets the focus.
This only happens when I close the second form when the busyWindow has been opened, and no when it hasn't (ie, if I open the form, I close it without clicking on the button, then the main GUI doesn't lose the focus).
Do you know what is happening or where could I try to search?
There could be two possible solutions to enable you to keep focus on your main window:
//Edited: Main Window in the below example would be the window with Grid and Button.
Since you are showing the busy window via ShowDialog() try setting the owner of the window by this: _busyWindow.ShowDialog(this);. I had earlier faced a similar problem and this worked for me. Since you specify the owner of the busyWindow, when it closes it would put the focus back on its owner,i.e. your main window
In case the above technique doesnt work (it should, as it worked for me), you could try to pass the reference of the main window to the busyWindow and then on its close set the focus of the main window. Sample:
_busyWindow.MyMainWindow = this; //MyMainWindow references mainWindow of your app
_busyWindow.ShowDialog();
And the following at the FormClosing of busyWindow:
private void BusyWindow_FormClosing(object sender, FormClosingEventArgs e)
{
this.Hide();
e.Cancel = true; // this cancels the close event.
MainWindow.Focus();
}
See if it works. The first solution should work.
Hope it helps.
Thanks & Happy Windowing!
Just set child's window Owner = null before closing it

WPF ComboBox DropDown part appears in the wrong place

I put several ComboBoxes on a XAML window. When I expand any of them, the DropDown part appears on the upper left corner of the screen.
I use Visual Studio 2008 C# Express. I don't remember this phenomenon when I used Visual Studio 2008 (Trial Version), though I use the same FrameWork (3.5).
It seems to be a bug.
Workaround:
Use Window.Show() instead with a custom logic to simulate the ShowDialog() behavior.
This appears to be a bug in WPF. In my case, I was trying to open a window in the Loaded event of another window. To get around this, I set a timer up to fire, then used a delegate to open the window (cannot open the window in a timer event because the calling thread that opens a window must be STA).
Edit - timer isn't necessary - didn't see the answer above just queue it on the dispatcher...
private delegate void DelegateOpenWindow();
private DelegateOpenWindow m_DelegateOpenWindow;
private Timer loginTimer = new Timer(200);
private void MainWindow1_Loaded(object sender, RoutedEventArgs e)
{
// create delegate used for asynchronous call
m_DelegateOpenWindow= new DelegateOpenWindow(this.OpenWindow);
// start a timer to fire off the open window.
loginTimer.Elapsed += loginTimer_Elapsed;
loginTimer.Enabled = true;
}
void loginTimer_Elapsed(object sender, ElapsedEventArgs e)
{
loginTimer.Enabled = false;
this.Dispatcher.BeginInvoke(m_DelegateOpenWindow);
}
void OpenWindow()
{
MyWindow w = new MyWindow();
w.Owner = this;
w.ShowDialog();
}
I started observing this (and other strange behavioral quirks) yesterday when I tried to "tweak" window sizes, shapes, colors, and invoke a log-on dialog from the Window.Loaded event handler. I had been doing this just fine in each of a dozen+ individual "MVVM" pattern apps. Yesterday, I decided to move this from each app's code behind into a consolidated code-behind base class, since the pre-processing had become common in all those apps. When I did, the drop-downs in two ComboBoxes in the log-in dialog suddenly appeared in the upper left corner of my screen. I seem to have "solved" it by using the following technique (your mileage may vary):
protected void WindowBaseLoadedHandler(object sender, RoutedEventArgs e)
{
...non-essential lines of code removed...
if (DataContext != null)
{
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
{
/*----------------------------------------------------------------------
* Do we have a View Model? If so, perform standard VM Initialization...
*---------------------------------------------------------------------*/
this.IsEnabled = false;
LoginDlg loginDlg = new LoginDlg();
loginDlg.ShowDialog();
if (!loginDlg.Success)
{
/*-----------------------------------
* Log on failed -- terminate app...
*----------------------------------*/
...termination logic removed...
}
this.IsEnabled = true;
}));
}
WindowBaseLoadedHandler is the Loaded event handler. LoginDlg is a WPF app with a dialog containing two ComboBoxes.
Recap: After I consolidated the code into the Loaded event handler of the base class the ComboBox's drop down lists appeared in the upper left corner of my screen. Once I wrapped the logic into the Dispatcher.BeginInvoke call, the appropriate ComboBox behavior returned with lists below the current item.
I suspect WPF needs the application to return from the Loaded event to complete the layout system's initialization. That doesn't fully explain why it worked before, but I'll have to queue up my desire to hunt that "why" down for some rainy day in the future and celebrate overcoming the latest obstacle for today.
In any event, I hope someone finds this of use.
I'm using the latest .Net 4.5 and WPF framework and I still have this problem. One thing I noticed is that it only happen when there's an attached debugger. When the debugger is not attached, everything works fine.
I had the same problem on Visual Studio 2019.
Using window.Show() can help but it can ruin your design.
The solution is to open the window asynchronously.
var yourDialog= new YourDialog();
yourDialog.Owner = this;
TaskCompletionSource<bool?> completion = new TaskCompletionSource<bool?>();
this.Dispatcher.BeginInvoke(new Action(() =>
completion.SetResult(yourDialog.ShowDialog())));
bool? result = await completion.Task;
You can also create a more elegant solution by making the extension method:
public static class AsyncWindowExtension
{
public static Task<bool?> ShowDialogAsync(this Window self)
{
if (self == null) throw new ArgumentNullException("self");
TaskCompletionSource<bool?> completion = new TaskCompletionSource<bool?>();
self.Dispatcher.BeginInvoke(new Action(() => completion.SetResult(self.ShowDialog())));
return completion.Task;
}
}
And you can use it like this:
await dlgReview.ShowDialogAsync();
It’s a bug in WPF (not the only one, I'm afraid). It happened when I opened another window in the Loaded Event, something like:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
Window selectionWindow = new SelectionWindow();
bool? result = selectionWindow.ShowDialog();
if (result == true)
RecordChanged();
}
I already found a workabout.

In WPF how to show changed state on controls before and after a time-intensive process completes?

The LoadIt() method below takes 5-10 seconds to complete.
I want the message area to display "Loading..." before LoadIt() starts and display "Reloaded" after it finishes.
How can I do that?
The following code doesn't work. It seems to not update the label until everything is finished, at which point it just displays "Reloaded" again.
private void Button_Click(object sender, RoutedEventArgs e)
{
lblMessage.Text = "Loading...";
LoadIt();
lblMessage.Text = "Reloaded";
}
There's more than one solution discussed here:
http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/6fce9b7b-4a13-4c8d-8c3e-562667851baa/
you could move LoadIt to a separate thread, or you could simulate the WinForms Application.DoEvents but this is quite a hack (http://shevaspace.spaces.live.com/blog/cns!FD9A0F1F8DD06954!526.entry)
You can use the Dispatcher object to start tasks in the background thread:
public delegate void LoadItDelegate();
this.Dispatcher.BeginInvoke(
System.Windows.Threading.DispatcherPriority.Background,
new LoadItDelegate(LoadIt));
Make sure its in the background, because the UI thread has more priority, so the UI gets updated.. and also move your "I am done message" to the end of your LoadIt method :)

Resources