ComponentOne (C1.WPF) 使用指南
本文件說明 GST 專案中 ComponentOne WPF 元件的使用模式、效能最佳化與主題整合。 適用於 ProcessVision 和 Jope-PLC-Monitor。
整合流程總覽
從新專案第一次引入 C1.WPF 到畫面能看到控件,要經過 安裝 → 授權 → 引入 ResourceDictionary → XAML 使用 → Runtime 驗證 → 渲染 六個步驟。下圖同時把「授權驗證失敗 (license 過期 / 未涵蓋部署環境)」的 fallback 路徑畫出來:
各步驟對照:
| 步驟 | 動作 | 常見陷阱 |
|---|---|---|
| 1 | dotnet add package C1.WPF.Core 等主套件(見 §1 清單) | 版本要跟 C1.WPF.Core 一致,不可混搭不同主版本 |
| 2 | 加入 licenses.licx 並讓公司授權檔參與 build(LicenseCompiler) | NuGet 包自帶 evaluation watermark;正式部署必須靠 licenses.licx 與實際授權檔完成 compile-time license embedding |
| 3 | 在 App.xaml 以 MergedDictionaries 引入 C1.WPF.Themes.Material.xaml 或 Dark 變體,並在頁面加 xmlns:c1="http://schemas.componentone.com/winfx/2006/xaml" | 多個 MergedDictionaries 順序會影響樣式覆寫 |
| 4 | 直接寫 <c1:FlexChart ...> / <c1:FlexGrid ...> 等控件 | 複雜控件(如 FlexChart Series)建議在 Code-behind 動態建構(見 §2.2) |
| 5 | dotnet run / 部署到目標機台 | Release build 不會印授權錯誤到 Console,必須看 Output 或捕捉 LicenseException |
| 6a | C1License 驗證通過,控件正常 render | — |
| 6b → Fallback | license 缺失或過期時,控件會 render 成帶浮水印 / 彈窗 / 直接 throw LicenseException | Fallback 路徑不會自動切到開源替代,必須人為決策 |
讀圖重點:
- Fallback 回到步驟 5 而非步驟 1:只需更新 license 檔或呼叫
C1License.SetLicenseKey(key)後重新啟動 Runtime;不需要重 install NuGet 或改 XAML。 - 授權驗證發生在 Runtime,不在 Build 時:build 成功不代表部署環境授權有效。部署時必須實機跑一次驗證。
- 替換為開源替代 (LiveCharts) 是最後手段:會改動 XAML 與 Code-behind,屬於架構變更,不是純運維修復。
1. 使用的元件
| 套件 | 版本 | 用途 |
|---|---|---|
C1.WPF.Core | 8.0.20242.966 | 核心元件 |
C1.WPF.Chart | 8.0.20242.966 | FlexChart 圖表 |
C1.WPF.Grid | 8.0.20242.966 | FlexGrid 網格 |
C1.WPF.Input | 8.0.20242.966 | 輸入控件 |
C1.WPF.DateTimeEditors | 8.0.20242.966 | 日期時間選擇器 |
C1.WPF.Gauge | 8.0.20242.966 | 儀表盤 |
C1.WPF.Themes.Material | 8.0.20242.966 | Material 主題 |
C1.WPF.Themes.MaterialDark | 8.0.20242.966 | Material Dark 主題 |
1.1 控件分類
上表按 NuGet 套件列出;下圖則按用途分類,幫助選擇控件:
- 資料呈現類(Chart / Grid / Gauge)是 GST 專案的主力使用對象;其中 FlexChart 在 §2 有完整使用範例。
- 輸入類(Input / DateTimeEditors)通常搭配
FlexGridcell editor 使用,或放在設定畫面。 - 主題類 兩者互斥,同時只掛一個;切換時直接替換
App.xaml中的ResourceDictionarySource。 - GST 專案目前未使用 ToolBar / Ribbon / DocViewer / RichTextBox 等套件,因此未列入。
2. FlexChart 即時圖表
2.1 XAML 定義
xmlns:c1="http://schemas.componentone.com/winfx/2006/xaml"
<c1:FlexChart x:Name="dataChart"
ChartType="Line"
LegendPosition="Bottom"
ToolTipContent="{}{seriesName}
Time: {x:HH:mm:ss}
Value: {y:F2}">
<c1:FlexChart.AxisX>
<c1:Axis Title="Time" Format="HH:mm:ss" LabelAngle="-45" MajorGrid="True">
<c1:Axis.MajorGridStyle>
<c1:ChartStyle Stroke="#3A3A3A" />
</c1:Axis.MajorGridStyle>
</c1:Axis>
</c1:FlexChart.AxisX>
<c1:FlexChart.AxisY>
<c1:Axis Title="Value" MajorGrid="True">
<c1:Axis.MajorGridStyle>
<c1:ChartStyle Stroke="#3A3A3A" />
</c1:Axis.MajorGridStyle>
</c1:Axis>
</c1:FlexChart.AxisY>
</c1:FlexChart>
2.2 程式碼建構 Series
private void BuildChartSeries()
{
dataChart.BeginUpdate(); // 暫停渲染
try
{
dataChart.Series.Clear();
var colors = new[]
{
Color.FromRgb(0xFF, 0x57, 0x22), // Deep Orange
Color.FromRgb(0x3F, 0x51, 0xB5), // Indigo
Color.FromRgb(0x4C, 0xAF, 0x50), // Green
Color.FromRgb(0x9C, 0x27, 0xB0), // Purple
Color.FromRgb(0x00, 0xBC, 0xD4), // Cyan
Color.FromRgb(0xFF, 0xC1, 0x07), // Amber
Color.FromRgb(0xE9, 0x1E, 0x63), // Pink
Color.FromRgb(0x60, 0x7D, 0x8B) // Blue Grey
};
int colorIndex = 0;
foreach (var dataSeries in _viewModel.DataSeries)
{
if (!dataSeries.IsVisible || dataSeries.DataPoints.Count == 0)
continue;
var brush = new SolidColorBrush(colors[colorIndex % colors.Length]);
brush.Freeze(); // 記憶體最佳化
var series = new Series
{
SeriesName = dataSeries.DisplayName,
ItemsSource = dataSeries.DataPoints,
Binding = "Value",
BindingX = "Timestamp",
Style = new ChartStyle
{
Stroke = brush,
StrokeThickness = 2
}
};
dataChart.Series.Add(series);
colorIndex++;
}
}
finally
{
dataChart.EndUpdate(); // 恢復渲染
}
}
2.3 Data Model
public class ChartDataPoint
{
public DateTime Timestamp { get; set; }
public double Value { get; set; }
}
Series 的 Binding 對應 Value 屬性,BindingX 對應 Timestamp 屬性。
2.4 即時更新(Incremental Refresh)
private void RefreshChartData()
{
dataChart.BeginUpdate();
try
{
var selectedTags = _viewModel.SelectedTags;
for (int i = 0; i < dataChart.Series.Count && i < selectedTags.Count; i++)
{
// 只更新 ItemsSource,不重建 Series
dataChart.Series[i].ItemsSource = selectedTags[i].GetPoints();
}
}
finally
{
dataChart.EndUpdate();
}
}
重點:不要在每次 Polling 時重建 Series,只更新 ItemsSource。
3. 效能最佳化
3.1 BeginUpdate / EndUpdate
chart.BeginUpdate(); // 暫停所有渲染
try
{
// 批量操作(加/移 Series、更新 ItemsSource)
}
finally
{
chart.EndUpdate(); // 一次性渲染
}
必須使用。不使用的話,每次 Series.Add() 或 ItemsSource 變更都會觸發重繪,大量數據時會造成 UI 卡頓。
3.2 Brush Freezing
var brush = new SolidColorBrush(color);
brush.Freeze(); // 建立不可變副本,減少記憶體
對重複使用的 Brush 呼叫 Freeze(),避免 WPF 追蹤變更。
3.3 事件驅動更新
// ViewModel 端
_viewModel.DataPointsUpdated += (s, e) => RefreshChartData();
// 不要在 Polling 迴圈中直接操作 Chart
// 透過事件解耦,由 UI 層決定更新時機
3.4 大量數據處理建議
| 數據量 | 建議 |
|---|---|
| < 1,000 點 | 直接綁定,無需特殊處理 |
| 1,000 - 10,000 點 | 使用 BeginUpdate/EndUpdate |
| > 10,000 點 | 考慮降採樣(downsample)後再綁定 |
4. 主題整合
4.1 支援的主題
| 主題 | 類別 | 適用場景 |
|---|---|---|
C1ThemeMaterialDark | 深色 | 工業監控(預設) |
C1ThemeMaterial | 淺色 | 一般辦公 |
C1ThemeSystem | 系統 | 跟隨 Windows 設定 |
C1ThemeOffice365White | Office | 文件處理 |
4.2 套用主題
// ThemeHelper.cs
var theme = ThemeFactories[themeName]();
_currentThemeResources = theme.ThemeResources;
if (_currentThemeResources != null)
{
app.Resources.MergedDictionaries.Insert(0, _currentThemeResources);
}
4.3 自訂 Palette
Resources/Themes/
├── DarkPalette.xaml ← 深色主題色板
└── LightPalette.xaml ← 淺色主題色板
圖表的背景色、網格線、文字顏色透過 Palette 統一管理,確保與整體主題一致。
5. ToolTip 格式
ToolTipContent="{}{seriesName}
Time: {x:HH:mm:ss}
Value: {y:F2}"
| 語法 | 說明 |
|---|---|
{seriesName} | Series 名稱 |
{x:format} | X 軸值(支援 DateTime 格式) |
{y:format} | Y 軸值(支援數值格式) |
{value:format} | 同 {y} |

 | 換行(XML escaped) |
