How to customize startup of WPF application? - wpf

When a new WPF Application project is created, MainWindow.xaml, App.xaml and their corresponding code behind classes are automatically generated. In the App.xaml there is an attribute that defines which window is going to be run initially and by the default it's StartupUri="MainWindow.xaml"
I have created a new Dispatcher class in the same project. At startup, I want the instance of that class Dispatcher to be constructed and then one of its method to run. That method would actually create and show the MainWindow window. So how do I modify the App.xaml or App.xaml.cs in order to make it happen? Or, if it cannot be done by App, how should I implement it? Thanks.

You can remove the StartupUri attribute from the App.xaml.
Then, by creating an override for OnStartup() in the App.xaml.cs, you can create your new instance of your Dispatcher class.
Here's what my quick app.xaml.cs implementation looks like:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
new MyClassIWantToInstantiate();
}
}
}
Update
I recently discovered this workaround for a bug if you use this method to customize app startup and suddenly none of the Application-level resources can be found.

Try to use the Startup event (class Application) - MSDN.
You can show MainWindow in this event handler - after you create a Dispatcher instance.

1.In App.xaml, To replace the StartupUri with a subscription to the Startup event.
Use the event in App.xaml.cs .
For instance,
Startup="Application_Startup" in .xaml.
public partial class App : Application
{
private void Application_Startup(object sender, StartupEventArgs e)
{
// Create the startup window
MainWindow wnd = new MainWindow();
// Do stuff here, e.g. to the window
wnd.Title = "Something else";
// Show the window
wnd.Show();
}
}

Related

Caliburn.Micro - why uses UserControl instead of Window

My question is exactly like in the title.
I'm starting with Caliburn.Micro for MVVM approach (which also is new for me) and in every tutorial the first step is to remove the default MainWindow.xaml file and create a new UserControl file. Why is that? UserControl does not even accept a Title. Isn't it possible to build application using normal Windows? I already tried that, but with every launch I get error "Cannot find view for ViewModel", although both MainView.xaml and MainViewModel.cs are present. When I created a pair of USerControl and ViewModel for it, everything started to work as expected. So again, why Windows don't work?
It wouldn't really be a problem, but I'm thinking that some additions like Modern UI themes for WPF might not work without a window. I'm not sure of that.
Probably one solution would be to display a defined UserControl View inside of a Window, but it's just a workaround.
You could create your own custom shell window by creating a custom WindowManager:
public class CustomWindowManager : WindowManager
{
protected override Window CreateWindow(object rootModel, bool isDialog, object context, IDictionary<string, object> settings)
{
Window window = new Window();
window.Title = "custom...";
return window;
}
}
...that you register in your bootstrapper:
public class HelloBootstrapper : BootstrapperBase
{
...
protected override void Configure()
{
_container.Singleton<IWindowManager, CustomWindowManager>();
...
}
}

How to "restore" SynchronizationContext when using custom startup?

My app works fine, but now I wanted to have custom startup, so I could catch any errors, add my logging from the start, etc.
So I used approach as shown in this answer What code controls the startup of a WPF application?
[STAThread]
public static void Main(string[] args) {
//include custom startup code here
var app = new MyApplication();//Application or a subclass thereof
var win = new MyWindow();//Window or a subclass thereof
app.Run(win); //do WPF init and start windows message pump.
}
It works fine with one exception -- SynchronizationContext.Current is null. And I need it :-)
So how to correctly make custom startup and have synchronization context?
Don't create your own Main method. Override the OnStartup method in your App.xaml.cs file:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var win = new MyWindow();
win.Show();
}
}
Then you will get a SynchronizationContext as usual.
Don't forget to remove the StartupUri attribute from the <Application> root element of your App.xaml file.

Should I create separate Bootstrapper for each WPF window?

