在wpf中直接显示Docx文件 ,直接看看效果吧:
下面直接看代码,添加主要有两个类:
DocxReader类:
using System;
using System.IO;
using System.IO.Packaging;
using System.Xml;namespace WpfEmbeddedDocx
{class DocxReader : IDisposable{protected const stringMainDocumentRelationshipType ="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",// XML namespacesWordprocessingMLNamespace = "http://schemas.openxmlformats.org/wordprocessingml/2006/main",RelationshipsNamespace = "http://schemas.openxmlformats.org/officeDocument/2006/relationships",// Miscellaneous elementsDocumentElement = "document",BodyElement = "body",// Block-Level elementsParagraphElement = "p",TableElement = "tbl",// Inline-Level elementsSimpleFieldElement = "fldSimple",HyperlinkElement = "hyperlink",RunElement = "r",// Run content elementsBreakElement = "br",TabCharacterElement = "tab",TextElement = "t",// Table elementsTableRowElement = "tr",TableCellElement = "tc",// Properties elementsParagraphPropertiesElement = "pPr",RunPropertiesElement = "rPr";// Note: new members should also be added to nameTable in CreateNameTable method.protected virtual XmlNameTable CreateNameTable(){var nameTable = new NameTable();nameTable.Add(WordprocessingMLNamespace);nameTable.Add(RelationshipsNamespace);nameTable.Add(DocumentElement);nameTable.Add(BodyElement);nameTable.Add(ParagraphElement);nameTable.Add(TableElement);nameTable.Add(ParagraphPropertiesElement);nameTable.Add(SimpleFieldElement);nameTable.Add(HyperlinkElement);nameTable.Add(RunElement);nameTable.Add(BreakElement);nameTable.Add(TabCharacterElement);nameTable.Add(TextElement);nameTable.Add(RunPropertiesElement);nameTable.Add(TableRowElement);nameTable.Add(TableCellElement);return nameTable;}private readonly Package package;private readonly PackagePart mainDocumentPart;protected PackagePart MainDocumentPart{get { return this.mainDocumentPart; }}public DocxReader(Stream stream){if (stream == null)throw new ArgumentNullException("stream");this.package = Package.Open(stream, FileMode.Open, FileAccess.Read);foreach (var relationship in this.package.GetRelationshipsByType(MainDocumentRelationshipType)){this.mainDocumentPart = package.GetPart(PackUriHelper.CreatePartUri(relationship.TargetUri));break;}}public void Read(){using (var mainDocumentStream = this.mainDocumentPart.GetStream(FileMode.Open, FileAccess.Read))using (var reader = XmlReader.Create(mainDocumentStream, new XmlReaderSettings(){NameTable = this.CreateNameTable(),IgnoreComments = true,IgnoreProcessingInstructions = true,IgnoreWhitespace = true}))this.ReadMainDocument(reader);}private static void ReadXmlSubtree(XmlReader reader, Action<XmlReader> action){using (var subtreeReader = reader.ReadSubtree()){// Position on the first node.subtreeReader.Read();if (action != null)action(subtreeReader);}}private void ReadMainDocument(XmlReader reader){while (reader.Read())if (reader.NodeType == XmlNodeType.Element && reader.NamespaceURI == WordprocessingMLNamespace &&reader.LocalName == DocumentElement){ReadXmlSubtree(reader, this.ReadDocument);break;}}protected virtual void ReadDocument(XmlReader reader){while (reader.Read())if (reader.NodeType == XmlNodeType.Element && reader.NamespaceURI == WordprocessingMLNamespace &&reader.LocalName == BodyElement){ReadXmlSubtree(reader, this.ReadBody);break;}}private void ReadBody(XmlReader reader){while (reader.Read())this.ReadBlockLevelElement(reader);}private void ReadBlockLevelElement(XmlReader reader){if (reader.NodeType == XmlNodeType.Element){Action<XmlReader> action = null;if (reader.NamespaceURI == WordprocessingMLNamespace)switch (reader.LocalName){case ParagraphElement:action = this.ReadParagraph;break;case TableElement:action = this.ReadTable;break;}ReadXmlSubtree(reader, action);}}protected virtual void ReadParagraph(XmlReader reader){while (reader.Read()){if (reader.NodeType == XmlNodeType.Element && reader.NamespaceURI == WordprocessingMLNamespace &&reader.LocalName == ParagraphPropertiesElement)ReadXmlSubtree(reader, this.ReadParagraphProperties);elsethis.ReadInlineLevelElement(reader);}}protected virtual void ReadParagraphProperties(XmlReader reader){}private void ReadInlineLevelElement(XmlReader reader){if (reader.NodeType == XmlNodeType.Element){Action<XmlReader> action = null;if (reader.NamespaceURI == WordprocessingMLNamespace)switch (reader.LocalName){case SimpleFieldElement:action = this.ReadSimpleField;break;case HyperlinkElement:action = this.ReadHyperlink;break;case RunElement:action = this.ReadRun;break;}ReadXmlSubtree(reader, action);}}private void ReadSimpleField(XmlReader reader){while (reader.Read())this.ReadInlineLevelElement(reader);}protected virtual void ReadHyperlink(XmlReader reader){while (reader.Read())this.ReadInlineLevelElement(reader);}protected virtual void ReadRun(XmlReader reader){while (reader.Read()){if (reader.NodeType == XmlNodeType.Element && reader.NamespaceURI == WordprocessingMLNamespace &&reader.LocalName == RunPropertiesElement)ReadXmlSubtree(reader, this.ReadRunProperties);elsethis.ReadRunContentElement(reader);}}protected virtual void ReadRunProperties(XmlReader reader){}private void ReadRunContentElement(XmlReader reader){if (reader.NodeType == XmlNodeType.Element){Action<XmlReader> action = null;if (reader.NamespaceURI == WordprocessingMLNamespace)switch (reader.LocalName){case BreakElement:action = this.ReadBreak;break;case TabCharacterElement:action = this.ReadTabCharacter;break;case TextElement:action = this.ReadText;break;}ReadXmlSubtree(reader, action);}}protected virtual void ReadBreak(XmlReader reader){}protected virtual void ReadTabCharacter(XmlReader reader){}protected virtual void ReadText(XmlReader reader){}protected virtual void ReadTable(XmlReader reader){while (reader.Read())if (reader.NodeType == XmlNodeType.Element && reader.NamespaceURI == WordprocessingMLNamespace &&reader.LocalName == TableRowElement)ReadXmlSubtree(reader, this.ReadTableRow);}protected virtual void ReadTableRow(XmlReader reader){while (reader.Read())if (reader.NodeType == XmlNodeType.Element && reader.NamespaceURI == WordprocessingMLNamespace &&reader.LocalName == TableCellElement)ReadXmlSubtree(reader, this.ReadTableCell);}protected virtual void ReadTableCell(XmlReader reader){while (reader.Read())this.ReadBlockLevelElement(reader);}public void Dispose(){this.package.Close();}}
}
DocxToFlowDocumentConverter类:
using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Packaging;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Navigation;
using System.Xml;namespace WpfEmbeddedDocx
{class DocxToFlowDocumentConverter : DocxReader{private const string// Run properties elementsBoldElement = "b",ItalicElement = "i",UnderlineElement = "u",StrikeElement = "strike",DoubleStrikeElement = "dstrike",VerticalAlignmentElement = "vertAlign",ColorElement = "color",HighlightElement = "highlight",FontElement = "rFonts",FontSizeElement = "sz",RightToLeftTextElement = "rtl",// Paragraph properties elementsAlignmentElement = "jc",PageBreakBeforeElement = "pageBreakBefore",SpacingElement = "spacing",IndentationElement = "ind",ShadingElement = "shd",// AttributesIdAttribute = "id",ValueAttribute = "val",ColorAttribute = "color",AsciiFontFamily = "ascii",SpacingAfterAttribute = "after",SpacingBeforeAttribute = "before",LeftIndentationAttribute = "left",RightIndentationAttribute = "right",HangingIndentationAttribute = "hanging",FirstLineIndentationAttribute = "firstLine",FillAttribute = "fill";private FlowDocument document;private TextElement current;private bool hasAnyHyperlink;public FlowDocument Document{get { return this.document; }}public DocxToFlowDocumentConverter(Stream stream): base(stream){}protected override XmlNameTable CreateNameTable(){var nameTable = base.CreateNameTable();nameTable.Add(BoldElement);nameTable.Add(ItalicElement);nameTable.Add(UnderlineElement);nameTable.Add(StrikeElement);nameTable.Add(DoubleStrikeElement);nameTable.Add(VerticalAlignmentElement);nameTable.Add(ColorElement);nameTable.Add(HighlightElement);nameTable.Add(FontElement);nameTable.Add(FontSizeElement);nameTable.Add(RightToLeftTextElement);nameTable.Add(AlignmentElement);nameTable.Add(PageBreakBeforeElement);nameTable.Add(SpacingElement);nameTable.Add(IndentationElement);nameTable.Add(ShadingElement);nameTable.Add(IdAttribute);nameTable.Add(ValueAttribute);nameTable.Add(ColorAttribute);nameTable.Add(AsciiFontFamily);nameTable.Add(SpacingAfterAttribute);nameTable.Add(SpacingBeforeAttribute);nameTable.Add(LeftIndentationAttribute);nameTable.Add(RightIndentationAttribute);nameTable.Add(HangingIndentationAttribute);nameTable.Add(FirstLineIndentationAttribute);nameTable.Add(FillAttribute);return nameTable;}protected override void ReadDocument(XmlReader reader){this.document = new FlowDocument();this.document.BeginInit();this.document.ColumnWidth = double.NaN;base.ReadDocument(reader);if (this.hasAnyHyperlink)this.document.AddHandler(Hyperlink.RequestNavigateEvent,new RequestNavigateEventHandler((sender, e) => Process.Start(e.Uri.ToString())));this.document.EndInit();}protected override void ReadParagraph(XmlReader reader){using (this.SetCurrent(new Paragraph()))base.ReadParagraph(reader);}protected override void ReadTable(XmlReader reader){// Skip table for now.}protected override void ReadParagraphProperties(XmlReader reader){while (reader.Read())if (reader.NodeType == XmlNodeType.Element && reader.NamespaceURI == WordprocessingMLNamespace){var paragraph = (Paragraph)this.current;switch (reader.LocalName){case AlignmentElement:var textAlignment = ConvertTextAlignment(GetValueAttribute(reader));if (textAlignment.HasValue)paragraph.TextAlignment = textAlignment.Value;break;case PageBreakBeforeElement:paragraph.BreakPageBefore = GetOnOffValueAttribute(reader);break;case SpacingElement:paragraph.Margin = GetSpacing(reader, paragraph.Margin);break;case IndentationElement:SetParagraphIndent(reader, paragraph);break;case ShadingElement:var background = GetShading(reader);if (background != null)paragraph.Background = background;break;}}}protected override void ReadHyperlink(XmlReader reader){var id = reader[IdAttribute, RelationshipsNamespace];if (!string.IsNullOrEmpty(id)){var relationship = this.MainDocumentPart.GetRelationship(id);if (relationship.TargetMode == TargetMode.External){this.hasAnyHyperlink = true;var hyperlink = new Hyperlink(){NavigateUri = relationship.TargetUri};using (this.SetCurrent(hyperlink))base.ReadHyperlink(reader);return;}}base.ReadHyperlink(reader);}protected override void ReadRun(XmlReader reader){using (this.SetCurrent(new Span()))base.ReadRun(reader);}protected override void ReadRunProperties(XmlReader reader){while (reader.Read())if (reader.NodeType == XmlNodeType.Element && reader.NamespaceURI == WordprocessingMLNamespace){var inline = (Inline)this.current;switch (reader.LocalName){case BoldElement:inline.FontWeight = GetOnOffValueAttribute(reader) ? FontWeights.Bold : FontWeights.Normal;break;case ItalicElement:inline.FontStyle = GetOnOffValueAttribute(reader) ? FontStyles.Italic : FontStyles.Normal;break;case UnderlineElement:var underlineTextDecorations = GetUnderlineTextDecorations(reader, inline);if (underlineTextDecorations != null)inline.TextDecorations.Add(underlineTextDecorations);break;case StrikeElement:if (GetOnOffValueAttribute(reader))inline.TextDecorations.Add(TextDecorations.Strikethrough);break;case DoubleStrikeElement:if (GetOnOffValueAttribute(reader)){inline.TextDecorations.Add(new TextDecoration(){Location = TextDecorationLocation.Strikethrough,PenOffset = this.current.FontSize * 0.015});inline.TextDecorations.Add(new TextDecoration(){Location = TextDecorationLocation.Strikethrough,PenOffset = this.current.FontSize * -0.015});}break;case VerticalAlignmentElement:var baselineAlignment = GetBaselineAlignment(GetValueAttribute(reader));if (baselineAlignment.HasValue){inline.BaselineAlignment = baselineAlignment.Value;if (baselineAlignment.Value == BaselineAlignment.Subscript ||baselineAlignment.Value == BaselineAlignment.Superscript)inline.FontSize *=0.65; //MS Word 2002 size: 65% http://en.wikipedia.org/wiki/Subscript_and_superscript}break;case ColorElement:var color = GetColor(GetValueAttribute(reader));if (color.HasValue)inline.Foreground = new SolidColorBrush(color.Value);break;case HighlightElement:var highlight = GetHighlightColor(GetValueAttribute(reader));if (highlight.HasValue)inline.Background = new SolidColorBrush(highlight.Value);break;case FontElement:var fontFamily = reader[AsciiFontFamily, WordprocessingMLNamespace];if (!string.IsNullOrEmpty(fontFamily))inline.FontFamily =(FontFamily)new FontFamilyConverter().ConvertFromString(fontFamily);break;case FontSizeElement:var fontSize = reader[ValueAttribute, WordprocessingMLNamespace];if (!string.IsNullOrEmpty(fontSize))// Attribute Value / 2 = Points// Points * (96 / 72) = Pixelsinline.FontSize = uint.Parse(fontSize) * 0.6666666666666667;break;case RightToLeftTextElement:inline.FlowDirection = (GetOnOffValueAttribute(reader))? FlowDirection.RightToLeft: FlowDirection.LeftToRight;break;}}}protected override void ReadBreak(XmlReader reader){this.AddChild(new LineBreak());}protected override void ReadTabCharacter(XmlReader reader){this.AddChild(new Run("\t"));}protected override void ReadText(XmlReader reader){this.AddChild(new Run(reader.ReadString()));}private void AddChild(TextElement textElement){((IAddChild)this.current ?? this.document).AddChild(textElement);}private static bool GetOnOffValueAttribute(XmlReader reader){var value = GetValueAttribute(reader);switch (value){case null:case "1":case "on":case "true":return true;default:return false;}}private static string GetValueAttribute(XmlReader reader){return reader[ValueAttribute, WordprocessingMLNamespace];}private static Color? GetColor(string colorString){if (string.IsNullOrEmpty(colorString) || colorString == "auto")return null;return (Color)ColorConverter.ConvertFromString('#' + colorString);}private static Color? GetHighlightColor(string highlightString){if (string.IsNullOrEmpty(highlightString) || highlightString == "auto")return null;return (Color)ColorConverter.ConvertFromString(highlightString);}private static BaselineAlignment? GetBaselineAlignment(string verticalAlignmentString){switch (verticalAlignmentString){case "baseline":return BaselineAlignment.Baseline;case "subscript":return BaselineAlignment.Subscript;case "superscript":return BaselineAlignment.Superscript;default:return null;}}private static double? ConvertTwipsToPixels(string twips){if (string.IsNullOrEmpty(twips))return null;elsereturn ConvertTwipsToPixels(double.Parse(twips, CultureInfo.InvariantCulture));}private static double ConvertTwipsToPixels(double twips){return 96d / (72 * 20) * twips;}private static TextAlignment? ConvertTextAlignment(string value){switch (value){case "both":return TextAlignment.Justify;case "left":return TextAlignment.Left;case "right":return TextAlignment.Right;case "center":return TextAlignment.Center;default:return null;}}private static Thickness GetSpacing(XmlReader reader, Thickness margin){var after = ConvertTwipsToPixels(reader[SpacingAfterAttribute, WordprocessingMLNamespace]);if (after.HasValue)margin.Bottom = after.Value;var before = ConvertTwipsToPixels(reader[SpacingBeforeAttribute, WordprocessingMLNamespace]);if (before.HasValue)margin.Top = before.Value;return margin;}private static void SetParagraphIndent(XmlReader reader, Paragraph paragraph){var margin = paragraph.Margin;var left = ConvertTwipsToPixels(reader[LeftIndentationAttribute, WordprocessingMLNamespace]);if (left.HasValue)margin.Left = left.Value;var right = ConvertTwipsToPixels(reader[RightIndentationAttribute, WordprocessingMLNamespace]);if (right.HasValue)margin.Right = right.Value;paragraph.Margin = margin;var firstLine = ConvertTwipsToPixels(reader[FirstLineIndentationAttribute, WordprocessingMLNamespace]);if (firstLine.HasValue)paragraph.TextIndent = firstLine.Value;var hanging = ConvertTwipsToPixels(reader[HangingIndentationAttribute, WordprocessingMLNamespace]);if (hanging.HasValue)paragraph.TextIndent -= hanging.Value;}private static Brush GetShading(XmlReader reader){var color = GetColor(reader[FillAttribute, WordprocessingMLNamespace]);return color.HasValue ? new SolidColorBrush(color.Value) : null;}private static TextDecorationCollection GetUnderlineTextDecorations(XmlReader reader, Inline inline){TextDecoration textDecoration;Brush brush;var color = GetColor(reader[ColorAttribute, WordprocessingMLNamespace]);if (color.HasValue)brush = new SolidColorBrush(color.Value);elsebrush = inline.Foreground;var textDecorations = new TextDecorationCollection(){(textDecoration = new TextDecoration(){Location = TextDecorationLocation.Underline,Pen = new Pen(){Brush = brush}})};switch (GetValueAttribute(reader)){case "single":break;case "double":textDecoration.PenOffset = inline.FontSize * 0.05;textDecoration = textDecoration.Clone();textDecoration.PenOffset = inline.FontSize * -0.05;textDecorations.Add(textDecoration);break;case "dotted":textDecoration.Pen.DashStyle = DashStyles.Dot;break;case "dash":textDecoration.Pen.DashStyle = DashStyles.Dash;break;case "dotDash":textDecoration.Pen.DashStyle = DashStyles.DashDot;break;case "dotDotDash":textDecoration.Pen.DashStyle = DashStyles.DashDotDot;break;case "none":default:// If underline type is none or unsupported then it will be ignored.return null;}return textDecorations;}private IDisposable SetCurrent(TextElement current){return new CurrentHandle(this, current);}private struct CurrentHandle : IDisposable{private readonly DocxToFlowDocumentConverter converter;private readonly TextElement previous;public CurrentHandle(DocxToFlowDocumentConverter converter, TextElement current){this.converter = converter;this.converter.AddChild(current);this.previous = this.converter.current;this.converter.current = current;}public void Dispose(){this.converter.current = this.previous;}}}
}
,最后,在MainWindow.xaml代码:
<Window x:Class="WpfEmbeddedDocx.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:WpfEmbeddedDocx"mc:Ignorable="d"Title="MainWindow" Height="450" Width="800"><Grid><DockPanel><Menu DockPanel.Dock="Top"><MenuItem Header="_Open file..." Click="OnOpenFileClicked"/></Menu><FlowDocumentScrollViewer Name="FlowDocumentScrollViewer"></FlowDocumentScrollViewer></DockPanel></Grid>
</Window>
MainWindow.cs的代码:
using System.IO;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Win32;namespace WpfEmbeddedDocx
{public partial class MainWindow : Window{public MainWindow(){InitializeComponent();}private void ReadDocx(string path){using (var stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)){var flowDocumentConverter = new DocxToFlowDocumentConverter(stream);flowDocumentConverter.Read();FlowDocumentScrollViewer.Document = flowDocumentConverter.Document;this.Title = Path.GetFileName(path);}}private void OnOpenFileClicked(object sender, RoutedEventArgs e){var openFileDialog = new OpenFileDialog(){DefaultExt = ".docx",Filter = "Word documents (.docx)|*.docx"};if (openFileDialog.ShowDialog() == true)this.ReadDocx(openFileDialog.FileName);}}
}
这样就能实现视频中的效果啦。。
下载链接:https://pan.baidu.com/s/1UO9GYYsUmoPWd49aVGR4rQ
提取码:bybq
原Git仓库代码地址:https://github.com/ArtMalykhin/wpf-embedded-docx
感谢作者无私分享