WPF - Display usercontrol dll's name as they load in splash screen - wpf

I am in the process of writing a WPF application that hosts 10+ usercontrols I have written. What I would like to do is modify the code from "Wonko the Sane"'s answer in this post
Is there a way to show a splash screen for WPF application?
to dynamically show the name of these usercontrol dll's as they load.
I have not been able to find anywhere how to get the names of dll's as they load.
Any assistance would be appreciated.
Thanks, Jim

Sorry, but you won't be able to do that. The WPF Framework loads before your program starts executing. The best that you'll be able to do is to add the names of the relevant DLLs into a string collection and then loop through them, displaying each one temporarily. Even if you could display what was being loaded, the chances are that they'd actually load so quick that you wouldn't see anything anyway.
It's also worth pointing out that it is only really worth having a splash screen in a WPF Application if you have a real lot of initialisation loading to do. In that case, you can show what the application is doing, but you'll probably find that in most cases, the loading is still done too fast for the UI to update in time.

You can get the current application domain and then use AssemblyLoad event to get loaded Dll name.
AppDomain MyDomain = AppDomain.CurrentDomain;
MyDomain.AssemblyLoad += new AssemblyLoadEventHandler(SplashControllerObject.LocalEventHandler);
private void LocalEventHandler(object sender, AssemblyLoadEventArgs args)
{
//use sender.LoadedAssembly.FullName for DLL name loaded
}

Related

Prism application with no initial shell

