Почему приложения WPF отличаются друг от друга между Windows 7 и Windows 8, и можно ли это устранить?

Я действительно удивлен, что этот вопрос, похоже, еще не задан... если он есть, но я просто не мог его найти, извинения.

Хорошо, поэтому мой рабочий компьютер только что был обновлен с Windows 7 до Windows 8. К моему абсолютному ужасу, мое приложение WPF выглядит по-разному несколькими способами... разными, я имею в виду хуже, уродливее, элементы управления не выстроены правильно и т.д. Вот пример:

Windows 7:

enter image description here

Windows 8:

enter image description here

Проблемы с Windows 8 (только с этого изображения):

  • Неверная строка заголовка, включая кнопки (Свернуть, Закрыть и т.д.).
  • Неверный размер шрифта в строке заголовка
  • Неверный FontWeight в заголовках (настройка Windows 7 SemiBold = настройка выделенной области Windows 8)
  • Значок (или текст) смещен в строке заголовка
  • Значок в строке заголовка очень размыт.
  • Неправильные настройки заполнения и/или маржи, разделяющие элементы слева.
  • Неправильные настройки заполнения и/или маржи, уменьшающие высоту текстового поля справа.
  • "Скрытый" цвет выбора по умолчанию на элементах слева больше не скрыт
  • Назад на передний флажок галочка
  • Изображения на некоторых кнопках очень размыты.

Итак, мой вопрос таков:

Почему приложения WPF отличаются друг от друга между Windows 7 и Windows 8 и могут ли быть исправлены?

Чтобы прояснить это, я не вижу список различий между WPF в двух операционных системах. Я также не после исправлений для отдельных пунктов, перечисленных выше. Я бы хотел, чтобы кто-то объяснил, почему эти пользовательские интерфейсы выглядят иначе, например. что вызывает эти различия. Я также слышал разговоры о некоторых системных настройках в WPF, которые позволили бы мне заставить ПК отображать приложение, как если бы оно было на Windows 7, но я не знаю, насколько это было правдой.


ОБНОВЛЕНИЕ → >

Как @AndrasSebö любезно отметил, есть вопрос StackOverflow под названием тема Windows 7 для WPF?, которая устраняет аналогичную проблему для Windows XP. К сожалению, это никак не влияет на Windows 8. Есть ли там пользователи Microsoft, которые действительно знают, какие различия были реализованы, чтобы вызвать эту проблему? Или кто-нибудь?


ОБНОВЛЕНИЕ 2 → >

Хорошо, поэтому после некоторого тестирования я начинаю думать, что эта проблема не связана с темой Windows. Используя код, указанный в ответе @Gusdor, я попытался изменить тему на Aero, и не было видимой разницы..., которая заставила меня задуматься. Затем я изменил его на Luna, чтобы проверить этот код, и он сработал.

"Я работал", я имею в виду, что тема Windows изменилась, но элементы управления пользовательским интерфейсом или, точнее, остались некорректные Padding и Margin. Затем я попытался изменить тему на Luna с помощью метода XAML, упомянутого @AndrasSebö, и произошло то же самое... ScrollBar выглядел по-другому, поэтому я мог видеть, что тема изменилась, но проблема осталась.

Итак, теперь я думаю, что это может иметь какое-то отношение к тому факту, что это новый компьютер, над которым я работаю... может быть, есть какая-то dll или настройка, которую мне нужно установить? Я просто угадываю здесь - у меня есть вся платформа Microsoft.NET Framework, установленная до версии 4.5.1, поскольку я нахожусь в Windows 8.1.

Это абсолютный кошмар, поскольку у меня нет времени, чтобы пойти и исправить все представления в этом большом приложении. Пожалуйста, помогите, если сможете.

Ответы

Ответ 1

Хорошо, к сожалению, не было быстрого решения этой проблемы. Если вы находитесь в подобной ситуации, и предоставленные здесь ответы также не подходят для вас, то вот краткое изложение изменений, которые я вручную должен был сделать, чтобы пользовательский интерфейс в Windows 8 выглядел так же, как пользовательский интерфейс в Windows 7.

TextBox: необходимо добавить Padding к умолчанию Style:

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

ListBoxItem: необходимо предоставить новый ControlTemplate, чтобы скрыть выделение и мыши над цветами фона:

<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: необходимо предоставить новый ControlTemplate для изменения выбора и мыши над цветами фона:

<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: необходимо предоставить новый ControlTemplate, чтобы остановить тик от появления назад, когда Bullet находится справа от Content (благодаря ответу Fredrik на Default ControlTemplate для CheckBox здесь, в разделе Переполнение стека:

<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>

Чтобы удалить ужасную строку заголовка и отобразить Windows 8 по умолчанию: необходимо обновить до .NET 4.5 и использовать включенную библиотеку имен System.Windows.Controls.Ribbon вместо отдельной ранее используемой DLL-библиотеки Microsoft Ribbon for WPF (RibbonControlsLibrary).

К сожалению, я никогда не узнал, как воспроизвести параметр SemiBold свойства FontWeight в Windows 8. Если кто-нибудь знает, как это сделать, сообщите мне.

В целом переход на Windows 8 был болезненным и тревожным. Я надеюсь, что эта информация поможет другим немного болезненно.

Ответ 2

Если вы используете WPF без специального (явного) стиля, он будет использовать стандартный стиль aero a7. В случае окон 8 он отличается (aero2).

Если вы хотите, чтобы ваше приложение выглядело одинаково на Windows 7 и на Windows8, я также рекомендую создать собственный стиль, в котором вы сами определяете маржу, paddings, fonts и т.д.

Ответ 3

Проблема (как описано в других ответах) заключается в том, что WPF выбирает тему по умолчанию, определенную версией операционной системы.

Вам нужно переопределить это поведение. ЭТА СТАТЬЯ описывает, как:

WPF поставляется с несколькими сборками тем, по одному для каждой темы Windows (Luna, Royale и Aero и рекурсивная тема, Classic.) Обычно тема загружается в соответствии с вашей текущей системной темой, но если вы хотите создать последовательный поиск своего приложения, вы можете захотеть принудительная нагрузка конкретной.

Чтобы это сделать, просто добавьте следующий код в свое приложение Событие запуска (в этом примере показано, как использовать тему Aero):

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); 

Важно указать версию и токен открытого ключа. В противном случае вам придется скопировать сборку тем в папку вашего исполняемый файл. Причина, по которой я добавляю его в объединенные словари что я не хочу потерять другие ресурсы, которые я добавил в Файл App.xaml.

Ответ 4

Ваша проблема может быть связана с this

В библиотеке лент WPF есть ошибка, из-за которой тема Windows 8 не применяется, если используется ленточный режим.

Кроме того, Windows 7 и 8 используют просто разные стили для своих элементов управления, таких как текстовые поля. При разработке для нескольких платформ, будь то только Windows, вы должны знать, что размеры, поля и paddings изменяются. Вместо абсолютных значений вы должны позволить элементам управления определять их потребность в пространстве, избегая установки явных высот или ширины вообще.