Search code examples
c#wpfsizetocontent

SizeToContent paints an unwanted border


Whenever I try to make a window and I set the SizeToContent to WidthAndHeight, on opening the window correctly sizes to it's contents, but it adds a small border to the right and the bottom. On resizing this disappears, and when using a set height and width this problem also doesn't occur.

This is a sample of what I mean:

enter image description here

You could say this is not a huge problem, though I find it makes my application look unprofessional, especially when I need to present this. Does anybody know why this is happening, or whether there is a workaround? I am coding this project in C#.

XAML Code:

<Window x:Class="FPricing.InputDialog"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="InputDialog" Width="400" Height="300" SizeToContent="WidthAndHeight">
    <StackPanel>
        <Label x:Name="question">?</Label>
        <TextBox x:Name="response"></TextBox>
        <Button Content="OK" IsDefault="True" Click="Button_Click" />
    </StackPanel>
</Window>

Values are passed on on creation of the class.

However I experience this problem on every window I have ever created, even without custom underlying code.


Solution

  • Using this tool (it's good, btw) I found that the Border control of the Window (it's immediate child) doesn't fill the whole window, leaving that "border", which is actually the background of the Window control.

    I've found a workaround. Width and Height of the Border are NaN. If you set those to an integer value, the "border" disappears.

    Let's use the values of ActualWidth and ActualHeight, but rounded to an integer.

    Define the converter:

    C#

    [ValueConversion(typeof(double), typeof(double))]
    public class RoundConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            return Math.Ceiling((double)value);
        }
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            return value;
        }
    }
    

    XAML (remember to include your namespace, in this case "c")

    <c:RoundConverter x:Key="RoundConverter"/>
    

    Then create a style binding the size to the actual size using the converter. It's important to use a Key, so it won't apply to every Border (most controls use it):

    <Style TargetType="{x:Type Border}" x:Key="WindowBorder">
        <Setter Property="Width" Value="{Binding RelativeSource={RelativeSource Self}, Path=ActualWidth, Converter={StaticResource RoundConverter}}"/>
        <Setter Property="Height" Value="{Binding RelativeSource={RelativeSource Self}, Path=ActualHeight, Converter={StaticResource RoundConverter}}"/>
    </Style>
    

    Finally, apply this style to the first child of the window (the Border control):

    private void Window_Loaded(object sender, RoutedEventArgs e) {
        GetVisualChild(0).SetValue(StyleProperty, Application.Current.Resources["WindowBorder"]);
    }
    

    If someone can do this in a simpler way, please share too.