OfficeViewer.Avalonia
0.1.6
dotnet add package OfficeViewer.Avalonia --version 0.1.6
NuGet\Install-Package OfficeViewer.Avalonia -Version 0.1.6
<PackageReference Include="OfficeViewer.Avalonia" Version="0.1.6" />
<PackageVersion Include="OfficeViewer.Avalonia" Version="0.1.6" />
<PackageReference Include="OfficeViewer.Avalonia" />
paket add OfficeViewer.Avalonia --version 0.1.6
#r "nuget: OfficeViewer.Avalonia, 0.1.6"
#:package OfficeViewer.Avalonia@0.1.6
#addin nuget:?package=OfficeViewer.Avalonia&version=0.1.6
#tool nuget:?package=OfficeViewer.Avalonia&version=0.1.6
OfficeViewer.Avalonia
中文说明
OfficeViewer.Avalonia 是用于 Avalonia 的只读 Office/PDF 原生预览控件包,提供 DOCX、PPTX、XLSX 与常见 PDF 的连续流式预览。
控件外层保持透明,不会强制宿主窗口背景。请由应用在外层使用 Border、Panel 或主题容器决定背景、圆角与阴影。
参考项目
DOCX、PPTX、XLSX 的文件读取、关系解析、样式模型和连续布局设计参考了 vue-office-core 项目。本包将对应思路移植为 C# 的 Open XML 解析和 Avalonia 控件渲染;它不包含 Vue、JavaScript 或 WebView 运行时,也不是对 Vue 组件的直接包装。
PDF 预览是当前项目独立实现的纯托管常见子集解析器:它不捆绑 PDF.js、PDFium 或 PdfPig。支持范围请见“格式范围与限制”。
包含控件
| 文档格式 | 命名空间和控件 | 读取结果属性 |
|---|---|---|
| Word / DOCX | OfficeViewer.Avalonia.Docx.DocxViewer |
PageCount |
| PowerPoint / PPTX | OfficeViewer.Avalonia.Pptx.PptxViewer |
PageCount |
| Excel / XLSX | OfficeViewer.Avalonia.Xlsx.XlsxViewer |
SheetCount、SelectedSheetIndex |
OfficeViewer.Avalonia.Pdf.PdfViewer |
PageCount |
每个控件均提供可绑定的 byte[]? Document 属性。给 Document 赋新的文件字节数组会自动开始读取;将其清除或设为 null 会自动取消旧读取任务,并释放当前文档的模型、图像与可视资源。PPTX/PDF 仅会实例化可视页及少量相邻页,避免长文档持续占用图片内存。控件仍保留 LoadAsync 作为非绑定场景的便捷方法。
缩放
所有四个预览控件均支持 Ctrl + 鼠标滚轮缩放,以及触屏单指上下左右拖动、双指缩放。 内容超出视口时可以横向或纵向移动;双指缩放结束后,剩余一指可继续拖动。
安装
从你的 NuGet 源安装:
<PackageReference Include="OfficeViewer.Avalonia" Version="0.1.6" />
本仓库本地构建后的包目录如下,可在 Visual Studio、Rider 或 NuGet.Config 中添加为本地源:
OfficeViewer.Avalonia.NuGet\artifacts\packages
Avalonia XAML 用法
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:docx="clr-namespace:OfficeViewer.Avalonia.Docx;assembly=OfficeViewer.Avalonia"
xmlns:pptx="clr-namespace:OfficeViewer.Avalonia.Pptx;assembly=OfficeViewer.Avalonia"
xmlns:xlsx="clr-namespace:OfficeViewer.Avalonia.Xlsx;assembly=OfficeViewer.Avalonia"
xmlns:pdf="clr-namespace:OfficeViewer.Avalonia.Pdf;assembly=OfficeViewer.Avalonia">
<Grid RowDefinitions="Auto,*">
<TextBlock Text="{Binding PageCount, ElementName=DocxPreview}" />
<Border Grid.Row="1" Background="White" Padding="8">
<docx:DocxViewer x:Name="DocxPreview"
Document="{Binding DocxDocument}" />
</Border>
</Grid>
</Window>
其他三种控件的声明方式:
<pptx:PptxViewer x:Name="PptxPreview"
Document="{Binding PptxDocument}" />
<pdf:PdfViewer x:Name="PdfPreview"
Document="{Binding PdfDocument}" />
<xlsx:XlsxViewer x:Name="XlsxPreview"
Document="{Binding XlsxDocument}"
SelectedSheetIndex="{Binding SelectedWorksheet, Mode=TwoWay}" />
SelectedSheetIndex 从 0 开始。XLSX 控件故意不内置工作表选择器,请绑定到你自己的按钮、ComboBox、选项卡或 ViewModel。工作簿读取完成后,SheetCount 会更新。
C# 加载与释放
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
public sealed class OfficePreviewViewModel : INotifyPropertyChanged
{
private byte[]? _docxDocument;
private byte[]? _pptxDocument;
private byte[]? _xlsxDocument;
private byte[]? _pdfDocument;
private int _selectedWorksheet;
public byte[]? DocxDocument { get => _docxDocument; set => SetField(ref _docxDocument, value); }
public byte[]? PptxDocument { get => _pptxDocument; set => SetField(ref _pptxDocument, value); }
public byte[]? XlsxDocument { get => _xlsxDocument; set => SetField(ref _xlsxDocument, value); }
public byte[]? PdfDocument { get => _pdfDocument; set => SetField(ref _pdfDocument, value); }
public int SelectedWorksheet { get => _selectedWorksheet; set => SetField(ref _selectedWorksheet, value); }
public async Task OpenDocxAsync(string path) => DocxDocument = await File.ReadAllBytesAsync(path);
public async Task OpenPptxAsync(string path) => PptxDocument = await File.ReadAllBytesAsync(path);
public async Task OpenXlsxAsync(string path) => XlsxDocument = await File.ReadAllBytesAsync(path);
public async Task OpenPdfAsync(string path) => PdfDocument = await File.ReadAllBytesAsync(path);
public void ReleaseDocuments()
{
// null automatically cancels loading and releases each viewer's resources.
DocxDocument = null;
PptxDocument = null;
XlsxDocument = null;
PdfDocument = null;
}
public event PropertyChangedEventHandler? PropertyChanged;
private void SetField<T>(ref T field, T value, [CallerMemberName] string? name = null)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return;
field = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
Document、PageCount、SheetCount 是 Avalonia StyledProperty。请在 ViewModel 中将文档字节数组绑定到 Document;需要释放内存时也将绑定源设为 null,使控件和 ViewModel 都不再保留该字节数组。
可在代码中调用 LoadAsync(Stream) 读取流。控件不会关闭调用方传入的流,而会创建自己的字节快照并将其赋给 Document;MVVM 绑定仍建议使用 byte[]? Document。
NativeAOT
本包支持 NativeAOT。
格式范围与限制
- DOCX:WordprocessingML 段落、文字 Run、编号、图片、表格、常见形状/文本框和页面流式布局。
- PPTX:PresentationML 幻灯片、主题/样式继承、文字、图片、填充、渐变、常见形状及已支持图表的连续流布局。
- XLSX:工作簿/工作表关系、共享字符串/富文本、样式、合并单元格、图片、行列尺寸、颜色和当前工作表绑定。
- PDF:压缩对象流、Form XObject、文字/CMap 解码、带常见蒙版的图片、填充/线条/透明度,以及 WPS 水印标记。加密、签名、损坏文件或高级 PDF 图形/字体仍可能需要完整 PDF 渲染器,本包不会宣称完全兼容。
English
OfficeViewer.Avalonia is a set of read-only native Avalonia viewers for DOCX, PPTX, XLSX, and common PDF files. Documents use continuous scrolling rather than a flip-book UI.
The outer viewer surface is transparent. Hosts own the surrounding background, corner radius, and shadow by wrapping the control in a Border, Panel, or theme container.
Reference project
The file-reading flow, relationship parsing, style models, and continuous-layout design for DOCX, PPTX, and XLSX are informed by vue-office-core. This package ports those ideas to C# Open XML parsing and Avalonia-native rendering. It does not bundle Vue, JavaScript, or a WebView, and it is not a wrapper around Vue components.
The PDF viewer is this project's separate managed common-subset implementation. It does not bundle PDF.js, PDFium, or PdfPig. See “Format scope and limitations” for the supported subset.
Included controls
| Document | Namespace and control | Result count |
|---|---|---|
| Word / DOCX | OfficeViewer.Avalonia.Docx.DocxViewer |
PageCount |
| PowerPoint / PPTX | OfficeViewer.Avalonia.Pptx.PptxViewer |
PageCount |
| Excel / XLSX | OfficeViewer.Avalonia.Xlsx.XlsxViewer |
SheetCount, SelectedSheetIndex |
OfficeViewer.Avalonia.Pdf.PdfViewer |
PageCount |
预览截图 / Screenshots
以下截图来自 samples 目录中的实际控件运行效果。 / The following screenshots show the viewers running with the sample documents in the samples directory.
| 格式 / Format | 预览 / Preview |
|---|---|
| Word / DOCX | |
| PowerPoint / PPTX | |
| Excel / XLSX | |
Every viewer exposes a bindable byte[]? Document property. Assign a new document byte array to start loading automatically; clear it or assign null to cancel stale loading and release the current document model, images, and visual resources. PPTX and PDF only materialize visible pages/slides plus a small adjacent buffer. LoadAsync remains available as a convenience method for non-binding scenarios.
Zoom
All four viewers support Ctrl + mouse wheel zoom, one-finger touch panning in both directions, and two-finger pinch zoom. Panning is available when content exceeds the viewport; the remaining finger can continue panning after a pinch.
Install
Install from your NuGet source:
<PackageReference Include="OfficeViewer.Avalonia" Version="0.1.6" />
For a local build of this repository, add the following folder as a NuGet source:
OfficeViewer.Avalonia.NuGet\artifacts\packages
Avalonia XAML usage
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:docx="clr-namespace:OfficeViewer.Avalonia.Docx;assembly=OfficeViewer.Avalonia"
xmlns:pptx="clr-namespace:OfficeViewer.Avalonia.Pptx;assembly=OfficeViewer.Avalonia"
xmlns:xlsx="clr-namespace:OfficeViewer.Avalonia.Xlsx;assembly=OfficeViewer.Avalonia"
xmlns:pdf="clr-namespace:OfficeViewer.Avalonia.Pdf;assembly=OfficeViewer.Avalonia">
<Grid RowDefinitions="Auto,*">
<TextBlock Text="{Binding PageCount, ElementName=DocxPreview}" />
<Border Grid.Row="1" Background="White" Padding="8">
<docx:DocxViewer x:Name="DocxPreview"
Document="{Binding DocxDocument}" />
</Border>
</Grid>
</Window>
Create the other controls in the same way:
<pptx:PptxViewer x:Name="PptxPreview"
Document="{Binding PptxDocument}" />
<pdf:PdfViewer x:Name="PdfPreview"
Document="{Binding PdfDocument}" />
<xlsx:XlsxViewer x:Name="XlsxPreview"
Document="{Binding XlsxDocument}"
SelectedSheetIndex="{Binding SelectedWorksheet, Mode=TwoWay}" />
SelectedSheetIndex is zero-based. The XLSX control intentionally has no built-in worksheet selector; bind it to your own buttons, ComboBox, tabs, or view model. SheetCount updates after a successful workbook load.
Load and release in C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
public sealed class OfficePreviewViewModel : INotifyPropertyChanged
{
private byte[]? _docxDocument;
private byte[]? _pptxDocument;
private byte[]? _xlsxDocument;
private byte[]? _pdfDocument;
private int _selectedWorksheet;
public byte[]? DocxDocument { get => _docxDocument; set => SetField(ref _docxDocument, value); }
public byte[]? PptxDocument { get => _pptxDocument; set => SetField(ref _pptxDocument, value); }
public byte[]? XlsxDocument { get => _xlsxDocument; set => SetField(ref _xlsxDocument, value); }
public byte[]? PdfDocument { get => _pdfDocument; set => SetField(ref _pdfDocument, value); }
public int SelectedWorksheet { get => _selectedWorksheet; set => SetField(ref _selectedWorksheet, value); }
public async Task OpenDocxAsync(string path) => DocxDocument = await File.ReadAllBytesAsync(path);
public async Task OpenPptxAsync(string path) => PptxDocument = await File.ReadAllBytesAsync(path);
public async Task OpenXlsxAsync(string path) => XlsxDocument = await File.ReadAllBytesAsync(path);
public async Task OpenPdfAsync(string path) => PdfDocument = await File.ReadAllBytesAsync(path);
public void ReleaseDocuments()
{
// null automatically cancels loading and releases each viewer's resources.
DocxDocument = null;
PptxDocument = null;
XlsxDocument = null;
PdfDocument = null;
}
public event PropertyChangedEventHandler? PropertyChanged;
private void SetField<T>(ref T field, T value, [CallerMemberName] string? name = null)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return;
field = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
Document, PageCount, and SheetCount are Avalonia styled properties. Bind the document byte array from a view model to Document; set that binding source to null when releasing memory so neither the viewer nor the view model retains the bytes.
For code-behind or service code, LoadAsync(Stream) accepts a stream without taking ownership of it. The viewer creates its own byte snapshot and assigns it to Document; byte[]? Document remains the recommended MVVM binding API.
NativeAOT
This package supports NativeAOT.
Format scope and limitations
- DOCX: WordprocessingML paragraphs, runs, numbering, images, tables, common shapes/text boxes, and page-flow layout.
- PPTX: PresentationML slides, theme/style inheritance, text, pictures, fills, gradients, common shapes, and supported charts in continuous flow.
- XLSX: workbook/sheet relationships, shared strings/rich text, styles, merged cells, images, row/column sizes, colors, and active-sheet binding.
- PDF: compressed object streams, Form XObjects, text/CMap decoding, images with common masks, fills/lines/transparency, and WPS watermark artifacts. Password-protected, signed, malformed, or advanced PDF graphics/font features can still require a full PDF renderer and are intentionally not claimed as fully supported.
Layout
OfficeViewer.Avalonia.NuGet/
src/OfficeViewer.Avalonia/ Package source / 包源码
samples/PackageConsumer/ PackageReference-only consumer / 独立消费项目
scripts/pack-and-verify.ps1 Package verification / 打包验证
artifacts/packages/ Generated .nupkg and .snupkg files / 生成包
0.1.6 更新 / Changes
- 触屏:统一四个控件的单指拖动与双指缩放,保留缩放中心,修复松开一指后不能继续拖动。
- PPTX:保持原始图文层级,支持图片裁剪,补充母版/版式静态元素及占位符位置继承,分别应用每段文字的对齐。
- DOCX:按段内分页标记拆分页面、支持直接设置的段前分页,保留离屏页已测量的高度,读取表格列宽与显式取消加粗/斜体。
- XLSX:修正数字/布尔值默认对齐、单元格缩小规则、图片锚点与裁剪;切换工作表时取消旧任务并释放图像。
- 解码任务限制为最多两个并发;离屏页面取消待完成任务。控件创建和文字测量仍需在 UI 线程执行,并分批让出 UI 线程。
Touch pan/pinch transitions are shared by all four viewers. PPTX preserves paint order, picture cropping and static master/layout elements, with placeholder bounds inheritance and per-paragraph alignment. DOCX improves explicit page breaks, retained page heights, table column ratios and explicit font toggles. XLSX improves general alignment, shrink-to-fit, image anchors/cropping and asynchronous sheet replacement. Image decoding is limited to two concurrent workers; obsolete page jobs are canceled. Native controls and text layout are still created on the UI thread in batches.
实现继续参考本地 vue-office-core 的 DOCX 包装层、ExcelJS 转换与图片锚点逻辑,以及 PPTX 使用的 pptx-preview 思路。列宽和图片裁剪同时参考 Open XML 列宽说明 和 DrawingML srcRect 说明。列宽当前按 Calibri 11 的最大数字宽度进行换算,其他默认字体可能存在差异。复杂形状、图表、自动分页及字体替换仍不保证与 Office/WPS 完全一致。
The implementation continues to reference vue-office-core and its underlying preview libraries, supplemented by the Open XML column-width and DrawingML source-rectangle specifications linked above. Column widths currently use the Calibri 11 maximum-digit-width fallback; other Normal fonts can differ. Complex shapes/charts, automatic pagination and font substitution are not guaranteed to match Office/WPS exactly.
回归检查 / Regression checks:
dotnet run --project tests/OfficeViewer.Regression -c Release
回归包含 Avalonia 原始触摸事件、解析/渲染断言、快速切表、取消加载和样例滚动检查;桌面测试不能替代 Android 真机验证。
Checks cover raw Avalonia touch input, parser/render assertions, rapid sheet switching, canceled loads and sample scrolling. Desktop tests do not replace Android device validation.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
修复单指滚动与双指缩放切换;改进 PPTX 层级、裁剪与版式继承,DOCX 分页和表格列宽,XLSX 图片锚点、对齐与异步切表;取消离屏任务并限制图片解码并发。Fix touch pan/pinch transitions; improve PPTX paint order, cropping and layout inheritance, DOCX breaks and table widths, and XLSX anchors, alignment and async sheet switching; cancel offscreen work and bound image decoding.