Window or class library isn't closing - c#

If i close my application with the X Button, something is still open and i have to close it via the stop button on visual studio.
It only happens when i open a second window which uses a lot of class librarys.
is there any way to determinate which part of the application is still running?

It isn't enough information for finding a fix for me. But I guess that some of your background processes aren't closed or something similar. You have to check your background processes more deeply.
I recommend you to use Parallel Tasks and Parallel Stacks windows. You could read there more about them:
How to: Use the Parallel Watch Window
Using the Parallel Stacks Window
Walkthrough: Debugging a Parallel Application
I think that this could help find a reason for such behaviour.

Go to your app.xaml and after StartupUri="..." add this ShutdownMode="OnMainWindowClose". That should solve your problem.

In your MainWindow.Xaml add Close event
<Window x:Class="ExertERPDesktop.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="Auto" Width="Auto" x:Name="window" TabIndex="0" Foreground="#FFFF00FF" Closed="OnClose">
and in your code behind
private void OnClose(object sender, EventArgs e)
{
Application.Current.Shutdown();
}

Related

C# WPF Memory leak when Window has a TabControl with a TabItem (or delayed memory reclaim?)

I experienced what appears to be a very obvious memory leak in an application that would open a settings window containing a TabControl with a number of TabItems. Initially believing that one of the user controls shown must be the culprit I commented out a bunch of things, finally getting out JetBrains dotMemory and making a demo-program.
The issue (I think)
When a Window contains a TabControl with at least one TabItem, when the window is closed, the Window-object still exists. If there are no TabItems in the TabControl, the Window-object is destroyed immediately (as expected).
Retention
According to dotMemory the 'Retention' is from WindowAutomationPeer(._owner), from TabControlAutomationPeer(._parent), from TabItemAutomationPeer(._parent), from ElementProxy(._peer) and then it says "RefCounted handle" at the bottom.
Reproduction
Create a new C# WPF application (Target framework: .NET Framework 4.7.2), named "TabsInWindows"
Add a button to MainWindow:
<Window x:Class="TabsInWindows.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="300" Width="300">
<Grid>
<Button Content="Open tab window" Click="Button_Click"/>
</Grid>
</Window>
Create a new Window, "TabsWindow" with a TabControl and a TabItem:
<Window x:Class="TabsInWindows.TabsWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="TabsWindow" Height="200" Width="300">
<Grid>
<TabControl x:Name="Subject">
<TabItem></TabItem>
</TabControl>
</Grid>
</Window>
Make the button in MainWindow open a new TabWindow
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
//TabsWindow.Open(this);
TabsWindow w = new TabsWindow();
w.Show();
}
}
Start the application. Every time you press the button a new window is created, but the TabItem (?) and therefore the TabWindow remains when the window is closed. (Repeat any number of times)
How to fix?
My issue is that in my actual application all contents of all tabs appears to be retained in memory, causing a significant memory leak.
I have tried, in the demo application, to do a number of things to avoid the hanging objects; Setting content of Grid to null. Clearing the Items in TabControl (Subject). Clearing the Children of the Grid.
None of it has worked.
I cannot work out what the 'AutomationPeer'-objects are or what the ElementProxy is created by and why it won't die.
If anyone can tell me how to get around this issue, or can shed some light on what ElementProxy is and why it is hanging around, it would be most helpful.
While writing this, I did keep dotMemory running with the test app and a while after having done anything last, the objects did appear to have been removed....
Which then raises the question: How long can I expect an object to be visible in memory, with references, before it is removed?
In an actual project
I then tried something similar in an actual project, ensuring that non of our own controls were directly linked to SettingsWindow (I'm not ruling out that I have a memory/reference issue in one of our controls, so any control listed directly in "Key Retention Paths" have been commented out).
I am left with "3 unique branches", one being an 'EffectiveValueEntry[40]' from out own extension of a ListBox, the other two are 'EffectiveValueEntry' ([19] and [22] respectively), both from a TextBlock, from TextBlockAutomationPeer[4], List, ListBoxItemAutomationPeer, ElementProxy.
After about ten minutes of doing nothing, the SettingsWindow was still there, but the "Key Retention Paths" has changed, and the "20 unique branches" are all EffectiveValueEntry ([32] on the first, [42] on the rest), TextBox, TextEditor, but now "F-Reachable Queue" is in the bottom of the list.
After about ten minutes more, the SettingsWindow was finally gone.
I then opened the settings window a few times again, and a minute after closing the last, only the 'TextBox'-references where left and a forced Garbage Collection later (using the button in dotMemory), the object references are gone.
What to believe?
So apparently, if I wait long enough 'magic' will happen - but this is a computer - not a magic-box!
Can anyone enlighten me on why some objects will appear in memory longer, but eventually be removed? How long should I expect such objects to lay about?
I would also like a way to prevent these 'ghost' objects from the TabItems, there should be no reason for them to take up memory if they will eventually be removed anyways...
You see, I discovered this while doing performance testing of some UI components in the SettingsWindow, and repeated tests took longer and longer as more memory was used, so simply waiting for the references to go away is not a very good option.
And if you are unable to help; thank you for taking the time to read my wall of text...
Set the owner of the TabWindow's
private void Button_Click(object sender, RoutedEventArgs e)
{
TabsWindow w = new TabsWindow();
w.Owner = this;
w.Show();
}

Memory Leak on UWP MediaPlayer when looping

We are currently playing a 4K h.265 video in an UWP app as background using MediaPlayerElement. We have set the MediaPlayer to infinite loop using IsLoopingEnabled = true. The problem is, that the memory usage is increasing every time the video loops. If we disable looping, the memory leak does not occure. We tried looping the video manually by resetting the position to zero when the video finished, but still it leaks memory. We also tried to call System.GC.collect() but that also did nothing.
Is this a UWP bug or are we missing something?
Edit:
Here is the code we are using:
MainPage.xaml
<Page
x:Class="MyProject.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MyApp"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="using:MyApp.Controls"
xmlns:xaml="using:Microsoft.Graphics.Canvas.UI.Xaml"
mc:Ignorable="d"
Background="Black" Loaded="MainPage_OnLoaded" Unloaded="MainPage_OnUnloaded">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="{StaticResource AppBrushNewBlue1}">
<MediaPlayerElement Name="bgMovie" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" AreTransportControlsEnabled="False" ></MediaPlayerElement>
<Canvas Name="mainCanvas" ManipulationMode="None" Background="Transparent">
</Canvas>
</Grid>
MainPage.xaml.cs
private MediaSource ms;
private async void MainPage_OnLoaded(object sender, RoutedEventArgs e)
{
ms = MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/bg_animation_V2.mp4"));
bgMovie.Source = ms;
bgMovie.MediaPlayer.IsLoopingEnabled = true;
bgMovie.MediaPlayer.Play();
[...]
}
We are not doing anything more with the MediaSource or the mediaPlayer itself. When we disable IsLoopingEnabled no memory leak occurs anymore.
As stated here https://stackoverflow.com/a/54947557/1018232 this seems to be a bug in Windows 10. Even the builtin video player "Movies and TV" has this issue. It seems this only happens on h.265 codec. Maybe it is a decoder driver bug or something like this.
There is always a confusing amount of different Media Player elements in WPF. You are using teh MediaPlayerElement. And it's documentation explicitly mentions that it is still in a open Beta-ish phase:
This control is currently available as a developer preview for Windows 10, version 1903, and later. Although we encourage you to try out this control in your own prototype code now, we do not recommend that you use it in production code at this time. For more information, see the XAML Islands feature roadmap. If you have feedback about this control, create a new issue in the Microsoft.Toolkit.Win32 repo and leave your comments there. If you prefer to submit your feedback privately, you can send it to XamlIslandsFeedback#microsoft.com.
So it is entirely possible you just found a bug.
As far as I can tell, the approach to playing Media before the MPE is the Storyboard and the MediaPlayer/MediaElement combination. As far as I can tell, MediaPlayer has no repeat mode. So a event will have to do. Someone with deeper WPF/UWP knowledge will have to tell you wich one is the right one for the time being.

Creating a scalable 'Application grouping/Hub' in WPF

I would like to find an elegant way of creating a 'hub' for applications in WPF (C#).
What I mean is, say, I have three applications AppA, AppB and AppC, which may have very different UIs (and logic) each, What I would like to achieve, is to have one 'landing page' that contains icons for each of the three applications.
Now, when the user clicks on one of the icons, the 'Overall Application' redirects the user to the UI for that specific clicked application.
I can think of two ways to achieve this:
1) Have a MainWindow with 3 images, and on ImageA_Click --> Another Window appears with the UI for AppA.
2) Have a MainWindow with a Tabcontrol that has 3 Tabs (each tab corresponding to each of the 3 Apps) --> Clicking on one tab directs the user to the specific UI for the App clicked.
What I want is to have an architecture that is scalable, meaning, say tomorrow, I have to develop 10 more apps, I want to be able to quickly (and painlessly) integrate the additional 10 Apps in the overall solution.
What is the best way to achieve this?
(Note that I am using the MVC pattern for each of the Apps - Not sure if that makes any difference)
I appreciate any help!
You can design the every app ui in separate page then using frame and navigation service access to them. Like this:
MainWindow.xaml:
<Window x:Class="Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
Loaded="MainWindow_OnLoaded">
<Grid>
<Frame Name="MainFrame"/>
</Grid>
</Window>
MainWindow.xaml.cs:
using System.Windows;
namespace Test
{
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
}
private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
{
MainFrame.NavigationService.Navigate(new HomePage());
// OR
MainFrame.NavigationService.Navigate(new App1Page());
// OR
MainFrame.NavigationService.Navigate(new App2Page());
// OR
MainFrame.NavigationService.Navigate(new App3Page());
}
}
}

