Rendere le applicazioni WPF in stile Metro, anche in Windows 7? (Finestra Chrome / Temi / Tema)


123

Mi piace il cromo della finestra sulla nuova suite Office e Visual Studio:

inserisci qui la descrizione dell'immagine

Ovviamente sto ancora sviluppando applicazioni per Windows 7, ma mi chiedo se esiste un modo semplice e veloce (leggi: stile WPF o libreria di Windows) per emulare questo stile. In passato ho eseguito alcuni stili di cromature per finestre, ma far sì che appaia e si comporti nel modo giusto è davvero complicato.

Qualcuno sa se esistono modelli o librerie esistenti per aggiungere un aspetto "Modern UI" alle mie applicazioni WPF?


8
Questa guida / pacchetto NuGet potrebbe essere utile: MahaApps Metro Contiene un set di stili e controlli per creare app WPF con l'aspetto di Metro.
Oliver Vogel

Le domande che ci chiedono di consigliare o trovare un libro, uno strumento, una libreria software, un tutorial o un'altra risorsa esterna al sito sono fuori tema per Stack Overflow in quanto tendono ad attirare risposte supponenti e spam. Descrivi invece il problema e cosa è stato fatto finora per risolverlo.
Scott Solmer

Risposte:


149

Quello che ho fatto è stato creare la mia finestra e il mio stile. Perché mi piace avere il controllo su tutto e non volevo che alcune librerie esterne usassero solo una finestra da essa. Ho visto MahApps.Metro già menzionato su GitHub

MahApps

e anche un'interfaccia utente moderna molto bella su GitHub . (Solo .NET4.5)

Interfaccia utente moderna

Ce n'è uno in più è Elysium ma davvero non l'ho provato.

Campi Elisi

Lo stile che ho fatto è stato davvero semplice quando ho visto come è fatto in questi. Ora ho la mia finestra e posso fare quello che voglio con xaml ... per me è il motivo principale per cui ho fatto il mio. E ne ho fatto un altro anche per te :) Probabilmente dovrei dire che non sarei in grado di farlo senza esplorare Modern UI, è stato di grande aiuto. Ho provato a farlo sembrare come VS2012 Window. Sembra questo.

MyWindow

Ecco il codice (tieni presente che ha come target .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);
    }
}

E qui le risorse:

<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
Ciao e grazie mille per questo fantastico codice che hai pubblicato. Solo un favore da chiedere, è possibile avere un'ombra sulla finestra? L'unica cosa che ho capito sta cambiando GlassFrameThicknessa 1. Ma l'ombra è troppo forte e scura. Come posso modificarne il peso e l'opacità?
xperator


È molto difficile creare la mia personalizzazione dei componenti, invece di utilizzare MahApps?
Matheus Saraiva

Fantastico! Grazie mille per questo eccellente contributo, avevo provato a fare la stessa cosa molte volte ma non ho mai ottenuto un risultato così perfetto.
Leodev

Supponiamo che io voglia aumentare lo spessore del bordo blu in alto e rimuovere il bordo su tutti gli altri lati (come la foto di elysium nella tua risposta), cosa dovrei cambiare? Sono nuovo di wpf, e da qui la domanda
mrid

49

La soluzione che ho finito per scegliere è stata MahApps.Metro ( github ), che (dopo averlo usato su due software ora) considero un eccellente kit di interfaccia utente (merito di Oliver Vogel per il suggerimento) .

Stile della finestra

Esegue la skin dell'applicazione con uno sforzo minimo richiesto e ha adattamenti dei controlli standard di Windows 8. È molto robusto.

Filigrana della casella di testo

Una versione è disponibile su Nuget:

Puoi installare MahApps.Metro tramite Nuget usando la GUI (fai clic con il tasto destro sul tuo progetto, Gestisci riferimenti Nuget, cerca 'MahApps.Metro') o tramite la console:

PM> Install-Package MahApps.Metro

È anche gratuito , anche per uso commerciale.

