Skip to main content

整合指南

本頁說明 MahApps.Metro 與其他框架、工具的整合方式。


MVVM 框架整合

搭配 CommunityToolkit.Mvvm

CommunityToolkit.Mvvm(前身 Microsoft.Toolkit.Mvvm)是目前推薦的輕量 MVVM 框架。

dotnet add package CommunityToolkit.Mvvm
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using MahApps.Metro.Controls.Dialogs;

public partial class DeviceMonitorViewModel : ObservableObject
{
private readonly IDialogCoordinator _dialogCoordinator;

[ObservableProperty]
private double _temperature;

[ObservableProperty]
private bool _isConnected;

[ObservableProperty]
private bool _isSettingsOpen;

public DeviceMonitorViewModel(IDialogCoordinator dialogCoordinator)
{
_dialogCoordinator = dialogCoordinator;
}

[RelayCommand]
private void ToggleSettings()
{
IsSettingsOpen = !IsSettingsOpen;
}

[RelayCommand]
private async Task EmergencyStop()
{
var result = await _dialogCoordinator.ShowMessageAsync(
this,
"緊急停機",
"確定要執行緊急停機?所有設備將立即停止。",
MessageDialogStyle.AffirmativeAndNegative);

if (result == MessageDialogResult.Affirmative)
{
await StopAllDevicesAsync();
}
}
}

搭配 ReactiveUI

如果專案同時使用 Rx.NET,ReactiveUI 是更好的搭配:

dotnet add package ReactiveUI.WPF
using ReactiveUI;
using ReactiveUI.Fody.Helpers;

public class DeviceViewModel : ReactiveObject
{
[Reactive]
public double Temperature { get; set; }

[Reactive]
public bool IsConnected { get; set; }

public ReactiveCommand<Unit, Unit> StopCommand { get; }

public DeviceViewModel()
{
var canStop = this.WhenAnyValue(x => x.IsConnected);

StopCommand = ReactiveCommand.CreateFromTask(
StopDeviceAsync, canStop);
}
}

MahApps.Metro.IconPacks 整合

IconPacks 提供數千個向量圖示,支援 Material Design、FontAwesome、Unicons 等多種圖示集。

安裝

# 只安裝 Material Design 圖示(推薦,檔案小)
dotnet add package MahApps.Metro.IconPacks.Material

# 或安裝全部圖示集(檔案較大)
dotnet add package MahApps.Metro.IconPacks

XAML namespace

xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"

使用

<!-- 基本圖示 -->
<iconPacks:PackIconMaterial Kind="Thermometer" Width="24" Height="24" />

<!-- 在按鈕中使用 -->
<Button Style="{StaticResource MahApps.Styles.Button.Circle}">
<iconPacks:PackIconMaterial Kind="Play" />
</Button>

<!-- 搭配文字 -->
<StackPanel Orientation="Horizontal">
<iconPacks:PackIconMaterial Kind="AlertCircle" Foreground="Red"
VerticalAlignment="Center" Margin="0,0,4,0" />
<TextBlock Text="溫度超過上限" VerticalAlignment="Center" />
</StackPanel>

常用圖示對照

場景Kind 值說明
設備連線LanConnect / LanDisconnect連線/斷線
設備運轉Play / Stop / Pause啟動/停止/暫停
溫度Thermometer溫度計
警報AlertCircle / BellRing告警
設定Cog / CogOutline齒輪
儀表板ViewDashboard面板
圖表ChartLine / ChartBar折線/長條圖
匯出FileExport / Download匯出/下載
搜尋Magnify放大鏡
重新整理Refresh重新載入

多語系支援

搭配 .resx 資源檔

<!-- 使用 x:Static 綁定資源 -->
<mah:Flyout Header="{x:Static props:Resources.DeviceSettings}" ... />

<Button Content="{x:Static props:Resources.StartDevice}" />

搭配動態語系切換

// 切換語系
public void ChangeLanguage(string cultureCode)
{
var culture = new CultureInfo(cultureCode);
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;

// 通知所有綁定更新
// 使用 CommunityToolkit.Mvvm 的 Messenger 或 EventAggregator
}

MahApps 控件的本地化

MahApps 的內建文字(如 Dialog 的 OK/Cancel)可透過 MetroDialogSettings 自訂:

var settings = new MetroDialogSettings
{
AffirmativeButtonText = "確定",
NegativeButtonText = "取消",
FirstAuxiliaryButtonText = "略過",
};

效能注意事項

大量控件時使用 VirtualizingStackPanel

<!-- DataGrid 預設就有虛擬化,但要確認沒有關掉 -->
<DataGrid VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.VirtualizationMode="Recycling"
EnableRowVirtualization="True"
EnableColumnVirtualization="True" />

<!-- ListBox/ItemsControl 加上虛擬化 -->
<ListBox VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.VirtualizationMode="Recycling"
ScrollViewer.CanContentScroll="True">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>

減少 ResourceDictionary 載入

只載入需要的資源,不要載入全部:

<!-- ✅ 只載入需要的 -->
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />

<!-- ❌ 不要額外載入不需要的主題 -->
<!-- 只載入一個主題就好,不要全部載入 -->

Flyout 的 CloseButtonVisibility

大量 Flyout 時,設定 CloseButtonVisibility="Collapsed" 減少不必要的元素:

<mah:Flyout CloseButtonVisibility="Collapsed"
IsPinned="False"
ExternalCloseButton="Left" />

避免過多動畫

在嵌入式或低規格工控機上,動畫可能影響效能:

<!-- 關閉特定轉場動畫 -->
<mah:MetroWindow
mah:MetroWindow.IsCloseButtonEnabled="True"
WindowTransitionsEnabled="False">

與 ComponentOne 共存

公司專案可能同時使用 MahApps.Metro 和 ComponentOne (C1.WPF)。兩者的樣式可能衝突。

解法:明確指定控件樣式

<!-- 確保 C1 FlexGrid 不受 MahApps 影響 -->
<c1:C1FlexGrid Style="{x:Null}" ... />

<!-- 對於標準控件,明確使用 MahApps 樣式 -->
<Button Style="{StaticResource MahApps.Styles.Button}" />

載入順序

在 App.xaml 中,MahApps 資源放前面,C1 資源放後面:

<ResourceDictionary.MergedDictionaries>
<!-- 1. MahApps -->
<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/Dark.Blue.xaml" />

<!-- 2. ComponentOne(後載入覆蓋衝突) -->
<ResourceDictionary Source="/C1Themes;component/MetroDark.xaml" />

<!-- 3. 自訂覆寫(最後載入,最高優先) -->
<ResourceDictionary Source="Styles/CustomOverrides.xaml" />
</ResourceDictionary.MergedDictionaries>

延伸閱讀