Search code examples
wpflayoutsizetocontent

Window sizing constraints by content


I want the window to respect MinWidth/MinHeight and MaxWidth/MaxHeight specifications of the content control inside.

Some suggested using SizeToContent, but this only helps to set the initial window size, not the constraints.

Others suggested overriding MeasureOverride and setting window's Min/Max height and width there, but this seems to be somewhat unclean, considering that such a trivial problem should surely have a purely declarative solution.

Just to mention another solution which seems reasonable but does not work (and had been previously mentioned in an answer which got deleted): binding MinWidth of the window to MinWidth of the control does not take into account window decorations.


Solution

  • If the initial window size is set so that actual content size is not coerced by the content's MinWidth/MinHeight and MaxWidth/MaxHeight in the initial layout pass (for example, by using Window.SizeToContent="WidthAndHeight"), then following equations are true:

    Window.ActualSize - Content.ActualSize = 
          Window.MinSize - Content.MinSize = Window.MaxSize - Content.MaxSize.
    

    Based on these equations you can derive the following code:

    public MainWindow()
    {
        InitializeComponent();
    
        this.SizeChanged += OnWindowSizeChanged;
    }
    
    private static void OnWindowSizeChanged(object sender, SizeChangedEventArgs e)
    {
        var window = (Window)sender;
        var content = (FrameworkElement)window.Content;
    
        window.MinWidth = window.ActualWidth - content.ActualWidth + content.MinWidth;
        window.MaxWidth = window.ActualWidth - content.ActualWidth + content.MaxWidth;
    
        window.MinHeight = window.ActualHeight - content.ActualHeight + content.MinHeight;
        window.MaxHeight = window.ActualHeight - content.ActualHeight + content.MaxHeight;
    
        window.SizeChanged -= OnWindowSizeChanged;
    }
    

    I do not know how to achieve this efficiently using the pure declarative approach since the code should be ran just once after the initial layout pass.