Aggiornamento 10-29-2013:

Ho scoperto che la versione Github di MahApps.Metro è ricca di controlli e stili che non sono disponibili nell'attuale versione di nuget, tra cui:

DataGrid:

inserisci qui la descrizione dell'immagine

Finestra pulita:

inserisci qui la descrizione dell'immagine

flyout:

inserisci qui la descrizione dell'immagine

piastrelle:

inserisci qui la descrizione dell'immagine

Il repository github è molto attivo con un bel po 'di contributi degli utenti. Consiglio di controllarlo.


Lo provo, bel +1 :)
Akrem

3
aggiornamento molto bello! Provo anche MahApps.Metro, Modern UI per WPF ed Elysium. Ho scoperto che Elysium è così complicato da usare e confondere sul loro sito web / Doc .. Modern UI e MahApps.Metro è leggero e facile da usare, ma MahApps. Metro più competitivo sui controlli del modulo WPF.
Cheung

È molto difficile creare la mia personalizzazione dei componenti, invece di utilizzare MahApps?
Matheus Saraiva

42

consiglierei Modern UI per WPF .

Ha un manutentore molto attivo, è fantastico e gratuito!

Modern UI for WPF (Screenshot dell'applicazione di esempio

Al momento sto portando alcuni progetti su MUI, la prima (e nel frattempo la seconda) impressione è semplicemente wow!

Per vedere MUI in azione puoi scaricare XAML Spy che si basa su MUI.

EDIT: utilizzo dell'interfaccia utente moderna per WPF alcuni mesi e lo adoro!


16

Sulla base della risposta di Viktor La Croix con la fonte sopra, lo cambierei per usare quanto segue:

Esempio di carattere Marlett

È una pratica migliore usare il carattere Marlett piuttosto che i punti dati del percorso per i pulsanti Riduci a icona, Ripristina / Ingrandisci e Chiudi.

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


Ciao Flying maverick. Saresti in grado di spiegare perché è una pratica migliore utilizzare il carattere marlett? Ho tre diverse implementazioni e non sono sicuro di quale usare. Il primo utilizza i punti dati del percorso, il secondo utilizza marlett e il terzo è una ricreazione dei pulsanti in formato SVG. Sto cercando di utilizzare le migliori pratiche al 100% in questo progetto e non sono sicuro di quale sia l'opzione migliore. Puoi spiegare perché Marlett è migliore?
user1632018

1
Ciao utente1632018 Se stai cercando di creare una finestra chrome personalizzata in Winform o WPF, dovresti dare un'occhiata al carattere "Marlett" disponibile sul tuo sistema. Questo carattere contiene i glifi effettivi utilizzati in Windows per i pulsanti Riduci a icona, Ingrandisci, Ripristina e Chiudi. L'utilizzo di questo tipo di carattere semplifica il riutilizzo di questi glifi in una finestra di Chrome personalizzata, invece delle immagini personalizzate utilizzate in genere. Puoi dare un'occhiata al carattere Marlett nella mappa dei caratteri di Windows o al seguente link per maggiori dettagli: microsoft.com/typography/fonts/font.aspx?FMID=1264 Spero che questo ti aiuti.
FlyingMaverick

2

Se sei disposto a pagare, ti consiglio caldamente Telerik Components per WPF . Offrono stili / temi fantastici e hanno temi specifici per entrambi, Office 2013 e Windows 8 (EDIT: e anche uno stile a tema di Visual Studio 2013). Tuttavia, offrendo molto di più che semplici stili, otterrai un sacco di controlli che sono davvero utili.

Ecco come appare in azione (screenshot tratti da campioni di telerik):

Telerik Dashboard Sample

Esempio di dashboard di Telerik CRM

Di seguito sono riportati i collegamenti all'esempio di dashboard esecutivo di telerik (primo screenshot) e qui per il dashboard CRM (secondo screenshot).

Offrono una prova di 30 giorni, provaci!


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.