xaf-office

SKILL.md

XAF: Office / Document Management Modules

Available Modules

Module Class File Type Platforms
File Attachments FileAttachmentsModule any file Blazor, WinForms
Spreadsheet SpreadsheetModule .xlsx Blazor, WinForms
Rich Text RichTextModule .docx, .rtf Blazor, WinForms
PDF Viewer PdfViewerModule .pdf Blazor, WinForms

File Attachments Module

NuGet Packages

<PackageReference Include="DevExpress.ExpressApp.FileAttachments" Version="25.1.*" />
<PackageReference Include="DevExpress.ExpressApp.FileAttachments.Blazor" Version="25.1.*" />
<!-- or for WinForms: -->
<PackageReference Include="DevExpress.ExpressApp.FileAttachments.Win" Version="25.1.*" />

Setup

// Module:
RequiredModuleTypes.Add(typeof(FileAttachmentsModule));

// Blazor Program.cs:
b.AddModule<FileAttachmentsModule>();
b.AddModule<FileAttachmentsBlazorModule>();

IFileData Interface

public interface IFileData {
    string FileName { get; set; }
    int Size { get; }
    void LoadFromStream(string fileName, Stream stream);
    void SaveToStream(Stream stream);
}

XPO Pattern — Single File Attachment

// Option 1: Built-in FileData (recommended)
using DevExpress.Persistent.BaseImpl;

public class Document : BaseObject {
    public Document(Session session) : base(session) { }

    private FileData attachment;
    [Aggregated]
    public FileData Attachment {
        get => attachment;
        set => SetPropertyValue(nameof(Attachment), ref attachment, value);
    }

    // EditorAlias auto-detected from IFileData
}

EF Core Pattern — Single File Attachment

using DevExpress.Persistent.BaseImpl.EF;

public class Document : BaseObject {
    // FileAttachment is the EF Core equivalent of FileData
    public virtual FileAttachment Attachment { get; set; }
}

// DbContext:
public DbSet<FileAttachment> FileAttachments { get; set; }

XPO Pattern — Multiple File Attachments (Collection)

public class Employee : BaseObject {
    public Employee(Session session) : base(session) { }

    [Aggregated]
    [Association("Employee-Documents")]
    public XPCollection<FileData> Documents => GetCollection<FileData>(nameof(Documents));
}

EF Core Pattern — Multiple Files

public class Employee : BaseObject {
    public virtual IList<FileAttachment> Documents { get; set; }
        = new ObservableCollection<FileAttachment>();
}

Programmatic File Access

// Load from stream
var attachment = objectSpace.CreateObject<FileData>();
using (var stream = File.OpenRead("report.pdf")) {
    attachment.LoadFromStream("report.pdf", stream);
}
employee.Attachment = attachment;
objectSpace.CommitChanges();

// Save to stream
using (var stream = new MemoryStream()) {
    employee.Attachment.SaveToStream(stream);
    File.WriteAllBytes("output.pdf", stream.ToArray());
}

Spreadsheet Module

Setup

<PackageReference Include="DevExpress.ExpressApp.Spreadsheet" Version="25.1.*" />
<PackageReference Include="DevExpress.ExpressApp.Spreadsheet.Blazor" Version="25.1.*" />
b.AddModule<SpreadsheetModule>();
b.AddModule<SpreadsheetBlazorModule>();

Business Object with Embedded Spreadsheet

// XPO
public class Budget : BaseObject {
    public Budget(Session session) : base(session) { }

    // Store spreadsheet as byte array
    private byte[] spreadsheetData;
    [EditorAlias("SpreadsheetPropertyEditor")]
    [Size(SizeAttribute.Unlimited)]
    public byte[] SpreadsheetData {
        get => spreadsheetData;
        set => SetPropertyValue(nameof(SpreadsheetData), ref spreadsheetData, value);
    }
}

