使WPF应用程序看起来像Metro风格,即使在Windows 7中也是如此?(Chrome浏览器/主题/主题)


123

我喜欢新的Office Suite和Visual Studio上的窗口镶边:

在此处输入图片说明

当然,我仍在为Windows 7开发应用程序,但我想知道是否有一种快速简便的方法(阅读:WPF样式或Windows库)来模仿这种样式。我过去曾经做过一些窗口镀铬样式设计,但是要使其外观和行为恰到好处确实很棘手。

有谁知道是否有现有的模板或库可以为WPF应用程序添加“现代UI”外观?


8
该指南/ NuGet程序包可能会有所帮助:MahaApps Metro它包含一组样式和控件,以创建具有Metro外观的WPF应用程序。
奥利弗·沃格尔

要求我们推荐或查找书籍,工具,软件库,教程或其他非现场资源的问题对于Stack Overflow来说是不重要的,因为它们往往会吸引有思想的答案和垃圾邮件。相反,请描述问题以及迄今为止已解决的问题。
斯科特·索默

Answers:


149

我所做的就是创建自己的窗口和样式。因为我喜欢控制一切,所以我不希望某些外部库仅使用其中的Window。我看了已经在GitHub上提到的MahApps.Metro

MahApps

以及GitHub上非常漂亮的Modern UI。(仅.NET4.5)

现代UI

还有另外一个是Elysium,但我真的没有尝试过。

极乐世界

当我查看这些样式的完成方式时,我做的样式真的很简单。现在我有了自己的Window,并且可以用xaml做任何我想做的事...对我来说,这就是我自己做的主要原因。我也为您提供了一个新的工具:)我可能应该说,如果不探索Modern UI,我将无法做到这一点,这是非常有用的。我试图使它看起来像VS2012窗口。看起来像这样。

我的窗户

这是代码(请注意,它的目标是.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
您好,非常感谢您发布的出色代码。请问一个问题,窗户上可能有阴影吗?我唯一想到的就是更改GlassFrameThickness1。但是阴影太浓太暗。如何更改其重量和不透明度?
xperator


创建自己的组件自定义而不是使用MahApps很难吗?
Matheus Saraiva

幻想曲!非常感谢您的出色贡献,我曾多次尝试做同样的事情,但从未获得如此完美的成绩。
Leodev

假设我想增加顶部蓝色边框的厚度,并去除所有其他侧面的边框(例如您的答案中的elysium pic),我需要更改什么?我是wpf的新手,因此提出了问题
凌晨

49

我最终选择的解决方案是MahApps.Metrogithub),该解决方案(现在已经在两个软件上使用了),我认为这是一个出色的UI套件(建议给Oliver Vogel推荐

窗式

它只需很少的工作即可为应用程序设置外观,并适应了标准Windows 8控件。非常健壮。

文字框水印

Nuget上有一个版本:

您可以使用GUI通过Nuget来安装MahApps.Metro(右键单击您的项目,管理Nuget引用,搜索“ MahApps.Metro”)或通过控制台:

PM>安装包MahApps.Metro

它也是免费的 -甚至用于商业用途。

2013年10月29日更新:

我发现MahApps.Metro的Github版本包含了当前nuget版本中不可用的控件和样式,包括:

数据网格:

在此处输入图片说明

清洁窗口:

在此处输入图片说明

弹出式广告:

在此处输入图片说明

瓷砖:

在此处输入图片说明

github存储库非常活跃,用户贡献很大。我建议检查一下。


我测试了,不错+1 :)
Akrem

3
非常好的更新!我还尝试了MahApps.Metro,WPF和Elysium的Modern UI。我发现Elysium太复杂了,难以在其网站/文档上使用和混淆。Modern UI和MahApps.Metro重量轻且易于使用,但是MahApps。 Metro在WPF表单控件上更具竞争力。
张翔

创建自己的组件自定义而不是使用MahApps很难吗?
Matheus Saraiva

42

我会推荐WPF的Modern UI

它有一个非常活跃的维护者,它很棒而且免费!

WPF的现代UI(示例应用程序的屏幕快照

我目前正在将一些项目移植到MUI,第一(同时第二)的印象真是太好了!

要查看运行中的MUI,可以下载基于MUI的XAML Spy

编辑: WPF使用现代UI几个月,我很喜欢它!


16

基于以上来源的Viktor La Croix答案,我将其更改为使用以下内容:

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>


嗨,飞行特立独行。您能否解释为什么使用marlett字体是更好的做法?我有三种不同的实现方式,我不确定要使用哪一种。第一个使用路径数据点,第二个使用marlett,第三个使用SVG格式的按钮重新创建。我正在尝试在此项目中使用100%最佳实践,但不确定哪一个是最佳选择。您能解释一下为什么Marlett更好吗?
user1632018 2014年

1
嗨,user1632018嗨,如果您希望在Winform或WPF中创建自定义镶边窗口,则应该查看系统上可用的'Marlett'字体。该字体包含Windows中用于“最小化”,“最大化”,“还原”和“关闭”按钮的实际字形。使用此字体可以非常轻松地在自定义镶边窗口中重用这些字形,而不是通常使用的自定义图像。您可以查看Windows字符映射表中的Marlett字体或以下链接,以了解更多详细信息:microsoft.com/typography/fonts/font.aspx?FMID=1264 希望这会有所帮助。
FlyingMaverick 2014年

2

如果您愿意付费,我强烈建议您使用Telerik Components for WPF。它们提供了出色的样式/主题,并且有针对Office 2013和Windows 8的特定主题(编辑:还有Visual Studio 2013主题样式)。但是实际上除了样式之外,您还可以提供更多的控件,这些控件确实非常有用。

这是实际效果(从telerik示例中截取的屏幕截图):

Telerik仪表板样本

Telerik CRM仪表板样本

这是Telerik Executive仪表板示例的链接(第一个屏幕截图),在这里是CRM仪表板的链接(第二个屏幕截图)。

他们提供30天的试用期,只需试一试!


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.