Application.LoadComponent makes application freeze on shutdown - wpf

If I use Application.LoadComponent() to load a UserControl, Page or Window, my application freezes when I try to close it.
The app apparently closes, but the process keeps running. Easy to notice when debugging.
I've tested it under Windows 7 64bit and Vista 32bit. In both cases I have used VS2008 and .NET 3.5.
A repro can be built by creating a wpf application as follows:
public partial class Window1 : Window {
public Window1() {
InitializeComponent();
}
public void LoadCopy() {
var uri = new Uri("/WpfApplication1;component/window1.xaml", UriKind.Relative);
var copy = (Window)Application.LoadComponent(uri);
MessageBox.Show(copy.Title);
}
private void Button_Click(object sender, EventArgs e) {
LoadCopy();
}
}
Does anyone know what might be happening? And how to solve it?

Try assigning the owner to the created assembly i.e.
copy.Owner = this;
I was able to close your example after doing this.

I think it is because you are calling LoadComponent() on what is also your Main Window ( http://msdn.microsoft.com/en-us/library/system.windows.application.mainwindow.aspx ), i.e. the startup uri, in your case Window1. The program is probably entering some loop when you close it because closing a Main Window by default shuts down the Application and your two instances of Window1 are waiting on each other (A.K.A. a deadlock)! Albeit seemingly only after making the Application invisible (so it seems to have closed).
If you still must use use LoadComponent() on Window1 I think you would need to not make it your startup uri by changing the StartupUri of your Application:
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml"> <!-- change this -->
</Application>
Or change Application.ShutdownMode ( http://msdn.microsoft.com/en-us/library/system.windows.application.shutdownmode.aspx ) to OnLastWindowClose:
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml"
ShutdownMode="OnLastWindowClose">
</Application>

I have build you application on Windows 7 32bit under .Net 4.0 and 3.5.
I works fine for me. I think you problem is configuration specific.
Which configuration do you have? Do you reference any assemblies except default WPF project references?

Related

Cannot set startup object in WPF VB.NET Project

I am using VS2010 VB.NET, working on a solution that has a number of projects. I have been developing on it for a while now, and in an attempt to debug a custom class inherited from ObservableCollection (which by the way would not load symbols when debugging even though it was apparent that the breakpointed line was being called), I changed the startup object for the startup project to a different WPF window which I had a couple of controls that I set aside for debugging.
Immediately I was confronted with 'Sub Main' was not found in . I tried changing the startup object back to the normal startup window, but now the Startup Object dropdown only has "Sub Main" as it's only option. I changed the StartupURI back in the App.xaml, to no avail.
Anyone else seen this?
How can I get it back to using the original window?
As a side note, is there a setting somewhere that would cause the debugger not to load symbols for an assembly? I know the DiskCollection class is being instantiated, but a breakpoint on the constructor always says Breakpoint cannot be hit, No Symbols loaded.
Cory
The startup in WPF is different then in winforms; it's set by the App.xaml file. Edit that in xaml mode and you will notice this:
<Application x:Class="WpfApplication6.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
The StartupUri sets which form will start things.
If you wanted code to kick things off instead you can remove the StartupUri and do this instead:
Startup="Application_Startup"
Then provide the code in the App.xaml.cs file like so:
public partial class App : Application
{
private void Application_Startup(object sender, StartupEventArgs e)
{
}
}
So aparently in the Project Properties page, the Enable application framework setting was unchecked. this apparently tells the compiler to use the StartupUri attribute to determine the startup page instead of using the main sub (or method; does this setting appear in C#?).
Somehow the setting was unchecked and so Sub Main was the only option in the StartupURI dropdown, the Windows Application Framework Propertie3s group was disabled, and the StartupUri attribute in the app.xaml was unused.
Now I know...
Cory

Cannot show up WPF application when setting MainWindow manually and composing application (MEF)

I got my hands om MEF for a week now and I am trying to build up a WPF application that loads imported controls from MEF.
I created a WPF application project and removed the default window and application start up URI. Then I handled the application startup event to compose the application:
public partial class App : Application, IPartImportsSatisfiedNotification
{
{...}
private void App_Startup(object sender, StartupEventArgs e)
{
this.Compose();
}
public void Compose()
{
try
{
globalCatalog.Catalogs.Add(new DirectoryCatalog(extensionsDirectoryPath));
CompositionContainer container = new CompositionContainer(globalCatalog);
container.ComposeParts(this);
}
catch (Exception ex)
{
// Do something
}
}
{...}
}
Actually, when debugging and watching objects after imports are satisfied, everything has hierarchically composed fine like I wanted. But when I try to show up the MainWindow of the application an exception is thrown on MainWindow.Show() call:
"Specified element is already the logical child of another element. Disconnect it first."
Though my code in OnImportsSatisfied method seems fine as it is working when not using MEF mecanism:
public void OnImportsSatisfied()
{
Window mainWindow = new Window();
mainWindow.Content = this.importedControl;
this.MainWindow = mainWindow;
this.MainWindow.Show();
}
I insist on the fact that this works perfectly when not importing controls with MEF. What is surprising is that this code does not work too:
Window mainWindow = new Window();
//mainWindow.Content = this.importedControl;
this.MainWindow = mainWindow;
this.MainWindow.Show();
So I suspect that ComposeParts is doing a bit more than what it says as it is the only member acting on my actual application instance.
Hope someone can help me (Glenn?).
Thanks.
Edit:
I discovered that when I remove the IPartImportsSatisfiedNotification interface from my parts, no exception is thrown and the window shows up. But of course the window is empty as I need this OnImportsSatisfied method to set the DataContext of the window to its associated imported view model.
The sample applications of the WPF Application Framework (WAF) show how to use MEF within a WPF application.
I finally discovered that I was importing my WPF user controls by using the default ImportAttribute constructor, which in fact will make a shared instance of the class if the creation policy is not specified during export. And as many of my controls were implementing the same interface and I was binding them in my views, I was actually trying to add this shared user control instance to different visual elements, which is not permited by WPF (and so the exception).
I marked my imports using the RequiredCreationPolicy set to NonShared and everything got back in order! That was all about learning MEF...

Cannot access resource defined in app.xaml

I am using Visual Studio 2010 RC1.
I define a resource "Brush2" in app.xaml_:
<Application x:Class="VideoThumbnails.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<RadialGradientBrush x:Key="Brush2" RadiusX="1" RadiusY="1" GradientOrigin="0.3,0.3">
<GradientStop Color="White" Offset="0"/>
<GradientStop Color="#ffc0c0" Offset="1"/>
</RadialGradientBrush>
</Application.Resources>
</Application>
In my Mainwindow I am trying to use that resource:
...
<Border Margin="4,2" BorderBrush="Black" BorderThickness="2" CornerRadius="4"
ToolTip="{Binding Path=FullPath}" HorizontalAlignment="Stretch"
Background="{StaticResource Brush2}">
...
No matter what I do it always raises an exception at runtime (Resource not found). I changed
build action without success.
How can I use resources defined in app.xaml?
If you've set the Startup Object to a custom class you need to create the custom Application class and also call its InitializeComponent method, like this:
App app = new App();
app.InitializeComponent();
Update: As #qqww2 suggested the InitializeComponent call can be moved inside the App class constructor.
I start my application not with a StartupUri in App.xaml, but with a event handler in App.xaml.cs.
When using override Startup() resources from App.xaml are not loaded:
public partial class App
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
...
}
}
But when using event Startup the resources are loaded just fine:
<Application x:Class="OxyplotTest.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Startup="OnStartup">
And code behind:
public partial class App
{
private void OnStartup(object sender, StartupEventArgs e)
{
...
}
}
Nothing you have done is incorrect. You either have 1) screwed up the project build somehow while randomly doing things to try to get it to work or 2) something else is going on here and we'll never know without the exception details.
I would highly suggest you try to repro this in a fresh brand new WPF project. Do the following steps (and ONLY the following steps):
Create a new WPF project, add the exact same brush to app.xaml, then open Window1 and bind the window's background to the resource. Run the app.
It should work as expected. If not, come back with the exception details. If it does, compare this new project with your current one to see what you are doing differently.
I know there is an already accepted answer, but I thought I would add my solution as well. I had code that was working, but some configuration change broke the resource references in the designer. In executing code, it worked fine.
After some initial research, I determined that the BuildAction property for App.xaml should be set to ApplicationDefinition. My was set to Page. However, that causes some issues with multiple entry points. Main() was already defined in App.xaml.cs. The compile error was indicating another entry point in App.g.cs (which is an autogenerated file).
I ended up using the approach #3 described at http://www.infosysblogs.com/microsoft/2008/09/how_to_write_custom_main_metho.html. The basic idea is that you create a new class that is only responsible for startup. In my case, I named it Startup.cs. It should have code that is similar to this:
using System.Threading;
namespace MyNamespace
{
public class Startup
{
[System.STAThreadAttribute()]
private static void Main()
{
var app = new App();
app.InitializeComponent();
app.Run();
}
}
}
Then in the project settings, change the Application -> Startup object so that your new class is selected.
I had a similar problem and solved it, so I figured I may as well post my solution. I kept getting the Resource not found error only at runtime as described above. In my Windows 8.1 c# App, I was using a style I had defined, and it showed up fine in Blend and the designer view, but didn't work at runtime. I was trying to use this style in a SettingsFlyout I had created following these instructions. After getting that to work, I set up a field in App.xaml to hold onto my flyouts (Preferences and ColorSettings) so I wouldn't be making a new one every time.
public static Preferences preferences;
public static ColorSettings colorsettings;
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
preferences = new Preferences();
colorsettings = new ColorSettings();
}
After poking around and googling for about an hour, I figured out that I was creating the flyouts too early, and when they were created they couldn't access the application's resources. So I moved their creation down to App.OnLaunched() and that solved the problem.
I'm not sure if that's the best way to go about things, but it worked. So, try to pinpoint where you're trying to access the resources you want, and if you're maybe trying too early. Sorry for the vagueness and maybe incorrectness, I'm really new to WPF.
I can concur that resources get messed up easily if you have something in App constructor. Move initialization of your own global objects into OnStartup method:
protected override void OnStartup(StartupEventArgs e)
{
}

