Как заставить приложения WPF выглядеть в стиле Metro даже в Windows 7? (Окно Chrome / Темы / Тема)

123

Мне нравится хром окна в новом Office Suite и Visual Studio:

введите описание изображения здесь

Конечно, я все еще разрабатываю приложения для Windows 7, но мне интересно, есть ли быстрый и простой способ (читай: стиль WPF или библиотека Windows) для имитации этого стиля. Раньше я делал хромированные окна для окон, но заставить их выглядеть и вести себя правильно - это действительно сложно.

Кто-нибудь знает, существуют ли существующие шаблоны или библиотеки для добавления внешнего вида «Современный пользовательский интерфейс» к моим приложениям WPF?

Даниил
источник
8
Это руководство / пакет NuGet может быть полезным: MahaApps Metro. Он содержит набор стилей и элементов управления для создания приложений WPF с использованием стиля Metro.
Оливер Фогель
Вопросы, просящие нас порекомендовать или найти книгу, инструмент, библиотеку программного обеспечения, учебное пособие или другой сторонний ресурс, не относятся к теме Stack Overflow, поскольку они, как правило, привлекают самоуверенные ответы и спам. Вместо этого опишите проблему и то, что было сделано для ее решения.
Скотт Солмер

Ответы:

149

Я создал свое собственное окно и стиль. Потому что мне нравится контролировать все, и я не хотел, чтобы некоторые внешние библиотеки просто использовали окно из них. Посмотрел уже упомянутый MahApps.Metro на GitHub

MahApps

а также очень красивый современный интерфейс на GitHub . (Только .NET4.5)

Современный интерфейс

Есть еще один, это Elysium, но я действительно не пробовал этот.

элизиум

Стиль, который я сделал, был действительно легким, когда я посмотрел, как это делается в этих. Теперь у меня есть собственное окно, и я могу делать с xaml все, что захочу ... для меня это основная причина, по которой я сделал собственное. И я сделал еще один для вас :) Наверное, я бы сказал, что не смог бы сделать это, не изучив Modern UI, это было большим подспорьем. Я попытался сделать его похожим на VS2012 Window. Это похоже на это.

MyWindow

Вот код (обратите внимание, что он нацелен на .NET4.5)

public class MyWindow : Window
{

    public MyWindow()
    {
        this.CommandBindings.Add(new CommandBinding(SystemCommands.CloseWindowCommand, this.OnCloseWindow));
        this.CommandBindings.Add(new CommandBinding(SystemCommands.MaximizeWindowCommand, this.OnMaximizeWindow, this.OnCanResizeWindow));
        this.CommandBindings.Add(new CommandBinding(SystemCommands.MinimizeWindowCommand, this.OnMinimizeWindow, this.OnCanMinimizeWindow));
        this.CommandBindings.Add(new CommandBinding(SystemCommands.RestoreWindowCommand, this.OnRestoreWindow, this.OnCanResizeWindow));
    }

    private void OnCanResizeWindow(object sender, CanExecuteRoutedEventArgs e)
    {
        e.CanExecute = this.ResizeMode == ResizeMode.CanResize || this.ResizeMode == ResizeMode.CanResizeWithGrip;
    }

    private void OnCanMinimizeWindow(object sender, CanExecuteRoutedEventArgs e)
    {
        e.CanExecute = this.ResizeMode != ResizeMode.NoResize;
    }

    private void OnCloseWindow(object target, ExecutedRoutedEventArgs e)
    {
        SystemCommands.CloseWindow(this);
    }

    private void OnMaximizeWindow(object target, ExecutedRoutedEventArgs e)
    {
        SystemCommands.MaximizeWindow(this);
    }

    private void OnMinimizeWindow(object target, ExecutedRoutedEventArgs e)
    {
        SystemCommands.MinimizeWindow(this);
    }

    private void OnRestoreWindow(object target, ExecutedRoutedEventArgs e)
    {
        SystemCommands.RestoreWindow(this);
    }
}

А вот ресурсы:

