Làm cho các ứng dụng WPF trông theo kiểu Metro, ngay cả trong Windows 7? (Cửa sổ Chrome / Chủ đề / Chủ đề)


123

Tôi thích chrome cửa sổ trên Office Suite và Visual Studio mới:

nhập mô tả hình ảnh ở đây

Tất nhiên tôi vẫn đang phát triển các ứng dụng cho Windows 7, nhưng tôi tự hỏi liệu có cách nào nhanh chóng và dễ dàng (đọc: phong cách WPF hoặc Thư viện Windows) để mô phỏng phong cách này. Tôi đã thực hiện một số kiểu chrome cửa sổ trong quá khứ, nhưng để nó nhìn và cư xử vừa phải thực sự rất khó khăn.

Có ai biết nếu có các mẫu hoặc thư viện hiện có để thêm giao diện "Giao diện người dùng hiện đại" vào các ứng dụng WPF của tôi không?


8
Hướng dẫn / Gói NuGet này có thể hữu ích: MahaApps Metro Nó chứa Tập hợp các kiểu và điều khiển để tạo Ứng dụng WPF với Giao diện và cảm nhận của Metro.
Oliver Vogel

Các câu hỏi yêu cầu chúng tôi đề xuất hoặc tìm một cuốn sách, công cụ, thư viện phần mềm, hướng dẫn hoặc tài nguyên ngoài trang web khác ngoài chủ đề cho Stack Overflow vì chúng có xu hướng thu hút các câu trả lời và spam. Thay vào đó, hãy mô tả vấn đề và những gì đã được thực hiện cho đến nay để giải quyết nó.
Scott Solmer

Câu trả lời:


149

Những gì tôi đã làm là tạo ra Cửa sổ và Phong cách của riêng tôi. Bởi vì tôi muốn có quyền kiểm soát mọi thứ và tôi không muốn một số thư viện bên ngoài chỉ sử dụng Cửa sổ từ đó. Tôi đã xem MahApps.Metro trên GitHub đã đề cập

Ứng dụng

giao diện người dùng hiện đại rất đẹp trên GitHub . (Chỉ .NET4.5)

Giao diện người dùng hiện đại

Có một cái nữa là Elysium nhưng tôi thực sự không thử cái này.

Chốn thiên đường

Phong cách tôi đã làm thực sự dễ dàng khi tôi nhìn cách nó được thực hiện trong những điều này. Bây giờ tôi có Cửa sổ của riêng mình và tôi có thể làm bất cứ điều gì tôi muốn với xaml ... đối với tôi đó là lý do chính khiến tôi tự làm. Và tôi cũng đã làm thêm một cái cho bạn nữa :) Tôi có lẽ nên nói rằng tôi sẽ không thể làm điều đó mà không khám phá Modern UI, nó rất hữu ích. Tôi đã cố gắng để làm cho nó trông giống như Cửa sổ VS2012. Có vẻ như thế này.

Cửa sổ của tôi

Đây là mã (xin lưu ý rằng nó đang nhắm mục tiêu .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);
    }
}

Và đây là tài nguyên:

<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
Xin chào và cảm ơn bạn rất nhiều vì mã tuyệt vời này mà bạn đã đăng. Chỉ cần một ân huệ để hỏi, Có thể có một cái bóng trên cửa sổ? Điều duy nhất tôi đã tìm ra được thay đổi GlassFrameThicknessđể 1. Nhưng cái bóng quá mạnh và tối. Làm thế nào tôi có thể thay đổi trọng lượng và độ mờ của nó?
xperator


Có phải rất khó để tạo tùy chỉnh các thành phần của riêng tôi, thay vì sử dụng MahApps?
Matheus Saraiva

Tưởng tượng! Cảm ơn bạn rất nhiều vì sự đóng góp tuyệt vời này, tôi đã cố gắng làm điều tương tự nhiều lần nhưng tôi chưa bao giờ có được một kết quả hoàn hảo như vậy.
Leodev

Giả sử tôi muốn tăng độ dày của đường viền màu xanh lên trên và xóa đường viền ở tất cả các mặt khác (như pic elysium trong câu trả lời của bạn), tôi sẽ phải thay đổi điều gì? Tôi mới sử dụng wpf và do đó, câu hỏi
mrid

49

Giải pháp cuối cùng tôi chọn là MahApps.Metro ( github ), mà (sau khi sử dụng nó trên hai phần mềm bây giờ) tôi xem xét một bộ giao diện người dùng tuyệt vời (tín dụng cho Oliver Vogel cho đề xuất) .

Kiểu cửa sổ

Nó tạo ra ứng dụng với rất ít nỗ lực cần thiết và có các điều chỉnh của các điều khiển Windows 8 tiêu chuẩn. Nó rất mạnh mẽ.

Hình mờ hộp văn bản

Một phiên bản có sẵn trên Nuget:

Bạn có thể cài đặt MahApps.Metro qua Nuget bằng GUI (nhấp chuột phải vào dự án của bạn, Quản lý tham chiếu Nuget, tìm kiếm 'MahApps.Metro') hoặc qua bảng điều khiển:

