让 WPF 应用程序看起来像 Metro 风格,即使在 Windows 7 中? (窗口 Chrome / 主题 / 主题)
Posted
技术标签:
【中文标题】让 WPF 应用程序看起来像 Metro 风格,即使在 Windows 7 中? (窗口 Chrome / 主题 / 主题)【英文标题】:Making WPF applications look Metro-styled, even in Windows 7? (Window Chrome / Theming / Theme) 【发布时间】:2012-11-15 13:14:30 【问题描述】:我喜欢新 Office 套件和 Visual Studio 上的窗口镶边:
当然,我仍在为 Windows 7 开发应用程序,但我想知道是否有一种快速简便的方法(阅读:WPF 样式或 Windows 库)来模拟这种样式。我过去做过一些窗口镶边样式,但让它看起来和表现得恰到好处真的很棘手。
有谁知道是否有现有的模板或库可以为我的 WPF 应用程序添加“现代 UI”外观和感觉?
【问题讨论】:
本指南/ NuGet 包可能会有所帮助:MahaApps Metro 它包含一组样式和控件,用于创建具有 Metro 外观的 WPF 应用程序。 要求我们推荐或查找书籍、工具、软件库、教程或其他场外资源的问题对于 Stack Overflow 来说是题外话,因为它们往往会吸引固执己见答案和垃圾邮件。相反,请描述问题以及迄今为止为解决该问题所做的工作。 【参考方案1】:我最终选择的解决方案是MahApps.Metro (github),它(现在在两个软件上使用它之后)我认为是一个优秀的 UI 工具包(感谢 Oliver Vogel 的建议) .
它只需要很少的努力就可以为应用程序设置皮肤,并且适应了标准的 Windows 8 控件。它非常强大。
Nuget 上有一个版本:
您可以使用 GUI 通过 Nuget 安装 MahApps.Metro(右键单击 您的项目,管理 Nuget 引用,搜索“MahApps.Metro”)或 通过控制台:
PM> 安装包 MahApps.Metro
它也是免费——即使用于商业用途。
2013 年 10 月 29 日更新:
我发现 Github 版本的 MahApps.Metro 包含当前 nuget 版本中不可用的控件和样式,包括:
数据网格:
清洁窗口:
弹出窗口:
瓷砖:
github 存储库非常活跃,有相当多的用户贡献。我建议检查一下。
【讨论】:
非常好的更新!我还尝试了 MahApps.Metro,用于 WPF 和 Elysium 的 Modern UI。我发现 Elysium 使用起来非常复杂,并且在他们的网站/文档上令人困惑。现代 UI 和 MahApps.Metro 重量轻且易于使用,但是 MahApps。 Metro 在 WPF 表单控件上更具竞争力。 不使用 MahApps 来创建自己的组件定制是否非常困难?【参考方案2】:我所做的是创建自己的窗口和样式。因为我喜欢控制一切,我不希望一些外部库只是为了使用它的 Window。我看了已经提到的MahApps.Metro on GitHub
也非常好Modern UI on GitHub。 (仅限 .NET4.5)
还有一个是Elysium,但我真的没试过这个。
当我看到它是如何完成的时,我所做的风格真的很简单。现在我有了自己的窗口,我可以用 xaml 做任何我想做的事情......对我来说,这是我自己做的主要原因。我也为你做了一个 :) 我应该说如果不探索 Modern UI 我将无法做到这一点,这对我很有帮助。我试图让它看起来像 VS2012 Window。看起来像这样。
这是代码(请注意它的目标是 .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>
【讨论】:
您好,非常感谢您发布的这么棒的代码。顺便问一句,窗户上可以有阴影吗?我唯一想到的是将GlassFrameThickness
更改为1
。但是阴影太浓了,太黑了。我怎样才能改变它的重量和不透明度?
Add DropShadow to a Custom made Window
不使用 MahApps 来创建自己的组件定制是否非常困难?
太棒了!非常感谢您做出如此出色的贡献,我曾多次尝试做同样的事情,但从未得到如此完美的结果。
假设我想增加顶部蓝色边框的厚度,并删除所有其他边的边框(如你的答案中的极乐世界图片),我需要改变什么?我是 wpf 的新手,因此提出了这个问题【参考方案3】:
基于Kapitán Mlíko's answer 上面的源代码,我会将其更改为使用以下内容:
对于最小化、恢复/最大化和关闭按钮,最好使用 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 如果您希望在 Winform 或 WPF 中创建自定义 chrome 窗口,您应该查看系统上可用的“Marlett”字体。此字体包含 Windows 中用于最小化、最大化、恢复和关闭按钮的实际字形。使用这种字体可以很容易地在自定义 chrome 窗口中重用这些字形,而不是通常使用的自定义图像。您可以查看 Windows Character Map 中的 Marlett 字体或以下链接了解更多详细信息:microsoft.com/typography/fonts/font.aspx?FMID=1264希望对您有所帮助。【参考方案4】:我会推荐 Modern UI for WPF 。
它有一个非常活跃的维护者,它很棒而且免费!
我目前正在将一些项目移植到 MUI,第一(同时也是第二)印象真是太棒了!
要查看 MUI 的实际效果,您可以下载基于 MUI 的 XAML Spy。
编辑:在 WPF 中使用 Modern UI 几个月,我很喜欢它!
【讨论】:
【参考方案5】:如果你愿意付费,我强烈推荐你Telerik Components for WPF。他们提供了很棒的styles/themes 并且有针对Office 2013 和Windows 8 的特定主题(编辑:还有Visual Studio 2013 主题风格)。然而,这里提供的不仅仅是样式,实际上你会得到一大堆非常有用的控件。
下面是它的实际效果(从 Telerik 样本中截取的屏幕截图):
这里是telerik executive dashboard sample(第一个屏幕截图)的链接,这里是CRM Dashboard(第二个屏幕截图)的链接。
他们提供 30 天的试用期,试一试!
【讨论】:
【参考方案6】:看看这个WPF metro-styled window with optional glowing borders。
这是一个独立的应用程序,它使用 Microsoft.Windows.Shell(包括在内)以外的任何其他库来创建带有可选发光边框的 Metro 风格窗口。
支持 Windows 一直到 XP (.NET4)。
【讨论】:
以上是关于让 WPF 应用程序看起来像 Metro 风格,即使在 Windows 7 中? (窗口 Chrome / 主题 / 主题)的主要内容,如果未能解决你的问题,请参考以下文章
wpf metro风格,怎么自定义gridview的scrollbar,就是想美化一下