【OpenXml】Pptx的邊框虛線轉為WPF的邊框虛線

【OpenXml】Pptx的邊框虛線轉為WPF的邊框虛線

如題

最後更新 2022/5/2 下午8:59
RyzenAdorer
預計閱讀 3 分鐘
分類
.NET
標籤
.NET C# WPF OpenXML

1. 安裝 Openxml SDK

首先,我們先安裝 NuGet 所需的 Openxml SDK,我們開源了解析 PPTX 的 Openxml 拍平層,以下兩種方式皆可安裝:

  • NuGet 套件管理員主控台:
Install-Package dotnetCampus.DocumentFormat.OpenXml.Flatten -Version 2.0.0
  • csproj 參考:
<PackageReference Include="dotnetCampus.DocumentFormat.OpenXml.Flatten" Version="2.0.0" />

2. 解析 PPTX

我這裡用 PPTX 的 7 種直線,分別設定 7 種可設定的虛線類型,PPTX 的顯示效果如下:

然後解析程式碼如下,解析主要邏輯部分:

private void PptxToGeometry(string filePath)
{
    if (!File.Exists(filePath) || !filePath.EndsWith(".pptx", StringComparison.OrdinalIgnoreCase))
    {
        return;
    }

    var lines = new List<Line>();
    using var presentationDocument = PresentationDocument.Open(filePath, false);
    var presentationPart = presentationDocument.PresentationPart;
    var presentation = presentationPart?.Presentation;
    var slideIdList = presentation?.SlideIdList;
    if (slideIdList == null)
    {
        return;
    }
    foreach (var slideId in slideIdList.ChildElements.OfType<SlideId>())
    {
        var slidePart = (SlidePart)presentationPart.GetPartById(slideId.RelationshipId);
        var slide = slidePart.Slide;
        foreach (var shapeProperties in slide.Descendants<ShapeProperties>())
        {
            var presetGeometry = shapeProperties.GetFirstChild<PresetGeometry>();
            if (presetGeometry != null && presetGeometry.Preset.HasValue)
            {
                if (presetGeometry.Preset == ShapeTypeValues.StraightConnector1)
                {
                    var transform2D = shapeProperties.GetFirstChild<Transform2D>();
                    var extents = transform2D?.GetFirstChild<Extents>();
                    if (extents != null)
                    {
                        var width = new Emu(extents.Cx!.Value).ToPixel().Value;
                        var height = new Emu(extents.Cy!.Value).ToPixel().Value;


                        var presetDash = shapeProperties.GetFirstChild<Outline>()?.GetFirstChild<PresetDash>()?.Val;
                        var dashArray = GetDashArrayByPresetLineDashValues(presetDash);
                        var line = ConverterToGeometry( width, height, dashArray);
                        lines.Add(line);
                    }
                }
            }
        }
    }

    this.ListBox.ItemsSource = lines;
}

PPTX 對應成 WPF 虛線的方法:

private DoubleCollection GetDashArrayByPresetLineDashValues(PresetLineDashValues presetLineDashValues)
{
    DoubleCollection dashStyle = presetLineDashValues switch
    {
        PresetLineDashValues.Solid => new(),
        PresetLineDashValues.Dot => new() { 0, 2 },
        PresetLineDashValues.Dash => new() { 3, 3 },
        PresetLineDashValues.LargeDash => new() { 8, 3 },
        PresetLineDashValues.DashDot => new() { 3, 3, 1, 3 },
        PresetLineDashValues.LargeDashDot => new() { 7.5, 3.5, 1, 3.5 },
        PresetLineDashValues.LargeDashDotDot => new() { 8, 3, 1, 3, 1, 3 },
        PresetLineDashValues.SystemDash => new() { 3, 1 },
        PresetLineDashValues.SystemDot => new() { 1, 1 },
        PresetLineDashValues.SystemDashDot => new() { 2, 2, 0, 2 },
        PresetLineDashValues.SystemDashDotDot => new() { 2, 2, 0, 2 },
        _ => new DoubleCollection()
    };
    return dashStyle;
}

最終繪製線條的方法:

private Line ConverterToGeometry(double width, double height, DoubleCollection dashDoubleCollection)
{
    var line = new Line
    {
        X1 = 0,
        Y1 = 0,
        X2 = width,
        Y2 = height,
        StrokeDashArray = dashDoubleCollection,
        Stroke = Stroke,
        StrokeThickness = StrokeThickness
    };
    return line;
}

最終的效果:

我們可以看到幾乎是接近的效果了,當然你也可以根據我的程式碼去微調更精確的值,只需稍微修改 GetDashArrayByPresetLineDashValues 方法內對應的值即可。

3. 後話

實際上,OpenXML 文件是有給出 PresetDash 的值的,大致如下:

但其值與 WPF 設定 Dash 的 DoubleCollection 不對應,因此以上的對應值都是我自行微調的。

4. 原始碼

BlogCodeSample/PptDashConverToWpfSample at main · ZhengDaoWang/BlogCodeSample

繼續探索

延伸閱讀

更多文章
同分類 / 同標籤 2025/5/27

WPF完成一個危險提醒效果

當我們寫的程式發放出去後,用戶是在進行一些危險操作,我們的軟體應該給一些提醒效果,比如邊框邊緣有紅色,類似與高德地圖那樣的警報提醒效果

繼續閱讀
同分類 / 同標籤 2024/6/20

CodeWF.EventBus:輕量級事件匯流排,讓通訊更流暢

CodeWF.EventBus,一款靈活的事件匯流排庫,實現模組間解耦通訊。支援多種.NET專案類型,如WPF、WinForms、ASP.NET Core等。採用簡潔設計,輕鬆實現命令的發布與訂閱、請求與回應。透過有序的事件處理,確保事件得到妥善處理。簡化您的程式碼,提升系統可維護性。

繼續閱讀