Membuat aplikasi WPF terlihat bergaya Metro, bahkan di Windows 7? (Jendela Chrome / Tema / Tema)

123

Saya suka jendela chrome di Office Suite dan Visual Studio baru:

masukkan deskripsi gambar di sini

Saya masih mengembangkan aplikasi untuk Windows 7 tentunya, tapi saya bertanya-tanya apakah ada cara yang cepat dan mudah (baca: gaya WPF atau Perpustakaan Windows) untuk meniru gaya ini. Saya telah melakukan beberapa gaya krom jendela di masa lalu, tetapi membuatnya terlihat dan berperilaku tepat sangat sulit.

Adakah yang tahu jika ada templat atau pustaka yang ada untuk menambahkan tampilan dan nuansa "UI Modern" ke aplikasi WPF saya?

Daniel
sumber
8
Panduan / Paket NuGet ini mungkin berguna: MahaApps Metro Berisi serangkaian gaya dan kontrol untuk membuat Aplikasi WPF dengan Tampilan dan nuansa Metro.
Oliver Vogel
Pertanyaan yang meminta kami untuk merekomendasikan atau menemukan buku, alat, perpustakaan perangkat lunak, tutorial, atau sumber daya di luar situs lainnya berada di luar topik untuk Stack Overflow karena mereka cenderung menarik jawaban yang memiliki opini dan spam. Sebaliknya, gambarkan masalahnya dan apa yang telah dilakukan sejauh ini untuk menyelesaikannya.
Scott Solmer

Jawaban:

149

Apa yang saya lakukan adalah membuat Jendela dan Gaya saya sendiri. Karena saya suka memiliki kendali atas segalanya dan saya tidak ingin beberapa perpustakaan eksternal hanya menggunakan Window darinya. Saya melihat MahApps.Metro yang sudah disebutkan di GitHub

MahApps

dan juga UI Modern yang sangat bagus di GitHub . (.NET4.5 saja)

UI modern

Ada satu lagi Elysium tapi saya benar-benar tidak mencobanya.

Elysium

Gaya yang saya lakukan sangat mudah ketika saya melihat bagaimana melakukannya dengan ini. Sekarang saya memiliki Window sendiri dan saya dapat melakukan apapun yang saya inginkan dengan xaml ... bagi saya itu adalah alasan utama mengapa saya melakukannya sendiri. Dan saya membuat satu lagi untuk Anda juga :) Saya mungkin harus mengatakan bahwa saya tidak akan dapat melakukannya tanpa menjelajah UI Modern. Ini sangat membantu. Saya mencoba membuatnya terlihat seperti VS2012 Window. Ini terlihat seperti ini.

MyWindow

Ini kodenya (harap diperhatikan bahwa ini menargetkan .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);
    }
}

Dan di sini sumber:

<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>
Kapitán Mlíko
sumber
1
Hai dan Terima kasih banyak atas kode bagus yang Anda posting ini. Hanya permintaan untuk bertanya, Apakah mungkin memiliki bayangan di jendela? Satu-satunya hal yang saya pikirkan adalah berubah GlassFrameThicknessmenjadi 1. Tapi bayangannya terlalu kuat dan gelap. Bagaimana cara mengubah bobot dan opasitasnya?
xperator
Apakah sangat sulit membuat kustomisasi komponen sendiri daripada menggunakan MahApps?
Matheus Saraiva
Fantástico! Terima kasih banyak atas kontribusi luar biasa ini, saya telah mencoba melakukan hal yang sama berkali-kali tetapi saya tidak pernah mendapatkan hasil yang sempurna.
Leodev
Misalkan saya ingin menambah ketebalan bingkai biru di atas, dan menghapus bingkai di semua sisi lainnya (seperti gambar elysium dalam jawaban Anda), apa yang harus saya ubah? Saya baru
mengenal
49

Solusi yang akhirnya saya pilih adalah MahApps.Metro ( github ), yang (setelah menggunakannya pada dua perangkat lunak sekarang) saya anggap sebagai kit UI yang sangat baik (kredit kepada Oliver Vogel untuk sarannya) .

Gaya jendela

Itu skins aplikasi dengan sedikit usaha yang diperlukan, dan memiliki adaptasi dari kontrol Windows 8 standar. Ini sangat kuat.

Watermark kotak teks

Versi A tersedia di Nuget:

Anda dapat menginstal MahApps.Metro melalui Nuget menggunakan GUI (klik kanan pada proyek Anda, Kelola Referensi Nuget, cari 'MahApps.Metro') atau melalui konsol:

PM> Instal-Paket MahApps.Metro

Itu juga gratis - bahkan untuk penggunaan komersial.

Perbarui 10-29-2013:

