Question

I'm really surprised that this question does not appear to have been asked yet... if it has, but I just couldn't find it, apologies.

Ok, so my work computer has just been upgraded from Windows 7 to Windows 8. To my absolute horror, my WPF Application looks different in several ways... by different, I mean worse, uglier, controls not lined up correctly, etc. Here is an example:

Windows 7:

enter image description here

Windows 8:

enter image description here

Windows 8 problems (just from this image):

  • Wrong title bar including buttons (Minimise, Close, etc.)
  • Wrong size Font in title bar
  • Wrong FontWeight in headings (Windows 7 SemiBold setting = Windows 8 Bold setting)
  • Icon (or text) misaligned in title bar
  • Icon in title bar is very blurry
  • Wrong Padding and/or Margin settings spacing out items on left
  • Wrong Padding and/or Margin settings reducing Textbox Heights on right
  • 'Hidden' default selection colour on items on left no longer hidden
  • Back to front Checkbox tick
  • Images on some Buttons are very blurry

So, my question is this:

Why do WPF Applications look different between Windows 7 and Windows 8 and can this be fixed?

To clarify this, I'm not after a list of differences between WPF on the two operating systems. I'm also not after fixes for the individual points listed above. I would like for someone to explain why these UIs look different, eg. what is causing these differences. I have also heard talk of some system settings in WPF that would enable me to make the PC render the application as if it were on Windows 7, but I don't know how truthful that was.


UPDATE >>>

As @AndrasSebö kindly pointed out, there is a StackOverflow question named Windows 7 theme for WPF?, which fixes a similar problem for Windows XP. Unfortunately, it doesn't seem to have any effect on Windows 8. Are there any Microsoft users out there that actually know what differences were implemented to cause this problem? Or anyone?


UPDATE 2 >>>

Ok, so after some more testing, I'm beginning to think that this problem is not related to the Windows Theme. Using the code provided in @Gusdor's answer, I tried changing the theme to Aero and there was no visible difference... that got me thinking. I then changed it to Luna to test that code and it worked.

By 'worked', I mean that the Windows Theme changed, but the UI controls, or more accurately, the incorrect Padding and Margin remained. I then tried changing the Theme to Luna using the XAML method mentioned by @AndrasSebö and the same thing happened... the ScrollBars looked different, so I could see that the Theme had changed, but the problem remained.

So now I'm thinking that this might have something to do with the fact that this is a brand new computer that I'm working on... might there be some dll or setting that I need to install? I'm really just guessing here - I have the whole Microsoft .NET Framework installed to version 4.5.1 as I'm on Windows 8.1.

This is an absolute nightmare as I don't have time to go and fix every view in this large application. Please help if you can.

Was it helpful?

Solution

Ok, so unfortunately, there was no quick fix for this problem. If you are in a similar situation and the answers supplied here do not work for you either, then here is a summary of the changes that I manually needed to make in order to make the UI on Windows 8 appear the same as the UI on Windows 7.

TextBox: Needed to add Padding to default Style:

<Setter Property="Padding" Value="1.5,2" />

ListBoxItem: Needed to provide new ControlTemplate to hide selection and mouse over background colours:

<Style x:Key="DefaultListBoxItem" TargetType="{x:Type ListBoxItem}">
    <Setter Property="Padding" Value="0" />
    <Setter Property="Margin" Value="2,0,1,0" />
    <Setter Property="HorizontalContentAlignment" Value="Stretch" />
    <Setter Property="VerticalContentAlignment" Value="Top" />
    <Setter Property="Background" Value="Transparent" />
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="KeyboardNavigation.TabNavigation" Value="Local" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ListBoxItem">
                <Grid Background="{TemplateBinding Background}">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal" />
                            <VisualState x:Name="MouseOver" />
                            <VisualState x:Name="Disabled">
                                <Storyboard>
                                    <DoubleAnimation Storyboard.TargetName="contentPresenter" Storyboard.TargetProperty="Opacity" Duration="0" To=".55" />
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="SelectionStates">
                            <VisualState x:Name="Unselected" />
                            <VisualState x:Name="Selected" /> 
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="FocusStates">
                            <VisualState x:Name="Focused">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="FocusVisualElement" Storyboard.TargetProperty="Visibility" Duration="0">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Visible</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Unfocused"/>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <ContentPresenter x:Name="contentPresenter" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}"/>
                    <Rectangle x:Name="FocusVisualElement" Fill="{x:Null}" Stroke="{x:Null}" StrokeThickness="0" Visibility="Collapsed" RadiusX="1" RadiusY="1" />
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

ComboBoxItem: Needed to provide new ControlTemplate to change selection and mouse over background colours:

<Style x:Key="{x:Type ComboBoxItem}" TargetType="{x:Type ComboBoxItem}">
    <Setter Property="SnapsToDevicePixels" Value="true" />
    <Setter Property="OverridesDefaultStyle" Value="true" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ComboBoxItem}">
                <Border x:Name="Border" Padding="2" SnapsToDevicePixels="true" Background="Transparent">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal" />
                            <VisualState x:Name="MouseOver">
                                <Storyboard>
                                    <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
                                        <EasingColorKeyFrame KeyTime="0" Value="#FF47484C" /> <!-- Background mouse over colour -->
                                    </ColorAnimationUsingKeyFrames>
                                    <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border" Storyboard.TargetProperty="(TextElement.Foreground).(SolidColorBrush.Color)">
                                        <EasingColorKeyFrame KeyTime="0" Value="White" /> <!-- Foreground mouse over colour -->
                                    </ColorAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Disabled" />
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="SelectionStates">
                            <VisualState x:Name="Unselected" />
                            <VisualState x:Name="Selected">
                                <Storyboard>
                                    <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
                                        <EasingColorKeyFrame KeyTime="0" Value="#FF47484C" /> <!-- Background selection colour -->
                                    </ColorAnimationUsingKeyFrames>
                                    <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border" Storyboard.TargetProperty="(TextElement.Foreground).(SolidColorBrush.Color)">
                                        <EasingColorKeyFrame KeyTime="0" Value="White" /> <!-- Foreground selection colour -->
                                    </ColorAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="SelectedUnfocused">
                                <Storyboard>
                                    <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
                                        <EasingColorKeyFrame KeyTime="0" Value="Red" />
                                    </ColorAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <ContentPresenter />
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

CheckBox: Needed to provide new ControlTemplate to stop tick from appearing back to front when Bullet is to the right of the Content (thanks to Fredrik's answer to the Default ControlTemplate for CheckBox question here on Stack Overflow:

<SolidColorBrush x:Key="CheckBoxFillNormal" Color="#F4F4F4" />
<SolidColorBrush x:Key="CheckBoxStroke" Color="#8E8F8F" />
<Style x:Key="EmptyCheckBoxFocusVisual">
    <Setter Property="Control.Template">
        <Setter.Value>
            <ControlTemplate>
                <Rectangle Margin="1" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2" />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<Style x:Key="CheckRadioFocusVisual">
    <Setter Property="Control.Template">
        <Setter.Value>
            <ControlTemplate>
                <Rectangle Margin="14,0,0,0" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2" />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<Style x:Key="{x:Type CheckBox}" TargetType="{x:Type CheckBox}">
    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
    <Setter Property="Background" Value="{StaticResource CheckBoxFillNormal}"/>
    <Setter Property="BorderBrush" Value="{StaticResource CheckBoxStroke}"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="FocusVisualStyle" Value="{StaticResource EmptyCheckBoxFocusVisual}"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type CheckBox}">
                <BulletDecorator Background="Transparent" SnapsToDevicePixels="true">
                    <BulletDecorator.Bullet>
                        <Aero:BulletChrome BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" IsChecked="{TemplateBinding IsChecked}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsPressed}"/>
                    </BulletDecorator.Bullet>
                    <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                </BulletDecorator>
                <ControlTemplate.Triggers>
                    <Trigger Property="HasContent" Value="true">
                        <Setter Property="FocusVisualStyle" Value="{StaticResource CheckRadioFocusVisual}"/>
                        <Setter Property="Padding" Value="4,0,0,0"/>
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

To remove the horrendous title bar and display the default Windows 8 one: Needed to upgrade to .NET 4.5 and utilise the included System.Windows.Controls.Ribbon namespace library instead of the separate 'Microsoft Ribbon for WPF' (RibbonControlsLibrary) dll previously used.

Unfortunately, I never found out how to reproduce the SemiBold setting of the FontWeight property on Windows 8. If anyone knows how to do this, please let me know.

On the whole, the move to Windows 8 has been a painful and troubling experience. I hope this information will help others in a slightly less painful manner.

OTHER TIPS

The problem (as described in other answers) is that WPF picks a default theme determined by the operating system version.

You need to override this behavior. THIS ARTICLE describes how:

WPF comes with a few theme assemblies, one for each Windows theme (Luna, Royale and Aero and the fallback theme, Classic.) Usually the theme is loaded according to your current system theme, but if you want to create a consistent look for your application, you may want to force-load a specific one.

To accomplish that, simply add the following code in your Application Startup event (this example shows how to use the Aero theme):

Uri uri = new Uri(“PresentationFramework.Aero;V3.0.0.0;31bf3856ad364e35;component\\themes/aero.normalcolor.xaml”, UriKind.Relative);

Resources.MergedDictionaries.Add(Application.LoadComponent(uri) as ResourceDictionary); 

It’s important to specify the version and the public key token. Otherwise you’ll have to copy the theme assembly to the folder of your executable. The reason I’m adding it to the merged dictionaries collection is that I don’t want to lose other resources I added to the App.xaml file.

If you use WPF without custom (explicit) style it is going to use standard windows 7 aero style. In case of windows 8 it is different (aero2).

If you would like to make sure, your application appears same on windows7 and on windows8 as well I recommend to create custom style where you define margin, paddings, fonts, etc by yourself.

Your problem may be related to this

There is currently a bug within the WPF ribbon library, which causes the Windows 8 theme not to apply if a ribbonwindow is being used.

Furthermore Windows 7 and 8 use simply different styles for their Controls such as Textboxes. When developing for multiple platforms, be it only Windows, you must be aware that sizes, margins and paddings change. Instead of absolute values you should let the controls dictate their need for space by avoiding setting explicit heights or widths altogether.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top