I've been creating a WPF application that initially loads as a task bar icon and then when clicked opens an appropriate window. This was a prototype and I want to move over to Prism and having watched the (superb) videos by Mike Taulty (channel9.msdn.com/niners/mtaulty) I have the feeling that what I need to do is create an application with a custom bootstrapper that does all the service registration but does not create an initial shell but instead simply loads the modules and perhaps identifies a module to Run. Has anyone anyone done something similar, if so how much work am I in for?
OK I bit the bullet and just tried it. I should first state that I was using the Autofac version of the Bootstrapper.
I returned null to CreateShell
I marked the apps ShutdownMode="OnExplicitShutdown" in the declaration at the top of App.Xaml (important otherwise it closes the application when you close the last window)
I created a module (IModule derived) that loaded the WPF notify icon by Philipp Summi (http://www.codeproject.com/Articles/36468/WPF-NotifyIcon)
In response to a command from the context menu on this icon I simply create the window and it's view model and show it.
This all works just as I had hoped. The only thing I have yet to do is see how to use regions with these temporary windows although other articles appear to have this covered. I'm not convinced the Autofac bootstrapper gives me any great advantages but I had developed a very early prototype using Autofac and stuck with it because it went smoothly. I will probably go with Unity or MEF in the long run just to avoid compatibility problems and to allow dynamic module loading from external plugins.

WPF precompiled resources in WinForm application?

I am working on an application that started out as a WinForm but it is now utilizing WPF windows with UI. The interaction is all working beautifully but when the WPF windows are first shown it takes quite a long time (around 1-3 seconds) for them to show. So long that some wonder if the app has crashed (until the content shows). The second time the same windows are invoked they come up quickly. I need them to come up quickly the first time around.
I am making use of styles and control templates that are located as XAML in the resource folder. In the XAML for the WPF windows I then merge them into the windows resource dictionary. The Build Action for those (in VS 2010) needs to be set to "Resource".
Preferably I want to keep them in separate files for easy maintenance.
As far as I understand if the build action was "Page" the XAML would be precompiled and should load faster but if I set it to Page I cannot merge them into the resource dictionary. Is there a way around that?
I am fairly new to this part of WPF and so far my internet search hasn't been successful.
To be clear: I am not talking about WPF controls being embedded in WinForms. I am talking about entirely separate WPF windows that are spawned from the WinForm context.
Is there a way to precompile the entire app or at least all XAML (it's all static, no dynamic XAML)?
Thanks in advance!
Edit: The UIs are not heavy by any means. The ones in question have between 5 and 20 buttons and the usual containers (basically a grid with 1 or 2 stack panels).
Update:
I tried precompilation with "NGEN install appname" - no effect on WPF window load.
I included all resources and templates into the window.xaml - no effect.
(window.xaml is pre-compiled)
I found this really interesting article about pre-jitting upon app load here:
http://www.codeproject.com/KB/dotnet/pre_JIT.aspx
(I used the improvement suggested by 'ittay ophir')
again: no effect on WPF window load...
The load times simply won't change on first load but they are significantly reduced on all consecutive loads (loads in 20ms or less).
What the heck is going on here?
How about loading the XAML asynchronously using XamlReader.LoadAsync Method ?

Prevent WPF Frame from storing history in the stack

This seems like it would be an easy solution, but I'm wasting too much time trying to figure this out. Perhaps I am designing my application incorrectly (which might be the case), so please help me out if you have a better solution.
I'm designing an enterprise level WPF application that looks a lot like Outlook with a Ribbon instead of a toolbar. I have a lot of different modules that are loaded into a frame when the user clicks on a RibbonButton. Keep in mind that his ribbon is shared accross all modules.
So I have a shell with a ribbon and a frame. When the user clicks on the Ribbon button, it loads the proper module (usercontrol) into the frame. All is good. However, if I navigate to another module (by clicking on another RibbonButton), and then click on the original RibbonButton, I now have two instances of the same module open... but only one is shown in the frame... the other module is in the frame's stack.
So my question is, how to I tell the frame to close the usercontrol when I navigate to a different module? I've tried setting the JournalEntry.KeepAlive="False", but that still did not work. Any thoughts? There is really not much code to post, but I can do so if it will help you.
If you never intend on going "back" to the previous entry, you can use NavigationService.RemoveBackEntry() to clear out the history each time you navigate. The easiest way to do that is to handle the Frame's Navigated event:
frame.Navigated += frame_Navigated;
void frame_Navigated(object sender, NavigationEventArgs e)
{
frame.NavigationService.RemoveBackEntry();
}

Composite Application Block Region injection slow

Im building a wpf app with the composite application block ("prism") V2, and Im having an issue where a user control that is injected by a module is very slow in rendering. The user control contains a datagrid with some 2000 rows in it and there is considerable lag in the control rendering to the screen. Initially I thought the slowness was due to the wpf toolkit datagrid control itself but this is not the case. When I move the control containing the datagrid (TestControl) out of the external module and into the shell project and load it straight from there the control renders immediately without any problems.
Im using the following code in the implementation of IModule in my module to inject the wpf user control into the shell
this.regionManager.RegisterViewWithRegion("mainRegion", typeof(TestControl));
Is there performance issues when loading controls from other modules in a prism app? Whats the most optimal way to load them in?
Thanks
the problem here seemed to be wpf being slow to update when the UI is being updated vai the dispatcher from a background thread. I took up the conversation on codeplex and got it more or less sorted.
http://compositewpf.codeplex.com/Thread/View.aspx?ThreadId=64113
It's likely this is an artifact of the lifecycle events. Your shell is going to display well before your modules start to load and register themselves. If you do this it will "appear" to take longer because your UI will appear with a big fat hole in it until the module initialization code fires.
A lot of the samples have you doing something like "Shell.Show();" in your CreateShell method of your bootstrapper, but you might consider moving the references to the Shell to a private member of your bootstrapper class and calling .Show() on it in, like this:
public class Bootstrapper : UnityBootstrapper
{
Shell shell;
protected override DependencyObject CreateShell()
{
shell = Container.Resolve<Shell>();
return shell;
}
protected override void InitializeModules()
{
base.InitializeModules();
shell.Show();
}
I tried this just now and it definitely felt like my app got a performance boost, so I think I'll make this change myself.
If your modules take a really long time to load, you also might want to show a splash screen between CreateShell and after InitializeModules.

What are the issues with running WPF across multiple AppDomains on one UI thread?

We are looking at creating a WPF UI that runs across multiple AppDomains. One of the app domains would run the application while the remaining AppDomains would host a series of user controls and logic. The idea, of course, is to sandbox these User Controls and the logic away from the main application.
Here is an example of doing this using MAF/System.AddIn. What are some of the experiences other have had with this? How does this solution handle RoutedEvents/Commands that might occur inside one user control and do these get properly serialized across AppDomains? What about WPF resources? Can they be accessed across AppDomains seamlessly?
Old question, but nonetheless: You will need to have multiple UI threads - one per AppDomain. Create them like this:
var thread = new Thread(() =>
{
var app = new Application();
app.Run();
});
thread.Name = AppDomain.CurrentDomain.FriendlyName;
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
The biggest challenge is then that you cannot send FrameworkElements between AppDomains (they are not MarshalByRefObject), but you can use the FrameworkElementAdapters.ViewToContractAdapter() and ContractAdapterToView() methods to work around this limitation. See the FrameworkElementAdapters MSDN page for more details.
Then, once you have this in place, the biggest problem IMHO is that you cannot lay anything on top of the FrameworkElement from the "remote" domain (the classical "airspace problem"). See this thread for more info about this.
I answered a simular question here and edited it for WPF also, you can use an intersting property of how the compisition engine operate's to tail-coat a dispatcher Pump, into one of the rendering contexts. It's a really light weight option.
Also, I'm guessing you know about the enterprise library and unity?
There is a WPF application block so using that pattern is not too painful ;) But don't they say, no pain no gain?
There's also CAB (Composite UI Application Block), ties into unity. The WPF SDK folks have crafted a Silverlight & WPF platform. (a.k.a Prism).
Oh right, also, you asked about Resources? I prefer to load reasources manually in the Application class. One thing I've realized, say you have a ResourceDictionary in a sub-folder and you are loading up MergedDictionaries in that ResourceDictionary. So, if in your Application class, you load "my-res-dir/MergedDictionaryLoader.xaml" (by code or xaml), ALL FUTURE LOADS OF MERGEDDICTIONARIES ARE LOADED FROM "my-res-dir".
Sort of insane if you ask me, I would think that as the process current directory has not changed, you should specify "my-res-dir/foo.xaml" for all your additional directories. However this is not the case (I do not believe this is documented anywhere at least very well and should be considered a bug imho).
So remember, WPF resource dictionary loading is going to be based off of the directory from which the current XAML is in. So you specify Source="foo.xaml" from within your "my-res-dir/MergedDictionaryLoader.xaml". I've even played with the URI pack / absolute syntax, however I've never found that too be much more intuative.

Resources