How to change StartupUri of WPF Application?

I am trying to modify App.cs and load the WPF XAML files from code behind but its not working as it should.
No matter whatever I try to set as StartupUri it doesnt start, the program quits after this.
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
LoginDialog dlg = new LoginDialog();
if (dlg.ShowDialog() != true)
return;
switch (dlg.ChoiceApp) {
case ChoiceApp.CustomerEntry:
StartupUri = new Uri("/MyApp;component/Forms/CustomerEntry.xaml",
UriKind.Relative);
break;
case ChoiceApp.VendorEntry:
StartupUri = new Uri("/MyApp;component/Forms/VendorEntry.xaml",
UriKind.Relative);
break;
}
}
}
Now I even did trace and found out that LoginDialog is working correctly and is returning values correctly but setting "StartupUri" does not work.
I checked in reverse assembly that DoStartup method of App gets called after OnStartup, so technically my StartupUri must load, but it doesnt, in App.xaml startup uri is not at all defined.
Note: Bug Confirmed
I noticed that ShowDialog sets Application.MainWindow and when dialog ends, it sets it back to null, and because of this setting StartupUri does not work after calling Modal Dialog in OnStartup or Startup event.
There is no error or exception about invalid uri or anything like that.
This method works without DialogBox being called in Startup event or OnStartup, i think calling showdialog on this method causes something like its mainwindow being set to expired window and it shuts down after this.
Akash, I ran into this exactly issue trying to implement a LoginDialog just like yours. The dialog does not have a bug, but rather the behavior is by design.
Not a bug. The default ShutdownMode of
Application is OnLastWindowClosed, so
as soon as the first window is closed
your application will start shutting
down! Change to OnExplicitShutdown and
it will work, but you'll have to
manage the shutdown.
See this previous StackOverflow question: WPF ShowDialog returns null immediately on second call
instead of overriding the OnStartup() method, hook into the event instead.
in the XAML
<Application x:Class="SOTestWPF.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Startup="Application_Startup">
<Application.Resources>
</Application.Resources>
</Application>
in the code behind:
private void Application_Startup(object sender, StartupEventArgs e)
{
var rnd = new Random();
if (rnd.NextDouble() > 0.5)
StartupUri = new Uri("/SOTestWPF;component/Window1.xaml", UriKind.Relative);
else
StartupUri = new Uri("/SOTestWPF;component/Window2.xaml", UriKind.Relative);
}
This is only my test case and I have verified that it performs correctly (randomly :D)
Just try in OnStartup() :
StartupUri = new Uri("Forms/CustomerEntry.xaml", UriKind.Relative);
Do you still have a StartupUri specified in the XAML? If so, remove it and see if that helps.MSDN Source
If not, you may need to approach this differently: have your Dialog as your startup, then from that point open another Window based on the selected value.

