开源C# WPF控件库:MahApps.Metro 介绍
MahApps.Metro 项目仓库:Here
个人调试仓库:GitHub
根据仓库例子,采用Prism的MvvM框架手动coding过一遍:
1 下载相应Nuget包
<ProjectSdk="Microsoft.NET.Sdk"><PropertyGroup><OutputType>WinExe</OutputType><TargetFramework>net6.0-windows</TargetFramework><UseWPF>true</UseWPF></PropertyGroup><ItemGroup><PackageReferenceInclude="MahApps.Metro"Version="2.4.10"/><PackageReferenceInclude="MahApps.Metro.IconPacks"Version="4.11.0"/><PackageReferenceInclude="Prism.Unity"Version="8.1.97"/></ItemGroup></Project>
2 App.xaml
<prism:PrismApplication x:Class="PlayWithMahApps.MetroForWork.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PlayWithMahApps.MetroForWork"
xmlns:prism="http://prismlibrary.com/" >
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/Light.Blue.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</prism:PrismApplication>
using Prism.Ioc;
using Prism.Regions;
using SelectNeidTool.Views;
using SelectNiedTool.Views;
using System.Windows;
namespace SelectNiedTool
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App
{
protected override Window CreateShell()
{
var window = Container.Resolve<MainWindow>();
//window.Loaded += (sender, args) =>
//{
// var manager = this.Container.Resolve<IRegionManager>();
// manager.RequestNavigate("ContentRegion", "DRWindows");
//};
return window;
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterForNavigation<DRWindows>();
containerRegistry.RegisterForNavigation<NRWindows>();
}
}
}
3 MainWindow.xaml
<mah:MetroWindow x:Class="PlayWithMahApps.MetroForWork.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
xmlns:local="clr-namespace:SelectNeidTool.Views"
Width="1024"
Height="768"
MinWidth="800"
MinHeight="600"
Title="{Binding Title}">
<Window.Resources>
<ResourceDictionary>
<Ellipse x:Key="AppThemeMenuIcon"
Width="16"
Height="16"
x:Shared="False"
Fill="{Binding ColorBrush, Mode=OneWay}"
Stroke="{Binding BorderColorBrush, Mode=OneWay}"
StrokeThickness="1" />
<Ellipse x:Key="AccentMenuIcon"
Width="16"
Height="16"
x:Shared="False"
Fill="{Binding ColorBrush, Mode=OneWay}" />
<Style x:Key="AppThemeMenuItemStyle"
BasedOn="{StaticResource MahApps.Styles.MenuItem}"
TargetType="{x:Type MenuItem}">
<Setter Property="Command" Value="{Binding ChangeAccentCommand}" />
<Setter Property="CommandParameter" Value="{Binding Name, Mode=OneWay}" />
<Setter Property="Header" Value="{Binding Name, Mode=OneWay}" />
<Setter Property="Icon" Value="{StaticResource AppThemeMenuIcon}" />
</Style>
<Style x:Key="AccentColorMenuItemStyle"
BasedOn="{StaticResource MahApps.Styles.MenuItem}"
TargetType="{x:Type MenuItem}">
<Setter Property="Command" Value="{Binding ChangeAccentCommand}" />
<Setter Property="CommandParameter" Value="{Binding Name, Mode=OneWay}" />
<Setter Property="Header" Value="{Binding Name, Mode=OneWay}" />
<Setter Property="Icon" Value="{StaticResource AccentMenuIcon}" />
</Style>
<!-- This is the template for the option menu item -->
<DataTemplate x:Key="HamburgerOptionsMenuItem" DataType="{x:Type mah:HamburgerMenuIconItem}">
<DockPanel Height="48" LastChildFill="True">
<ContentControl x:Name="IconPart"
Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type mah:HamburgerMenu}}, Path=CompactPaneLength}"
Content="{Binding Icon}"
DockPanel.Dock="Left"
Focusable="False"
IsTabStop="False" />
<TextBlock x:Name="TextPart"
VerticalAlignment="Center"
FontSize="16"
Text="{Binding Label}" />
</DockPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type mah:HamburgerMenu}}, Path=PanePlacement}" Value="Right">
<Setter TargetName="IconPart" Property="DockPanel.Dock" Value="Right" />
<Setter TargetName="TextPart" Property="Margin" Value="8 0 0 0" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ResourceDictionary>
</Window.Resources>
<!--How to set window icon from iconpack-->
<!--use the IconTemplate property to set a custom Icon at the title bar.-->
<!--https://github.com/MahApps/MahApps.Metro/issues/3464-->
<mah:MetroWindow.IconTemplate>
<DataTemplate>
<iconPacks:PackIconMaterial Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
Margin="4"
Foreground="{DynamicResource IdealForegroundColorBrush}"
Kind="TransmissionTower" />
</DataTemplate>
</mah:MetroWindow.IconTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Menu Grid.Row="0"
Margin="5"
HorizontalAlignment="Left"
VerticalAlignment="Stretch">
<MenuItem Header="Theme"
ItemContainerStyle="{StaticResource AppThemeMenuItemStyle}"
ItemsSource="{Binding AppThemes, Mode=OneWay}" />
<MenuItem Header="Accent"
ItemContainerStyle="{StaticResource AccentColorMenuItemStyle}"
ItemsSource="{Binding AccentColors, Mode=OneWay}" />
</Menu>
<Border Grid.Row="1"
BorderBrush="{DynamicResource MahApps.Brushes.Gray7}"
BorderThickness="1">
<mah:HamburgerMenu x:Name="HamburgerMenuControl"
DisplayMode="CompactOverlay"
HamburgerWidth="48"
IsPaneOpen="{Binding IsHamburgerMenuPaneOpen}"
ItemTemplate="{StaticResource HamburgerOptionsMenuItem}"
SelectedIndex="0"
VerticalScrollBarOnLeftSide="False">
<!-- Items -->
<mah:HamburgerMenu.ItemsSource>
<mah:HamburgerMenuItemCollection>
<mah:HamburgerMenuIconItem x:Name="AboutOption"
Command="{Binding DRCommand}"
Label="LTE_DRAN">
<mah:HamburgerMenuIconItem.Icon>
<iconPacks:PackIconMaterial Width="22"
Height="22"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Kind="Signal4g" />
</mah:HamburgerMenuIconItem.Icon>
</mah:HamburgerMenuIconItem>
<mah:HamburgerMenuIconItem x:Name="AboutOption2"
Command="{Binding NRCommand}"
Label="NR">
<mah:HamburgerMenuIconItem.Icon>
<!-- iconPacks need to be downloaded through Nuget, and icon by kind property-->
<iconPacks:PackIconMaterial Width="22"
Height="22"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Kind="Signal5g" />
</mah:HamburgerMenuIconItem.Icon>
</mah:HamburgerMenuIconItem>
<mah:HamburgerMenuIconItem x:Name="AboutOption3"
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=mah:HamburgerMenu}, Path=DataContext.ShowHamburgerAboutCommand}"
Label="ToolBox">
<mah:HamburgerMenuIconItem.Icon>
<iconPacks:PackIconMaterial Width="22"
Height="22"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Kind="Tools"/>
</mah:HamburgerMenuIconItem.Icon>
</mah:HamburgerMenuIconItem>
</mah:HamburgerMenuItemCollection>
</mah:HamburgerMenu.ItemsSource>
<!--Refer to https://elf-mission.net/programming/wpf/ui-gallery/case01-01/-->
<!--Refer to https://yutampo-blog.com/12-opencv%E3%81%A7%E7%94%BB%E5%83%8F%E5%87%A6%E7%90%86%E3%82%A2%E3%83%97%E3%83%AA%E3%82%92%E4%BD%9C%E3%82%8D%E3%81%86hambergermenu2/-->
<mah:HamburgerMenu.Content>
<mah:TransitioningContentControl x:Name="ContentRegion"
prism:RegionManager.RegionName="ContentRegion"
Transition="RightReplace"/>
</mah:HamburgerMenu.Content>
</mah:HamburgerMenu>
</Border>
</Grid>
</mah:MetroWindow>
MainWindow.xaml.cs
using System.Windows;
using MahApps.Metro.Controls;
using Prism.Regions;
namespace SelectNiedTool.Views
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : MetroWindow
{
public MainWindow()
{
InitializeComponent();
/* HamburgerMenu.Content 上に配置したコントロールは遅延作成されるらしく、
* Prism の RegionManager は遅延作成された Region を認識できないため RequestNavigate が認識されない
* これを回避するには Region を手動で RegionManager に登録する必要があるようなので、MainWindow のコードビハインドに 上記の処理を追加します。*/
RegionManager.SetRegionName(this.ContentRegion, "ContentRegion");
var regionMan = (IRegionManager)Prism.Ioc.ContainerLocator.Container.Resolve(typeof(IRegionManager));
RegionManager.SetRegionManager(ContentRegion, regionMan);
}
private void HamburgerMenuControl_OnItemInvoked(object sender, HamburgerMenuItemInvokedEventArgs e)
{
this.HamburgerMenuControl.Content = e.InvokedItem;
if (!e.IsItemOptions && this.HamburgerMenuControl.IsPaneOpen)
{
// close the menu if a item was selected
this.HamburgerMenuControl.IsPaneOpen = false;
}
}
}
}
4 DRWindows.xaml
<UserControl x:Class="PlayWithMahApps.MetroForWork.Views.DRWindows"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:SelectNeidTool.Views"
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
mc:Ignorable="d"
d:DesignHeight="600" d:DesignWidth="800">
<UserControl.Resources>
<Thickness x:Key="ControlMargin">5 5 5 5</Thickness>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel Grid.Column="0">
<mah:MetroHeader Header="{Binding InputTitle}" Margin="{StaticResource ControlMargin}">
<TextBox Text="{Binding InputPath, Mode=TwoWay}" />
</mah:MetroHeader>
<Button Width="110"
Margin="{StaticResource ControlMargin}"
Content="Diagnose"
Command="{Binding DiagnoseCommand}"
Style="{DynamicResource MahApps.Styles.Button.Square}" />
<Button Width="110"
Margin="{StaticResource ControlMargin}"
Content="Check"
Style="{DynamicResource MahApps.Styles.Button.Square.Highlight}" />
<Button Width="110"
Margin="{StaticResource ControlMargin}"
Content="Test"
Style="{DynamicResource MahApps.Styles.Button.Square.Highlight}" />
</StackPanel>
<StackPanel Grid.Row="0"
Grid.Column="1"
HorizontalAlignment="Center"
UseLayoutRounding="True">
<StackPanel>
<StackPanel.Resources>
<Style BasedOn="{StaticResource MahApps.Styles.CheckBox.Win10}" TargetType="{x:Type CheckBox}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type CheckBox}}, Path=IsChecked, TargetNullValue='IsChecked = Null', Mode=OneWay, StringFormat='{}IsChecked = {0}'}" />
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="Margin" Value="{StaticResource ControlMargin}" />
</Style>
</StackPanel.Resources>
<Label Content="Select BandWidth" Style="{DynamicResource DescriptionHeaderStyle}" />
<CheckBox mah:CheckBoxHelper.CheckCornerRadius="2"
IsChecked="False"
IsEnabled="True" />
<CheckBox mah:CheckBoxHelper.CheckCornerRadius="2"
IsChecked="False"
IsEnabled="True" />
<CheckBox mah:CheckBoxHelper.CheckCornerRadius="2"
IsChecked="False"
IsEnabled="True" />
<CheckBox mah:CheckBoxHelper.CheckCornerRadius="2"
IsChecked="False"
IsEnabled="True" />
<CheckBox mah:CheckBoxHelper.CheckCornerRadius="2"
IsChecked="False"
IsEnabled="True" />
</StackPanel>
</StackPanel>
<RichTextBox Grid.Row="0"
Grid.RowSpan="3"
Grid.Column="2"
Grid.ColumnSpan="3"
Margin="{StaticResource ControlMargin}"
mah:TextBoxHelper.SelectAllOnFocus="True"
IsDocumentEnabled="True"
SpellCheck.IsEnabled="True">
<FlowDocument>
<Paragraph>
<Run>Log Begin</Run>
<LineBreak />
<Run Text="{Binding Log}" />
<LineBreak />
<Run>Log Over</Run>
</Paragraph>
</FlowDocument>
</RichTextBox>
</Grid>
</UserControl>
5 MainWindowViewModel.cs
using ControlzEx.Theming;
using Prism.Commands;
using Prism.Mvvm;
using Prism.Regions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
namespace PlayWithMahApps.ViewModels
{
public class MainWindowViewModel : BindableBase
{
private string _title = "Prism Application";
public string Title
{
get { return _title; }
set { SetProperty(ref _title, value); }
}
public List<AppThemeMenuData> AppThemes { get; set; }
public List<AccentColorMenuData> AccentColors { get; set; }
public MainWindowViewModel(IRegionManager regionManager)
{
// create metro theme color menu items for the demo
this.AppThemes = ThemeManager.Current.Themes
.GroupBy(x => x.BaseColorScheme)
.Select(x => x.First())
.Select(a => new AppThemeMenuData { Name = a.BaseColorScheme, BorderColorBrush = a.Resources["MahApps.Brushes.ThemeForeground"] as Brush, ColorBrush = a.Resources["MahApps.Brushes.ThemeBackground"] as Brush })
.ToList();
// create accent color menu items for the demo
this.AccentColors = ThemeManager.Current.Themes
.GroupBy(x => x.ColorScheme)
.OrderBy(a => a.Key)
.Select(a => new AccentColorMenuData { Name = a.Key, ColorBrush = a.First().ShowcaseBrush })
.ToList();
this._regionManager = regionManager;
DRCommand = new DelegateCommand(DRNavigation);
NRCommand = new DelegateCommand(NRNavigation);
//Initialize the default region view
//Refer to https://stackoverflow.com/questions/54330435/navigate-to-a-default-view-when-application-loaded-using-prism-7-in-wpf
regionManager.RegisterViewWithRegion("ContentRegion", "DRWindows");
}
private DelegateCommand _fieldName;
public DelegateCommand CommandName =>
_fieldName ?? (_fieldName = new DelegateCommand(ExecuteCommandName));
void ExecuteCommandName()
{
return;
}
#region Region Navigation
//XAML中定义了RegionManager,ViewModel里可以接收这个RegionManager
//RegionManager顾名思义,管理Region
private readonly IRegionManager _regionManager;
public DelegateCommand DRCommand { get; private set; }
public DelegateCommand NRCommand { get; private set; }
void DRNavigation()
{
if (_regionManager != null)
{
//注意,方法与Region注册不同,是Navigate关联的方法
_regionManager.RequestNavigate("ContentRegion", "DRWindows");
}
}
void NRNavigation()
{
if (_regionManager != null)
{
_regionManager.RequestNavigate("ContentRegion", "NRWindows");
}
}
#endregion
}
public class AppThemeMenuData : AccentColorMenuData
{
protected override void DoChangeTheme(string? name)
{
if (name is not null)
{
ThemeManager.Current.ChangeThemeBaseColor(Application.Current, name);
}
}
}
public class AccentColorMenuData
{
public string? Name { get; set; }
public Brush? BorderColorBrush { get; set; }
public Brush? ColorBrush { get; set; }
public AccentColorMenuData()
{
//Update SimpleCommand with DelegateCommand
// this.ChangeAccentCommand = new SimpleCommand<string?>(o => true, this.DoChangeTheme);
this.ChangeAccentCommand = new DelegateCommand<string>(ExecuteChangeACommand, CanExecuteChangeACommand);
}
void ExecuteChangeACommand(string name)
{
this.DoChangeTheme(name);
}
bool CanExecuteChangeACommand(string name)
{
return true;
}
public ICommand ChangeAccentCommand { get; }
protected virtual void DoChangeTheme(string? name)
{
if (name is not null)
{
ThemeManager.Current.ChangeThemeColorScheme(Application.Current, name);
}
}
}
}
6 DRWindowsViewModel.cs
using Microsoft.WindowsAPICodePack.Dialogs;
using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PlayWithMahApps.ViewModels
{
class DRWindowsViewModel : BindableBase
{
/// <summary>
/// Property for log
/// </summary>
private string _log = @"";
public string Log
{
get { return _log; }
set { SetProperty(ref _log, value + Environment.NewLine); }
}
/// <summary>
/// Input file Label
/// </summary>
private string _inputTitle = "File Path";
public string InputTitle
{
get { return _inputTitle; }
set { SetProperty(ref _inputTitle, value); }
}
/// <summary>
/// Input file path
/// </summary>
private string _inputPath = "Please input file";
public string InputPath
{
get { return _inputPath; }
set { SetProperty(ref _inputPath, value); }
}
/// <summary>
/// Select file path and Diagnose
/// </summary>
private DelegateCommand _diagnose;
public DelegateCommand DiagnoseCommand =>
_diagnose ?? (_diagnose = new DelegateCommand(ExecuteDiagnoseCommand));
void ExecuteDiagnoseCommand()
{
//Please install WindowsAPICodePack-Shell in Nuget
using (var cofd = new CommonOpenFileDialog()
{
Title = "Please Select File",
InitialDirectory = @"C:",
IsFolderPicker = true,
})
{
if (cofd.ShowDialog() != CommonFileDialogResult.Ok)
{
return;
}
this.InputPath = cofd.FileName;
System.Windows.MessageBox.Show($"{cofd.FileName} is Selected");
}
for(int i = 0; i < 2000; i++)
{
Log += $"Test: {i}";
}
}
}
}
本文转载自: https://blog.csdn.net/watershed1993/article/details/134967223
版权归原作者 watershed1993 所有, 如有侵权,请联系我们删除。
版权归原作者 watershed1993 所有, 如有侵权,请联系我们删除。