<BooleanToVisibilityConverter x:Key="bool2VisibilityConverter" />

<Color x:Key="WindowBackgroundColor">#FF2D2D30</Color>
<Color x:Key="HighlightColor">#FF3F3F41</Color>
<Color x:Key="BlueColor">#FF007ACC</Color>
<Color x:Key="ForegroundColor">#FFF4F4F5</Color>

<SolidColorBrush x:Key="WindowBackgroundColorBrush" Color="{StaticResource WindowBackgroundColor}"/>
<SolidColorBrush x:Key="HighlightColorBrush" Color="{StaticResource HighlightColor}"/>
<SolidColorBrush x:Key="BlueColorBrush" Color="{StaticResource BlueColor}"/>
<SolidColorBrush x:Key="ForegroundColorBrush" Color="{StaticResource ForegroundColor}"/>

<Style x:Key="WindowButtonStyle" TargetType="{x:Type Button}">
    <Setter Property="Foreground" Value="{DynamicResource ForegroundColorBrush}" />
    <Setter Property="Background" Value="Transparent" />
    <Setter Property="HorizontalContentAlignment" Value="Center" />
    <Setter Property="VerticalContentAlignment" Value="Center" />
    <Setter Property="Padding" Value="1" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <Grid Background="{TemplateBinding Background}">
                    <ContentPresenter x:Name="contentPresenter"
                          HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                          VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                          SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                          Margin="{TemplateBinding Padding}"
                          RecognizesAccessKey="True" />
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="Background" Value="{StaticResource HighlightColorBrush}" />
                    </Trigger>
                    <Trigger Property="IsPressed" Value="True">
                        <Setter Property="Background" Value="{DynamicResource BlueColorBrush}" />
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter TargetName="contentPresenter" Property="Opacity" Value=".5" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<Style x:Key="MyWindowStyle" TargetType="local:MyWindow">
    <Setter Property="Foreground" Value="{DynamicResource ForegroundColorBrush}" />
    <Setter Property="Background" Value="{DynamicResource WindowBackgroundBrush}"/>
    <Setter Property="ResizeMode" Value="CanResizeWithGrip" />
    <Setter Property="UseLayoutRounding" Value="True" />
    <Setter Property="TextOptions.TextFormattingMode" Value="Display" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:MyWindow">
                <Border x:Name="WindowBorder" Margin="{Binding Source={x:Static SystemParameters.WindowNonClientFrameThickness}}" Background="{StaticResource WindowBackgroundColorBrush}">
                    <Grid>
                        <Border BorderThickness="1">
                            <AdornerDecorator>
                                <Grid x:Name="LayoutRoot">
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="25" />
                                        <RowDefinition Height="*" />
                                        <RowDefinition Height="15" />
                                    </Grid.RowDefinitions>
                                    <ContentPresenter Grid.Row="1" Grid.RowSpan="2" Margin="7"/>
                                    <Rectangle x:Name="HeaderBackground" Height="25" Fill="{DynamicResource WindowBackgroundColorBrush}" VerticalAlignment="Top" Grid.Row="0"/>
                                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Top" WindowChrome.IsHitTestVisibleInChrome="True" Grid.Row="0">
                                        <Button Command="{Binding Source={x:Static SystemCommands.MinimizeWindowCommand}}" ToolTip="minimize" Style="{StaticResource WindowButtonStyle}">
                                            <Button.Content>
                                                <Grid Width="30" Height="25" RenderTransform="1,0,0,1,0,1">
                                                    <Path Data="M0,6 L8,6 Z" Width="8" Height="7" VerticalAlignment="Center" HorizontalAlignment="Center"
                                                        Stroke="{Binding Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Button}}" StrokeThickness="2"  />
                                                </Grid>
                                            </Button.Content>
                                        </Button>
                                        <Grid Margin="1,0,1,0">
                                            <Button x:Name="Restore" Command="{Binding Source={x:Static SystemCommands.RestoreWindowCommand}}" ToolTip="restore" Visibility="Collapsed" Style="{StaticResource WindowButtonStyle}">
                                                <Button.Content>
                                                    <Grid Width="30" Height="25" UseLayoutRounding="True" RenderTransform="1,0,0,1,.5,.5">
                                                        <Path Data="M2,0 L8,0 L8,6 M0,3 L6,3 M0,2 L6,2 L6,8 L0,8 Z" Width="8" Height="8" VerticalAlignment="Center" HorizontalAlignment="Center"
                                                            Stroke="{Binding Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Button}}" StrokeThickness="1"  />
                                                    </Grid>
                                                </Button.Content>
                                            </Button>
                                            <Button x:Name="Maximize" Command="{Binding Source={x:Static SystemCommands.MaximizeWindowCommand}}" ToolTip="maximize" Style="{StaticResource WindowButtonStyle}">
                                                <Button.Content>
                                                    <Grid Width="31" Height="25">
                                                        <Path Data="M0,1 L9,1 L9,8 L0,8 Z" Width="9" Height="8" VerticalAlignment="Center" HorizontalAlignment="Center"
                                                            Stroke="{Binding Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Button}}" StrokeThickness="2"  />
                                                    </Grid>
                                                </Button.Content>
                                            </Button>
                                        </Grid>
                                        <Button Command="{Binding Source={x:Static SystemCommands.CloseWindowCommand}}" ToolTip="close"  Style="{StaticResource WindowButtonStyle}">
                                            <Button.Content>
                                                <Grid Width="30" Height="25" RenderTransform="1,0,0,1,0,1">
                                                    <Path Data="M0,0 L8,7 M8,0 L0,7 Z" Width="8" Height="7" VerticalAlignment="Center" HorizontalAlignment="Center"
                                                        Stroke="{Binding Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Button}}" StrokeThickness="1.5"  />
                                                </Grid>
                                            </Button.Content>
                                        </Button>
                                    </StackPanel>
                                    <TextBlock x:Name="WindowTitleTextBlock" Grid.Row="0" Text="{TemplateBinding Title}" HorizontalAlignment="Left" TextTrimming="CharacterEllipsis" VerticalAlignment="Center"  Margin="8 -1 0 0"  FontSize="16"  Foreground="{TemplateBinding Foreground}"/>
                                    <Grid Grid.Row="2">
                                        <Path x:Name="ResizeGrip" Visibility="Collapsed" Width="12" Height="12" Margin="1" HorizontalAlignment="Right"
                                        Stroke="{StaticResource BlueColorBrush}" StrokeThickness="1" Stretch="None" Data="F1 M1,10 L3,10 M5,10 L7,10 M9,10 L11,10 M2,9 L2,11 M6,9 L6,11 M10,9 L10,11 M5,6 L7,6 M9,6 L11,6 M6,5 L6,7 M10,5 L10,7 M9,2 L11,2 M10,1 L10,3" />
                                    </Grid>
                                </Grid>
                            </AdornerDecorator>
                        </Border>
                        <Border BorderBrush="{StaticResource BlueColorBrush}" BorderThickness="1" Visibility="{Binding IsActive, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Converter={StaticResource bool2VisibilityConverter}}" />
                    </Grid>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="WindowState" Value="Maximized">
                        <Setter TargetName="Maximize" Property="Visibility" Value="Collapsed" />
                        <Setter TargetName="Restore" Property="Visibility" Value="Visible" />
                        <Setter TargetName="LayoutRoot" Property="Margin" Value="7" />
                    </Trigger>
                    <Trigger Property="WindowState" Value="Normal">
                        <Setter TargetName="Maximize" Property="Visibility" Value="Visible" />
                        <Setter TargetName="Restore" Property="Visibility" Value="Collapsed" />
                    </Trigger>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="ResizeMode" Value="CanResizeWithGrip" />
                            <Condition Property="WindowState" Value="Normal" />
                        </MultiTrigger.Conditions>
                        <Setter TargetName="ResizeGrip" Property="Visibility" Value="Visible" />
                    </MultiTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="WindowChrome.WindowChrome">
        <Setter.Value>
            <WindowChrome CornerRadius="0" GlassFrameThickness="1" UseAeroCaptionButtons="False" />
        </Setter.Value>
    </Setter>