Saya menemukan bahwa MahApps.Metro versi Github dikemas dengan kontrol dan gaya yang tidak tersedia dalam versi nuget saat ini, termasuk:

Datagrid:

masukkan deskripsi gambar di sini

Jendela Bersih:

masukkan deskripsi gambar di sini

Flyout:

masukkan deskripsi gambar di sini

Ubin:

masukkan deskripsi gambar di sini

Repositori github sangat aktif dengan kontribusi pengguna yang cukup banyak. Saya sarankan untuk memeriksanya.

Daniel
sumber
Saya mengujinya, bagus +1 :)
Akrem
3
pembaruan yang sangat bagus! Saya juga mencoba MahApps.Metro, UI Modern untuk WPF dan Elysium. Saya menemukan bahwa Elysium sangat rumit untuk digunakan dan membingungkan di situs web mereka / Dok .. UI dan MahApps.Metro modern ringan dan mudah digunakan, tetapi MahApps. Metro lebih kompetitif pada kontrol bentuk WPF.
Cheung
Apakah sangat sulit membuat kustomisasi komponen sendiri daripada menggunakan MahApps?
Matheus Saraiva
42

saya akan merekomendasikan UI Modern untuk WPF .

Ini memiliki pengelola yang sangat aktif, itu luar biasa dan gratis!

UI modern untuk WPF (Screenshot dari aplikasi sampel

Saat ini saya memindahkan beberapa proyek ke MUI, kesan pertama (dan sementara itu kedua) hanya wow!

Untuk melihat MUI beraksi, Anda dapat mengunduh XAML Spy yang berbasis MUI.

EDIT: Menggunakan UI Modern untuk WPF beberapa bulan dan saya menyukainya!

Joel
sumber
16

Berdasarkan jawaban Viktor La Croix dengan sumber di atas, saya akan mengubahnya menggunakan yang berikut:

Contoh Font Marlett

Ini adalah praktik yang lebih baik untuk menggunakan font Marlett daripada titik Data Jalur untuk tombol Minimalkan, Pulihkan / Maksimalkan dan Tutup.

<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
sumber
Hai Maverick terbang. Bisakah Anda menjelaskan mengapa praktik yang lebih baik menggunakan font marlett? Saya memiliki tiga implementasi yang berbeda, dan saya tidak yakin mana yang akan digunakan. Yang pertama menggunakan titik data jalur, yang kedua menggunakan marlett dan yang ketiga adalah rekreasi tombol dalam format SVG. Saya mencoba menggunakan 100% praktik terbaik dalam proyek ini dan tidak yakin mana yang merupakan opsi terbaik. Bisakah Anda menjelaskan mengapa marlett lebih baik?
pengguna1632018
1
Hai user1632018 Jika Anda ingin membuat jendela chrome kustom di Winform atau WPF, Anda harus melihat font 'Marlett' yang tersedia di sistem Anda. Font ini berisi mesin terbang aktual yang digunakan di Windows untuk tombol Perkecil, Maksimalkan, Pulihkan, dan Tutup. Menggunakan font ini membuatnya sangat mudah untuk menggunakan kembali mesin terbang ini di jendela chrome kustom, bukan gambar kustom yang biasanya digunakan. Anda dapat melihat font Marlett di Windows Character Map atau tautan berikut untuk lebih jelasnya: microsoft.com/typography/fonts/font.aspx?FMID=1264 Semoga ini bisa membantu.
FlyingMaverick
2

Jika Anda bersedia membayar, saya sangat menyarankan Anda Komponen Telerik untuk WPF . Mereka menawarkan gaya / tema yang bagus dan ada tema khusus untuk keduanya, Office 2013 dan Windows 8 (EDIT: dan juga gaya bertema Visual Studio 2013). Namun ada menawarkan lebih dari sekedar gaya sebenarnya Anda akan mendapatkan sejumlah besar kontrol yang sangat berguna.

Berikut ini tampilannya (Screenshot diambil dari sampel telerik):

Contoh Dasbor Telerik

Contoh Dashboard CRM Telerik

Berikut adalah tautan ke sampel dasbor eksekutif telerik (tangkapan layar pertama) dan di sini untuk Dasbor CRM (tangkapan layar kedua).

Mereka menawarkan uji coba 30 hari, coba saja!

Joel
sumber
0

Lihatlah jendela bergaya metro WPF ini dengan tepi bercahaya opsional .

Ini adalah aplikasi yang berdiri sendiri yang tidak menggunakan perpustakaan lain selain Microsoft.Windows.Shell (disertakan) untuk membuat jendela bergaya metro dengan batas bercahaya opsional.

Mendukung Windows sepenuhnya ke XP (.NET4).

Laila
sumber