WPF Application wide capture of key up/down events

I'm trying to capture keypress events anywhere in my WPF application, regardless of which UI element has the focus. Currently I'm having no luck. Can anyone suggest some strategies that I might not have tried? Or, ideally, provide an answer like "oh that's easy, you just do this".
It's a distributed application, which has a chat system. The effect that I'm looking for is that the user can start typing a chat message at any time, without switching to a standard chat box. I'll display their message in the application myself, using FormattedText objects. This is important because it means there are no text input elements in the application anywhere.
My XAML structure looks roughly like:
<MainWindow>
<Canvas 1>
<Canvas 2>
<Image 1 />
</Canvas 2>
<Image 2 />
</Canvas 1>
</MainWindow>
I programmatically add elements into Canvas 2, and manipulate Image 2, which is why it has that structure.
I've tried adding KeyDown, KeyUp and the Preview events to MainWindow and Canvas 1, but none of them seem to fire (I check with breakpoints). I've also, after reading another related question here, tried manually setting the focus on the main window in the Loaded() method.
I realise there are many related questions on this site, but they haven't helped me because:
there aren't any answers (will my question be answered?)
they assume a text entry widget and are interested in bubbling up events
they want a keybinding for a small number of keys - I would like to capture any key
they are interested in detecting if a control/shift/alt key is down after they've already captured the event
Thank you for taking the time to read my long winded post, and thank you for suggestions.
Update (After Rachel's comment) When I put in a TextBox and set the focus to the TextBox, a key event method at the MainWindow level will fire. So that works as advertised.
However, I would really like to not have an explicit text entry widget in the application at all. I would like the user to be able to just start typing to compose a message.
A little bit of tinkering got me this:
XAML:
<Window x:Class="KeyInput.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="100" Width="225">
<Canvas>
<Grid>
<Label Name="test" Content="Empty" />
</Grid>
</Canvas>
</Window>
CS:
using System.Windows;
using System.Windows.Input;
namespace KeyInput
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.KeyDown += new KeyEventHandler(OnButtonKeyDown);
}
private void OnButtonKeyDown(object sender, KeyEventArgs e)
{
test.Content = test.Content + e.Key.ToString();
}
}
}
This prints out stuff like "Shift" So you'd obviously have to use switches... but it has a Text Box that collects key presses.
I managed to work it out, inspired by answers from Rachel and WernerCD. As they both demonstrated, having the event capture at the MainWindow level does work. The problem was that I neglected to mention that I had a dialog before the MainWindow loaded, which seems to interfere with normal keyboard focus on the MainWindow. Putting explicit Keyboard.focus() in the Loaded() method is too soon. I fixed the problem by putting Keyboard.focus() in the MainWindow_ContentRendered() method.
All is now well (until the next issue anyway). Thank you for the help.
I usually add a PreviewKeyDown event to the MainWindow.
Perhaps your problem is you don't have any control that accepts keyboard focus on your application. Do you get the same results if you add a TextBox to the MainWindow and have focus set there?

