SizeToContent on Window: A slow load causes window to display small, THEN resize properly

1.6k Views Asked by At

Ok, so I have a window that pops up (during normal operation of the program) at the user's request to display some context-specific information. This window happens to have a lot of elements in it, so it takes 0.5 - 1 sec to load. However, since I'm expecting this window to contain several different types of information depending on the context, it's content's width and height may vary. Thus I set the SizeToContent value to "WidthAndHeight" to allow the window to resize based on whatever content is bound to it.

However, since the window takes some time to load, the user first sees a small, square window and then the full-size window after everything renders. I would like to avoid having the user see the small window before it fully loads.

Is there any way to cause the window to only display AFTER it has rendered completely?

Things I've tried:

  • set the visibility of the window to "Hidden" and then set it to "Visible" in a ContentRendered event handler : the window never displayed.

  • set the opacity of the window to 0 and then set it to 1 in a ContentRendered event handler: the opacity of the content in the window itself is set to 0, then to 1.

Update : Another attempt

I have also tried to set Window.WindowState to "Minimized" in XAML and then set it to "Normal" in the ContentRendered event handler. This seems to work partially, though the width of the window itself is larger than it should be. Worse, it appears that the content in the window rendered according to the correct size for the window, and then the window made itself larger without re-rending the content. Thus, the content is not centered in the window and we have a nasty black rectangle to the right of the content that represents the difference between the correct size of the window and the current (larger) size. When I resize the window manually by grabbing the edge of the window, the content re-renders properly and everything looks fine. But how do I force such a re-rendering in code? Window.UpdateLayout() doesn't work.

3

There are 3 best solutions below

0
On BEST ANSWER

Ok, I found my mistake. SizeToContent set to WidthAndHeight works just fine as long as the DataContext for the new window was set BEFORE you show the window. As in:

secondaryWindow.DataContext = viewModel;  

secondaryWindow.Show();

rather than:

secondaryWindow.Show();

secondaryWindow.DataContext = viewModel;  

like I had.

So what was happening was that the window was sizing appropriately in the case that the DataContext was null, and then re-sizing when the DataContext was set.

Kudos to Elad Katz for adding a solution that indirectly caused me to find this bug.

1
On

Note that you can know what size the window needs event without showing it at all.

if you have a control that you want to know the size that it wants, you can do the following

// I'm picking Button here, but any control could be put here, be it
// Window or whatever:

Button b = new Button();

// I'm putting some content to see that it actually measures it children. If you'll put more text here
// you'll see bigger size
b.Content = "Hello";

// I'm manually measuring the control, passing in double.PositiveInfinity so that the control
// would give me the size it wants, regardless of any constraints (you can put constraints here
// if you like)
b.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));

// After Measure is called, the Property DesiredSize become relevant, and contains the size that the
// Control needs to show all of its contents.
MessageBox.Show(b.DesiredSize.ToString());
0
On

Ok, I found a solution that works. Not ideal, but it works.

First I set Window.WindowState to "Minimized" in XAML. This prevents the window from appearing on the screen as it is rendering. Then I subscribed to the ContentRendered event for the window, and added the following code in the handler:

this.WindowState = System.Windows.WindowState.Normal;
this.MaxWidth = MainContentPresenter.ActualWidth;
this.Height = MainContentPresenter.ActualHeight;

this.InvalidateVisual();

where MainContentPresenter is the ContentPresenter for the window. The ViewModel is bound to this element, so the content appears there.