6. 授權管理
目前兩個專案未顯式呼叫 C1License.SetLicenseKey(),依賴 NuGet 套件的隱式授權機制。
部署時注意:
- 確認 ComponentOne 授權涵蓋部署環境
.NET Reactor保護不會影響 C1 授權驗證(C1 DLL 不在保護範圍內)
7. 開發規範
7.1 Series 管理
- 在 Code-behind 建構 Series,不在 XAML 中靜態定義(因為 Series 數量動態變化)
- 使用預定義色彩陣列 + index 分配,確保視覺一致性
- 提供 Empty State 處理(無數據時顯示提示文字)
7.2 效能
- 永遠 用
BeginUpdate/EndUpdate包裹批量操作 Brush.Freeze()減少 WPF 追蹤開銷- Polling 資料透過事件通知 UI,不直接在 Polling 迴圈操作 Chart
7.3 主題
- 所有 Chart 的網格線、背景色使用 Palette Resource
- 不硬編碼色彩值(除了 Series 色彩陣列)
8. 涉及專案
| 專案 | C1 用途 | 說明 |
|---|---|---|
| ProcessVision | FlexChart(歷史數據圖表) | 溫度/壓力趨勢、Data Chart Window |
| PLC-Monitor | FlexChart(即時趨勢)+ FlexGrid | 多 Tag 即時監控、Alarm Grid |
文件版本:v1.0 | 建立日期:2026-03-16 | 對應 Issue:GST-171