I am new in WPF and Prism. I'd like to know if I should create new bootstrapper for each new window? For Example I have "Window1" where I select element from ListBox and click button "ShowDetails" and in the new window "Window2" I should see the details of my selection. I have windows and modules for them, but I'd like to know how and where I can register the module "Module2" for "Window2"?
Example of my Bootstrapper.
class Bootstrapper : UnityBootstrapper
{
protected override DependencyObject CreateShell()
{
var mainWindow = new Window1();
mainWindow.Show();
return mainWindow;
}
protected override IModuleCatalog GetModuleCatalog()
{
var moduleCatalog = new ModuleCatalog();
moduleCatalog.AddModule(typeof(Module1));
return moduleCatalog;
}
}
"App.xaml.cs"
public partial class App : Application
{
public App()
{
var bootstrapper = new Bootstrapper();
bootstrapper.Run();
}
}
The Bootstrapper is used usually in the startup class of a WPF Application. Usually this will be the file App.xaml.cs in the standard template, which is the code-behind class of the App.xaml file. You override the method OnStartup and instantiate your Bootstrapper and call its run method. You can delay the startup of the bootstrapper until the override of OnStartup instead of writing this in the constructor of the App.xaml.cs class. You will then use the RegionManager in Prism and define regions in your XAML. If you have multiple independent Windows this is a bit different from the way Prism is intended to be used. There is the concept of a MainWindow or Shell which you define in the CreateShell method of the Bootstrapper class which is available in the Prism source code. Instead, have a main window and define regions and perhaps consider creating a mechanism for displaying additional windows in dialogs. It is possible partition up the MainWindow into multiple regions and inject user controls via the RegionManager. This is done via the activate method of the RegionManager.
Start up by reading the Patterns And Practices Guide and perhaps consider watching the videos of Mike Taulty upon Prism. The first video is here:
Prism & Silverlight: Part 1 - Taking Sketched Code Towards Unity
There are many videos in the video series (10 in total) that will help you get started with PRISM.
An example of how to define a region in XAML is shown next:
<ItemsControl Regions:RegionManager.RegionName="MainRegion" />
A PRISM region can be activated, e.g. through a DelegateCommand or ICommand bound to a button is the following code:
var viewA = new ViewA();
var regionA = (new RegionManager()).Regions["RegionA"];
regionA.Activate(viewA);
You will have to define multiple modules that implement the IModule Interface and add these to your ModuleCatalog as you already have done with ModuleA.

Where put bootstrapper?

I want to create PRISM application with MVVM pattern and I don't know where I should put bootstrapper?
In Model, ViewModel or View?
Bootstrapper creates shell (so in View?) but it also registers container etc so maybe it should be like separate service?
The bootstrapper is part of the executable framework for configuring your application.
I suggest putting the bootstrapper code in the OnStartup event handler of your Application class.
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
SplashScreen splash = new SplashScreen("Resources\\mysplash.png");
splash.Show(true);
base.OnStartup(e);
MyBootstrapper b = new MyBootstrapper();
b.Run();
}
}
Technically, it is part of the View layer, imho, but is really there to configure the catalog and perform start-up operations.

Caliburn Launch without App.xaml, but with bootstrapper

I have a WinForms project from which I want to open a WPF window from a WPF user control project.
But when I create an instance of the WPF window and call Show(), the bootstrapper isn't loaded. In an Windows Application, it's located in the App.xaml, but an user control project doesn't have this.
What can I do?
Thanks!
The only thing accomplished by having the bootstrapper in App.xaml's resources is instantiation of the bootstrapper and keeping a reference so it isn't garbage-collected. You could try making it instantiate like this:
public class SomeClass {
static Bootstrapper _bs = new Bootstrapper();
...
}
That will make sure it's initialized as part of static construction, which happens sometime before you can create an instance of SomeClass. You may have to experiment to see whether that should happen in your UserControl or in your Window.
I have a console application which presents a WPF gui that I made with Caliburn.Micro. I present the GUI like this:
_App = new App();
_App.Run();
Where App.xaml contains the bootstrapper and the main thread is STA like this:
[STAThread]
static int Main(string[] args)
{ ... }
I know your situation is different but maybe this will give you an idea.
Console application test:
Add MaterialDesignColors pakage
[System.STAThreadAttribute()]
static void Main(string[] args)
{
var _app = new App();
_app.InitializeComponent();
_app.Run();
_app.Shutdown();
}

Resources