// EF Core
public class Budget : BaseObject {
    [EditorAlias("SpreadsheetPropertyEditor")]
    public virtual byte[] SpreadsheetData { get; set; }
}

Programmatic Spreadsheet Manipulation

using DevExpress.Spreadsheet;

// Read spreadsheet data from XAF object
byte[] data = budget.SpreadsheetData;
using var workbook = new Workbook();
using var stream = new MemoryStream(data);
workbook.LoadDocument(stream, DocumentFormat.Xlsx);

var sheet = workbook.Worksheets[0];
sheet.Cells["B2"].Value = 1234.56;
sheet.Cells["B3"].Formula = "=B2*1.23";

// Save back
using var outputStream = new MemoryStream();
workbook.SaveDocument(outputStream, DocumentFormat.Xlsx);
budget.SpreadsheetData = outputStream.ToArray();
objectSpace.CommitChanges();

Rich Text Module

Setup

<PackageReference Include="DevExpress.ExpressApp.RichTextEdit" Version="25.1.*" />
<PackageReference Include="DevExpress.ExpressApp.RichTextEdit.Blazor" Version="25.1.*" />
b.AddModule<RichTextEditModule>();
b.AddModule<RichTextEditBlazorModule>();

Business Object with Rich Text

// XPO
public class Article : BaseObject {
    public Article(Session session) : base(session) { }

    private byte[] content;
    [EditorAlias("RichTextPropertyEditor")]
    [Size(SizeAttribute.Unlimited)]
    public byte[] Content {
        get => content;
        set => SetPropertyValue(nameof(Content), ref content, value);
    }
}

// EF Core
public class Article : BaseObject {
    [EditorAlias("RichTextPropertyEditor")]
    public virtual byte[] Content { get; set; }
}

Mail Merge

using DevExpress.XtraRichEdit;
using DevExpress.XtraRichEdit.API.Native;

// Load template from byte[] stored in XAF object
using var server = new RichEditDocumentServer();
using var templateStream = new MemoryStream(article.Content);
server.LoadDocument(templateStream, DocumentFormat.OpenXml);

// Execute mail merge
server.Document.MailMerge.DataSource = contacts; // your data list
server.Document.MailMerge.Execute();

// Export result
using var outputStream = new MemoryStream();
server.SaveDocument(outputStream, DocumentFormat.OpenXml);
var mergedBytes = outputStream.ToArray();

PDF Viewer Module

Setup

<PackageReference Include="DevExpress.ExpressApp.PdfViewer" Version="25.1.*" />
<PackageReference Include="DevExpress.ExpressApp.PdfViewer.Blazor" Version="25.1.*" />
b.AddModule<PdfViewerModule>();
b.AddModule<PdfViewerBlazorModule>();

Business Object with PDF

// XPO
public class Contract : BaseObject {
    public Contract(Session session) : base(session) { }

    private byte[] pdfContent;
    [EditorAlias("PdfViewerPropertyEditor")]
    [Size(SizeAttribute.Unlimited)]
    public byte[] PdfContent {
        get => pdfContent;
        set => SetPropertyValue(nameof(PdfContent), ref pdfContent, value);
    }
}

Blazor vs WinForms Differences

Feature Blazor WinForms
File upload DxUpload component OpenFileDialog
Spreadsheet editor Browser-based DevExpress Spreadsheet XtraSpreadsheet (Win control)
Rich text editor Browser-based Rich Text editor XtraRichEdit (Win control)
PDF viewer Browser-based PDF viewer XtraPdfViewer (Win control)
Module class *BlazorModule *WindowsFormsModule

Auto-Added Document Actions

When an Office module property is present in Detail View, XAF automatically adds:

  • Save (document) action
  • Export / Print action (module-dependent)
  • Load (from file) action

No extra controller code needed for basic file operations.


Source Links

Weekly Installs
5
GitHub Stars
2
First Seen
4 days ago
Installed on
opencode5
gemini-cli5
claude-code5
github-copilot5
codex5
amp5