PM> Cài đặt gói MahApps.Metro

Nó cũng miễn phí - ngay cả đối với mục đích thương mại.

Cập nhật 10-29-2013:

Tôi phát hiện ra rằng phiên bản Github của MahApps.Metro được đóng gói với các điều khiển và kiểu không có trong phiên bản nuget hiện tại, bao gồm:

Dữ liệu:

nhập mô tả hình ảnh ở đây

Cửa sổ sạch sẽ:

nhập mô tả hình ảnh ở đây

Bay ra:

nhập mô tả hình ảnh ở đây

Gạch:

nhập mô tả hình ảnh ở đây

Kho github hoạt động rất tích cực với khá nhiều đóng góp của người dùng. Tôi khuyên nên kiểm tra nó toàn diện.


Tôi kiểm tra nó, đẹp +1 :)
Akrem

3
cập nhật rất hay! Tôi cũng đã thử MahApps.Metro, Modern UI cho WPF và Elysium. Tôi thấy rằng Elysium rất phức tạp khi sử dụng và nhầm lẫn trên trang web của họ / Doc .. Modern UI và MahApps.Metro có trọng lượng nhẹ và dễ sử dụng, nhưng MahApps. Metro cạnh tranh hơn về kiểm soát hình thức WPF.
Cheung

Có phải rất khó để tạo tùy chỉnh các thành phần của riêng tôi, thay vì sử dụng MahApps?
Matheus Saraiva

42

Tôi muốn giới thiệu UI hiện đại cho WPF .

Nó có một người bảo trì rất tích cực, nó là tuyệt vời và miễn phí!

Giao diện người dùng hiện đại cho WPF (Ảnh chụp màn hình của ứng dụng mẫu

Tôi hiện đang chuyển một số dự án sang MUI, ấn tượng đầu tiên (và trong khi đó là thứ hai) chỉ là wow!

Để xem MUI hoạt động, bạn có thể tải xuống XAML Spy dựa trên MUI.

EDIT: Sử dụng Modern UI cho WPF một vài tháng và tôi rất thích nó!


16

Dựa trên câu trả lời của Viktor La Croix với nguồn ở trên, tôi sẽ thay đổi nó để sử dụng như sau:

Ví dụ về phông chữ Marlett

Cách tốt hơn là sử dụng phông chữ Marlett thay vì các điểm Dữ liệu đường dẫn cho các nút Thu nhỏ, Khôi phục / Tối đa hóa và Đóng.

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


Hi bay maverick. Bạn có thể giải thích tại sao nên sử dụng phông chữ marlett tốt hơn không? Tôi có ba cách triển khai khác nhau và tôi không chắc nên sử dụng cái nào. Đầu tiên là sử dụng các điểm dữ liệu đường dẫn, thứ hai là sử dụng marlett và thứ ba là giải trí các nút ở định dạng SVG. Tôi đang cố gắng sử dụng 100% thực tiễn tốt nhất trong dự án này và không chắc chắn cái nào là lựa chọn tốt nhất. Bạn có thể giải thích tại sao marlett tốt hơn?
dùng1632018

1
Xin chào user1632018 Nếu bạn muốn tạo một cửa sổ chrome tùy chỉnh trong Winform hoặc WPF, bạn nên xem phông chữ 'Marlett' có sẵn trên hệ thống của bạn. Phông chữ này chứa các glyph thực tế được sử dụng trong Windows cho các nút Thu nhỏ, Tối đa hóa, Khôi phục và Đóng. Sử dụng phông chữ này giúp dễ dàng sử dụng lại các glyph này trong cửa sổ chrome tùy chỉnh, thay vì hình ảnh tùy chỉnh thường được sử dụng. Bạn có thể xem phông chữ Marlett trong Bản đồ nhân vật Windows hoặc liên kết sau để biết thêm chi tiết: microsoft.com/typography/fonts/font.aspx?FMID=1264 Hy vọng điều này sẽ giúp ích.
FlyingMaverick

2

Nếu bạn sẵn sàng trả tiền, tôi thực sự khuyên bạn nên sử dụng Linh kiện Telerik cho WPF . Họ cung cấp phong cách / chủ đề tuyệt vời và có các chủ đề cụ thể cho cả hai, Office 2013 và Windows 8 (EDIT: và cũng là một phong cách theo chủ đề Visual Studio 2013). Tuy nhiên, việc cung cấp nhiều hơn chỉ là các kiểu trong thực tế, bạn sẽ có được một loạt các điều khiển thực sự hữu ích.

Đây là cách nó hoạt động (Ảnh chụp màn hình lấy từ các mẫu telerik):

Mẫu bảng điều khiển Telerik

Mẫu bảng điều khiển Telerik CRM

Dưới đây là các liên kết đến mẫu bảng điều khiển telerik (ảnh chụp màn hình đầu tiên) và ở đây cho Bảng điều khiển CRM (ảnh chụp màn hình thứ hai).

Họ cung cấp một thử nghiệm 30 ngày, chỉ cần cho nó một shot!


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.