</Style>
Капитан Млико
источник
1
Привет и большое спасибо за этот отличный код, который вы разместили. Просто просьба спросить, можно ли иметь тень на окне? Единственное, в чем я разобрался, меняется GlassFrameThicknessна 1. Но тень слишком сильная и темная. Как я могу изменить его вес и прозрачность?
xperator
Насколько сложно создавать собственные настройки компонентов вместо использования MahApps?
Матеус Сараива,
FANTASTICO! Большое спасибо за этот отличный вклад, я пытался сделать то же самое много раз, но у меня никогда не было такого идеального результата.
Леодев
Предположим, я хочу увеличить толщину синей границы сверху и удалить границу со всех других сторон (например, изображение элизиума в вашем ответе), что мне нужно изменить? Я новичок в wpf, отсюда и вопрос
мрид
49

Решение, которое я выбрал, было MahApps.Metro ( github ), которое (после использования его в двух программах) я считаю отличным набором пользовательского интерфейса (благодарность Оливеру Фогелю за предложение) .

Стиль окна

Он сканирует приложение с минимальными усилиями и имеет адаптацию стандартных элементов управления Windows 8. Это очень надежно.

Водяной знак текстового поля

На Nuget доступна версия:

Вы можете установить MahApps.Metro через Nuget с помощью графического интерфейса (щелкните правой кнопкой мыши свой проект, "Управление ссылками Nuget", найдите "MahApps.Metro") или через консоль:

PM> Установочный пакет MahApps.Metro

Это также бесплатно - даже для коммерческого использования.

Обновление 29.10.2013:

Я обнаружил, что версия MahApps.Metro для Github содержит элементы управления и стили, которые недоступны в текущей версии nuget, в том числе:

DataGrids:

введите описание изображения здесь

Чистое окно:

введите описание изображения здесь

Всплывающие:

введите описание изображения здесь

плитки:

введите описание изображения здесь

Репозиторий github очень активен, и многие пользователи вносят свой вклад. Рекомендую это проверить.

Даниил
источник
Тестирую
3
очень красивое обновление! Я также пробую MahApps.Metro, Modern UI для WPF и Elysium. Я обнаружил, что Elysium настолько сложен в использовании и запутан на их веб-сайте / Doc .. Современный пользовательский интерфейс и MahApps.Metro легковесны и просты в использовании, но MahApps. Metro более конкурентоспособен в элементах управления формами WPF.
Cheung
Насколько сложно создавать собственные настройки компонентов вместо использования MahApps?
Матеус Сараива,
42

я бы порекомендовал современный интерфейс для WPF .

У него очень активный сопровождающий, это потрясающе и бесплатно!

Современный пользовательский интерфейс для WPF (снимок экрана примера приложения

Сейчас я портирую несколько проектов на MUI, первое (а пока второе) впечатление просто вау!

Чтобы увидеть MUI в действии, вы можете загрузить XAML Spy, основанный на MUI.

РЕДАКТИРОВАТЬ: Использование современного пользовательского интерфейса для WPF несколько месяцев, и мне это нравится!

Joel
источник
16

Основываясь на ответе Виктора Ла Круа с источником выше, я бы изменил его, чтобы использовать следующее:

Пример шрифта Marlett

Лучше использовать шрифт Marlett, а не точки данных пути для кнопок «Свернуть», «Восстановить / развернуть» и «Закрыть».

<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Top" WindowChrome.IsHitTestVisibleInChrome="True" Grid.Row="0">
<Button Command="{Binding Source={x:Static SystemCommands.MinimizeWindowCommand}}" ToolTip="minimize" Style="{StaticResource WindowButtonStyle}">
    <Button.Content>
        <Grid Width="30" Height="25">
            <TextBlock Text="0" FontFamily="Marlett" FontSize="14" VerticalAlignment="Center" HorizontalAlignment="Center" Padding="3.5,0,0,3" />
        </Grid>
    </Button.Content>
</Button>
<Grid Margin="1,0,1,0">
    <Button x:Name="Restore" Command="{Binding Source={x:Static SystemCommands.RestoreWindowCommand}}" ToolTip="restore" Visibility="Collapsed" Style="{StaticResource WindowButtonStyle}">
        <Button.Content>
            <Grid Width="30" Height="25" UseLayoutRounding="True">
                <TextBlock Text="2" FontFamily="Marlett" FontSize="14" VerticalAlignment="Center" HorizontalAlignment="Center" Padding="2,0,0,1" />
            </Grid>
        </Button.Content>
    </Button>
    <Button x:Name="Maximize" Command="{Binding Source={x:Static SystemCommands.MaximizeWindowCommand}}" ToolTip="maximize" Style="{StaticResource WindowButtonStyle}">
        <Button.Content>
            <Grid Width="31" Height="25">
                <TextBlock Text="1" FontFamily="Marlett" FontSize="14" VerticalAlignment="Center" HorizontalAlignment="Center" Padding="2,0,0,1" />
            </Grid>
        </Button.Content>
    </Button>
</Grid>
<Button Command="{Binding Source={x:Static SystemCommands.CloseWindowCommand}}" ToolTip="close"  Style="{StaticResource WindowButtonStyle}">
    <Button.Content>
        <Grid Width="30" Height="25">
            <TextBlock Text="r" FontFamily="Marlett" FontSize="14" VerticalAlignment="Center" HorizontalAlignment="Center" Padding="0,0,0,1" />
        </Grid>
    </Button.Content>
</Button>

FlyingMaverick
источник
Привет, летающий индивидуалист. Не могли бы вы объяснить, почему лучше использовать шрифт marlett? У меня есть три разные реализации, и я не уверен, какую из них использовать. Первый использует точки данных пути, второй использует марлетт, а третий - воссоздание кнопок в формате SVG. Я пытаюсь использовать в этом проекте 100% лучших практик и не уверен, какой из них лучший. Не могли бы вы объяснить, почему Марлетт лучше?
user1632018
1
Привет, user1632018 Если вы хотите создать собственное окно Chrome в Winform или WPF, вам следует взглянуть на шрифт Marlett, доступный в вашей системе. Этот шрифт содержит фактические глифы, используемые в Windows для кнопок «Свернуть», «Развернуть», «Восстановить» и «Закрыть». Использование этого шрифта позволяет очень легко повторно использовать эти глифы в настраиваемом окне Chrome вместо обычных изображений. Вы можете взглянуть на шрифт Marlett на карте символов Windows или по следующей ссылке для получения дополнительных сведений: microsoft.com/typography/fonts/font.aspx?FMID=1264 Надеюсь, это поможет.
FlyingMaverick
2

Если вы готовы платить, я настоятельно рекомендую вам компоненты Telerik для WPF . Они предлагают отличные стили / темы и имеют определенные темы для Office 2013 и Windows 8 (EDIT: а также тематический стиль Visual Studio 2013). Однако там предлагается гораздо больше, чем просто стили, на самом деле вы получите целый набор действительно полезных элементов управления.

Вот как это выглядит в действии (скриншоты взяты из образцов телерика):

Образец панели Telerik

Пример панели управления Telerik CRM

Вот ссылки на образец исполнительной панели управления Telerik (первый снимок экрана) и здесь на панель мониторинга CRM (второй снимок экрана).

Они предлагают 30-дневную пробную версию, просто попробуйте!

Joel
источник
0

Взгляните на это окно в стиле метро WPF с дополнительными светящимися границами .

Это автономное приложение, не использующее никаких других библиотек, кроме Microsoft.Windows.Shell (в комплекте), для создания окон в стиле метро с необязательными светящимися границами.

Поддерживает Windows вплоть до XP (.NET4).

Лайла
источник