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

前端 未结 4 458
無奈伤痛
無奈伤痛 2021-01-31 10:13

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 b

相关标签:
4条回答
  • 2021-01-31 10:46

    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.

    0 讨论(0)
  • 2021-01-31 10:54

    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.

    0 讨论(0)
  • 2021-01-31 11:05

    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.

    0 讨论(0)
  • 2021-01-31 11:07

    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.

    0 讨论(0)
提交回复
热议问题