Memory leak when using WPF WebBrowser control in multiple windows

I am working on a project that makes use of the WPF WebBrowser control (System.Windows.Controls.WebBrowser). The web browser element of the program is one of many activities the user can engage in, and is opened in a separate window. After the user navigates away from the browser, the window is closed, and a new window is created each time the user returns to the browser. We were noticing a significant memory leak / performance downgrade in our program (usage getting up to ~700mb from ~200 initial) upon continually using the browser. After failing to find any points of resource leaks within our own code, I decided to determine if the issue was with our own WebBrowser wrapper control, or the WPF control.
I created a new simple project consisting of only a MainWindow and a WebWindow. A button on the main window launches a browser directed at gmail (the site we noticed the biggest issue with of the few we examined). Upon closing this window, there is no freeing of resources (no reduction in VM size in Task Manager or Process Explorer) and the number of GDI objects the process has handles to does not decrease (the program starts with ~30, opening the browser takes it to ~140 and after closing the browser ~140 are still open). Opening another browser causes more handles, and more resources to be allocated. Furthermore, this problem is not fixed by specifically calling Dispose() on the WebBrowser control. The code is simple, and is as follows:
Main Window:
<Window x:Class="WebBrowserMemory.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<Button Click="Button_Click">Gmail</Button>
</StackPanel>
</Grid>
</Window>
Button_Click:
private void Button_Click(object sender, RoutedEventArgs e)
{
var win = new WebWindow();
win.Show();
win.Browser.Navigate("http://www.gmail.com");
}
Web Window:
<Window x:Class="WebBrowserMemory.WebWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WebWindow" Height="300" Width="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<WebBrowser Grid.Row="0" x:Name="_browser" />
<Button Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="10" Padding="10" Click="Button_Click">Close</Button>
</Grid>
</Window>
Relevant Code:
public WebBrowser Browser {
get { return _browser; }
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Close();
}
protected override void OnClosed(EventArgs e)
{
_browser.Dispose();
base.OnClosed(e);
}
Has anyone else encountered this issue using the WPF WebBrowser control?
[UPDATE: Updated post to indicate Dispose() call as per itowlson's answer - even calling Dispose() on the web browser control does not free the resources]
Unlike most WPF controls, WebBrowser (because it inherits from HwndHost) is IDisposable and encapsulates unmanaged resources. The WPF Window, unlike the WinForms Form, does not automatically dispose its children (because native WPF controls do not encapsulate unmanaged resources and do not require disposal).
Add an OnClosed override to your window (or handle the Closed event), and call Dispose on the WebBrowser control.
I have not been able to completely solve the leak, however,I have noticed that navigating the browser to "about:blank" prior to disposal definitely helps reduce the amount of memory that hangs around.
We instead used WinForm WebBrowser control, which was created inside FormsHost in WPF, however both work pretty same from the UI point of view, but we have found that WebBrowser of WinForms has better functionality and better performance compared to one given in WPF.
You can manually dispose WebBrowser of WinForm control that will certainly dispose all of its children and free resources accordingly, however with my past experience, WinForm's WebBrowser does not release 100% of its resources after closing, but yes it is far better then WPF.

Categories

Resources