How to persist caliburn micro app size?

Topics: Getting Started, UI Architecture
Sep 2, 2012 at 10:17 AM
Edited Sep 2, 2012 at 10:18 AM

Hi all!

I am working on an app using wpf and caliburn.micro. Now i need to be able to save the application main window size and position and to restore it the next time the app starts.

The app is ViewModel first. My main view is a UserControl and it's VM looks like this:

public class MainViewModel : Conductor<object>.Collection.OneActive {
// Body of the class omitted

I have found some code i think might be useful for persisting the app size:

But i can't figure out how to apply this on my app and therefore need some help. From where, and how, do i call the functions?



Sep 2, 2012 at 10:51 PM

The Bootstrapper class has an OnExit() method you can override, maybe that will help?  I haven't done anything like what you're talking about, I just read that in the wiki at:

Please post whatever you come up with when you have a solution.

Sep 3, 2012 at 8:02 AM

So, how do i get the the main window of my app?

Sep 4, 2012 at 5:11 AM


In the bootstrapper....

Sep 4, 2012 at 9:32 AM

Trying to figure out how to set the window size and position now.

I have made this override in the bootstrapper:

        protected override void OnStartup(object sender, StartupEventArgs e) {
            base.OnStartup(sender, e);

            Application.Current.MainWindow.Left = 10;       // Works!
            Application.Current.MainWindow.Top = 10;        // Works!
            Application.Current.MainWindow.Width = 500;     // Does NOT work.
            Application.Current.MainWindow.Height = 350;    // Does NOT work.

I can set the Top and Left of the app, but Height and Width has no effect. I think this is because the window is resized to fit the content after i set the properties in the bootstrapper. So how can i set the height and width?


Sep 4, 2012 at 12:15 PM

OK, making progress. But there are still issues.

I can now save and restore main window top, left, width, and height. But if i make the window bigger than the content, the app will start with a black border around the content and the content will only stretch out to occupy the whole window when i start resizing the man window by dragging one of it's edges.

I have tried calling InvalidateArrange(), InvalidateMeasure() and InvalidateVisual() followed by calling Updatelayout() on the main window, but that doesn't seem to do anything.

Any ideas?


Ps. Where is Eisenberg? You haven't abandoned this project i hope. Actually, i hope you are busy writing all the missing documentation for this otherwise super great framework.


Nov 28, 2012 at 6:40 AM
Edited Nov 28, 2012 at 6:43 AM

I've been fighting my way through this same issue, and I finally got this to work by adding one line of code to the above snippet:

        protected override void OnStartup(object sender, StartupEventArgs e) 
base.OnStartup(sender, e);

Application.Current.MainWindow.SizeToContent = SizeToContent.Manual; // Enables Width/Height to be set explicitly Application.Current.MainWindow.Left = 10; // Works! Application.Current.MainWindow.Top = 10; // Works! Application.Current.MainWindow.Width = 500; // Works now! Application.Current.MainWindow.Height = 350; // Works now! }
Jan 11, 2013 at 5:51 PM
Edited Jan 13, 2013 at 12:44 AM

Hi all,

I'm getting the Shell's size and location by overriding the OnStartUp method  as done in this thread. The actual numbers come from an Isolated storage file and it works fine. Note that I don't need the line of code Application.Current.MainWindow.SizeToContent = SizeToContent.Manual; to enable Width and Height.



Here's the code in the OnExit Method.


      protected override void OnExit(object sender, EventArgs e) {
         _appSettings.ShellTop = App.Current.MainWindow.Top;
         _appSettings.ShellLeft = App.Current.MainWindow.Left;
         _appSettings.ShellWidth = App.Current.MainWindow.Width;
         _appSettings.ShellHeight = App.Current.MainWindow.Height;
         base.OnExit(sender, e);

I made sure to save the settings before calling the base.

Any suggestions on where to save the settings?





         App.Current.MainWindow.Left = _appSettings.ShellLeft;
         App.Current.MainWindow.Top = _appSettings.ShellTop;
         App.Current.MainWindow.Width = _appSettings.ShellWidth;
         App.Current.MainWindow.Height = _appSettings.ShellHeight;


 I'm now overriding the OnExit method to do the reverse, that is save the current location and size to the Isolated Storage file. The problem is that the App.Current.MainWindow is null. I take it that CM has destroyed the MainWindow before calling the OnExit Method.

Jan 12, 2013 at 9:56 AM

I have finally been able to make this work. The solution was the Application.Current.MainWindow.SizeToContent = SizeToContent.Manual; (thanks gmcelhanon!)

I save the position in my shell view model (vm for the main window of the app) where i have this code:

        public override void CanClose(Action<bool> callback) {
            // Save application main window size and position
            Settings.Default.MainWindowPlacement = PersistWindowSize.WindowPlacement.GetWindowPosition(Application.Current.MainWindow);
            base.CanClose(callback);    // This callback can be called with parameter set to false to cancel close


Jan 13, 2013 at 12:36 AM

Thank you Li for that leed.  I will follow up on it.

I am very new to CM so I'm experimenting a lot.

Interestingly enough, I was also looking up methods in the ViewModel that I could override. Here's a little tid bit that may be useful.

When I change the Shell's size and location (Top, Left, Width, Height) in the Startup method the shell displays once and then moves to the location defined in the Startup Method of the bootstrapper.  So this, did not work for me.  I was thinking that it might be better to set the size and location of the shell in the viewmodel since it's the viewmodel that will display the view (Viewmodel first). I override the OnViewAttached method and set the size of the shell there. This way the size and location is changed before it is displayed by CM. This seems to works great. Here's the method. It just seems more natural for the viewmodel to control the view instead of the bootstrapper.

      protected override void OnViewAttached(object view, object context) {
         base.OnViewAttached(view, context);
         ShellView shellView = view as ShellView;
         //Get window size from Isolated storage in UserSettings
         _appSettings = SettingsSerializer.Deserialize(_Name);

         shellView.Top = _appSettings.ShellTop;
         shellView.Left = _appSettings.ShellLeft;
         shellView.Width = _appSettings.ShellWidth;
         shellView.Height = _appSettings.ShellHeight;


Hope this is useful,