MaterialDesignExtensions icon indicating copy to clipboard operation
MaterialDesignExtensions copied to clipboard

SizeToContent not rendered correctly

Open stojy opened this issue 4 years ago • 5 comments

I'm new to this project, so my apologies in advance if this has been covered elsewhere.

It apears that MaterialWindow does not render the correct dimensions when using SizeToContent.

For example..

<mde:MaterialWindow x:Class="ClrVpin.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:clrVpin="clr-namespace:ClrVpin"
        xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
        xmlns:mde="https://spiegelp.github.io/MaterialDesignExtensions/winfx/xaml"
        mc:Ignorable="d"
        d:DataContext="{d:DesignData }"
        WindowStartupLocation="CenterScreen"
        ResizeMode="NoResize"
        SizeToContent="WidthAndHeight"
        Width="300" Height="250"
        Title="ClrVpin" WindowState="Normal">

Yields the MaterialWindow plus also the underlying Window.. image

My workaround is to manually specify Width and Height, but this is a little painful for windows that I'd prefer dynamically size to the content.

stojy avatar May 24 '21 14:05 stojy

I have exactly the same problem, which is very annoying. it makes SizeToContent practically useless, and all size calculations are have to be done in my own code. Is there any plan the fix this problem?

markmov avatar Aug 25 '21 06:08 markmov

hi @markmov, AFAIK this has not been investigated and/or fixed. Do you have a workaround to calculate the size automatically (vs my existing approach to manually specify the absolute width and height)?

stojy avatar Aug 29 '21 00:08 stojy

Hi @stojy, My workaround is as follows: I don't set SizeToContent in xaml. In the "Loaded" event I've added: SizeToContent = SizeToContent.WidthAndHeight; This works almost OK, but it leaves a single extra pixel to the right and to the bottom. So in the "ContentRendered" event I've added: SizeToContent = SizeToContent.Manual; And now the window looks OK... Ugly, but working...

markmov avatar Aug 29 '21 05:08 markmov

Hi @markmov, my apologies for not replying sooner.. but the email notification got lost in my spam folder :(

Thanks for the tip. The Loaded handler works a treat..

Loaded += (_, _) => SizeToContent = SizeToContent.WidthAndHeight;

Regarding the extra pixel at the bottom, is this the sort of artifact you're seeing without applying the ContentRendered hack? image

If so, try this..

  1. UseLayoutRounding="True" in xaml (or code behing)
  2. Remove ContentRendered handler. It should now be unnecessary (and expensive as I suspect it would cause a re-render)

And as a bonus, it should also remove the pixel artifacts in the nav bar too (only noticable if you're using a dark theme heading style). image

Essentially I suspect the root issue here is the windows scaling that is being applied, especially for users on high resolution screens (eg. 4k).

stojy avatar Sep 18 '21 08:09 stojy

One thing I've just noticed.. whilst explicitly assiging the SizeToContent within the Loaded event does assign the correct with/height, it unfortunately breaks WindowStartupLocation CentreScreen/Owner. It looks like the window isn't repositioned to account for the (reduced) size.

Whilst it's possible to offset this with a bit of math, it looks like making a similar change in ContentRendered is simpler as it doesn't suffer the same problem.

public class MaterialWindowEx : MaterialWindow
    {
        // workarounds for MaterialDesignExtensions layout issue supporting SizeToContent.WidthAndHeight
        // - refer https://github.com/spiegelp/MaterialDesignExtensions/issues/144
        public MaterialWindowEx()
        {
            // removes unnecessary pixels in window: header, right, and bottom
            UseLayoutRounding = true;
            
            ContentRendered += (_, _) =>
            {
                if (SizeToContent != SizeToContent.Manual)
                {
                    // force a SizeToContent change so that WPF/MDE can correctly layout the window to fit the content
                    var sizeToContent = SizeToContent;
                    SizeToContent = SizeToContent.Manual;
                    SizeToContent = sizeToContent;
                }
            };
        }
    }

Plus the code above will only perform the content sizing if it's needed, e.g. in xaml SizeToContent=SizeToContent.WidthAndHeight

stojy avatar Sep 18 '21 15:09 stojy