Problems with Prism hosted in a WinForm ElementHost

I am having problems with hosting a WPF prism app in an ElementHost control and am desparate for help.
The PRISM app runs fine in silverlight and in a standalone WPF.
The main Shell seems to setup fine in the elementHost on a WinForm however other views only load with the “RegisterViewWithRegion” and not the “Add,Activate” procedure. I need “Add,Activate” for scoping. However I beleive the problem is that I am loading my shell twice … not on purpose. I cannot find a way to call the bootsrapper and set the elementHot without calling “Resolve” twice.
Here is the code for my WinForm and my bootstrapper. Again everything works when using "RegisterViewWithRegion".
Here is the Winform Constructor:
public Form1()
{
InitializeComponent();
if (System.Windows.Application.Current == null)
{
new MyApp();
}
Bootstrapper bootStrapper = new Bootstrapper();
bootStrapper.Run();
var shellElement = bootStrapper.Container.Resolve<ShellContainer>();
//Attach the WPF control to the host
elementHost.Child = shellElement;
}
Here is the bootstrapper:
public class Bootstrapper : UnityBootstrapper
{
protected override DependencyObject CreateShell()
{
return Container.Resolve<ShellContainer>();
}
protected override void InitializeModules()
{
IModule moduleSurvey = Container.Resolve<SurveyModule>();
moduleSurvey.Initialize();
}
}
The Bootstrapper automatically sets Application.Current.MainForm to whatever you returned in the CreateShell method. Hopefully you are setting up an Application (I think that's what you are doing in the first If block). If so, you can just change this:
var shellElement = bootStrapper.Container.Resolve<ShellContainer>();
To this:
var shellElement = Application.Current.MainForm;
That ought to work, but there are definitely some weirdnesses with the ElementHost. We ended up with a lot of strange rendering bugs, especially in a Citrix environment. I don't know if this is a limitation of your setup, but I thought I would mention it.
Good luck!
I had the same GCE (Gross Conceptual Error). I was seeing the same behavior of my views being instantiated twice when using Add or Activate. I was deep into debugging the behaviors when it hit me.
The following is returning a new instance of the ShellContainer.
var shellElement = bootStrapper.Container.Resolve<ShellContainer>();
Either register your ShellContainer type in the container with a ContainerControlledLifetimeManager or put a prublic property on your bootstrapper to access the ShellContainer instance to set into your ElementHost.

Resources