Note注意

重要说明: .NET Client Profile Framework 不支持此功能。 要在最终用户的机器上使用此功能,则必须安装完整的 .NET Framework。 更多信息,请参阅 Windows 窗体部署 文档中的 关于 .NET Framework 4.0 Client Profile 的重要说明 小节。

CodeCentralShow Me

在 DevExpress Code Central 数据库中可以找到完整的示例项目,网址是 http://www.devexpress.com/example=E2704。 取决于目标平台类型 (ASP.NET、WinForms 等),可以在线运行本示例,或者下载自动可执行的示例。

下面的示例演示了如何实现报表存储器,来把报表持久化到数据库中或任何其他自定义位置中。 这可能是有用的,当为最终用户提供使用 XtraReports 最终用户设计器 来创建和定制报表的功能、并且需要有保存和共享所有报表的公共目标时。

要完成此任务,需要创建一个继承自 ReportStorageExtension 基本类的自定义报表存储器,并实现所有必需的功能。 然后可以通过调用 ReportStorageExtension.RegisterExtensionGlobal 静态方法来启用此存储器。

这个示例展示了如何实现下列类型的自定义报表存储器:

C#CopyCode image复制代码
 (StorageDataSet.cs)
namespace ReportStorageSample {
}

C#CopyCode image复制代码
 (Form1.cs)
using System;
using System.IO;
using System.Windows.Forms;
using DevExpress.XtraReports.UserDesigner;
using DevExpress.XtraReports.UI;
// ...

namespace ReportStorageSample {
    public partial class Form1 : Form {
        public Form1() {
            InitializeComponent();
        }

        private void buttonDesign_Click(object sender, EventArgs e) {
            XRDesignForm form = new XRDesignForm();
            string url = GetSelectedUrl();
            if (!string.IsNullOrEmpty(url))
                form.OpenReport(url);
            form.ShowDialog(this);

            object selectedItem = listBox1.SelectedItem;
            FillListBox();
            if (selectedItem != null && listBox1.Items.Contains(selectedItem))
                listBox1.SelectedItem = selectedItem;
        }

        private void buttonPreview_Click(object sender, EventArgs e) {
            XtraReport report = GetSelectedReport();
            if (report != null)
                report.ShowPreviewDialog();
        }
        string GetSelectedUrl() {
            return listBox1.SelectedItem as string;
        }
        XtraReport GetSelectedReport() {
            string url = GetSelectedUrl();
            if (string.IsNullOrEmpty(url))
                return null;
            using (MemoryStream stream = new MemoryStream(Program.ReportStorage.GetData(url))) {
                return XtraReport.FromStream(stream, true);
            }
        }
        private void Form1_Load(object sender, EventArgs e) {
            FillListBox();
            if (listBox1.Items.Count > 0)
                listBox1.SelectedIndex = 0;
        }
        void FillListBox() {
            listBox1.Items.Clear();
            string[] urls = Program.ReportStorage.GetStandardUrls(null);
            foreach (string url in urls) {
                listBox1.Items.Add(url);
            }
        }
        private void listBox1_SelectedIndexChanged(object sender, EventArgs e) {
            buttonPreview.Enabled = listBox1.SelectedItem != null;
        }
    }
}
C#CopyCode image复制代码
 (DataSetReportStorage.cs)
using System;
using System.IO;
using System.Data;
using System.Windows.Forms;
using System.ComponentModel;
using System.Collections.Generic;
using DevExpress.XtraReports.UI;
using DevExpress.XtraReports.Extensions;
// ...

namespace ReportStorageSample {
    class DataSetReportStorage : ReportStorageExtension {
        const string fileName = "ReportStorage.xml";
        StorageDataSet dataSet;
        public DataSetReportStorage() {
        }
        string StoragePath {
            get {
                string dirName = Path.GetDirectoryName(Application.ExecutablePath);
                return Path.Combine(dirName, fileName);
            }
        }
        StorageDataSet DataSet {
            get {
                if (dataSet == null) {
                    dataSet = new StorageDataSet();
                    if (File.Exists(StoragePath))
                        dataSet.ReadXml(StoragePath, XmlReadMode.ReadSchema);
                }
                return dataSet;
            }
        }
        StorageDataSet.ReportStorageDataTable ReportStorage {
            get {
                return DataSet.ReportStorage;
            }
        }

        public override bool CanSetData(string url) {
            return true;
        }
        public override bool IsValidUrl(string url) {
            return !string.IsNullOrEmpty(url);
        }
        public override byte[] GetData(string url) {
            StorageDataSet.ReportStorageRow row = FindRow(url);
            if (row != null)
                return row.Buffer;
            return new byte[] { };
        }
        StorageDataSet.ReportStorageRow FindRow(string url) {
            DataRow[] result = ReportStorage.Select(string.Format("Url = '{0}'", url));
            if (result.Length > 0)
                return result[0] as StorageDataSet.ReportStorageRow;
            return null;
        }
        public override void SetData(XtraReport report, string url) {
            StorageDataSet.ReportStorageRow row = FindRow(url);
            if (row != null)
                row.Buffer = GetBuffer(report);
            else {
                int id = ReportStorage.Rows.Count;
                report.Extensions["StorageID"] = id.ToString();
                row = ReportStorage.AddReportStorageRow(id, url, GetBuffer(report));
            }
            DataSet.WriteXml(StoragePath, XmlWriteMode.WriteSchema);
        }
        byte[] GetBuffer(XtraReport report) {
            using (MemoryStream stream = new MemoryStream()) {
                report.SaveLayout(stream);
                return stream.ToArray();
            }
        }
        public override string GetNewUrl() {
            StorageEditorForm form = CreateForm();
            form.textBox1.Enabled = false;
            if (form.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                return form.textBox1.Text;
            return string.Empty;
        }
        StorageEditorForm CreateForm() {
            StorageEditorForm form = new StorageEditorForm();
            foreach (string item in GetUrls())
                form.listBox1.Items.Add(item);
            return form;
        }
        public override string SetNewData(XtraReport report, string defaultUrl) {
            StorageEditorForm form = CreateForm();
            form.textBox1.Text = defaultUrl;
            form.listBox1.Enabled = false;
            if (form.ShowDialog() == DialogResult.OK) {
                string url = form.textBox1.Text;
                if (!string.IsNullOrEmpty(url) && !form.listBox1.Items.Contains(url)) {
                    TypeDescriptor.GetProperties(typeof(XtraReport))["DisplayName"].SetValue(report, url);
                    SetData(report, url);
                    return url;
                }
                else {
                    MessageBox.Show("Incorrect report name", "Error",
                        MessageBoxButtons.OKCancel, MessageBoxIcon.Error);
                }
            }
            return string.Empty;
        }
        public override bool GetStandardUrlsSupported(ITypeDescriptorContext context) {
            return true;
        }
        public override string[] GetStandardUrls(ITypeDescriptorContext context) {
            if (context != null && context.Instance is XRSubreport) {
                XRSubreport xrSubreport = context.Instance as XRSubreport;
                if (xrSubreport.RootReport !=
                    null && xrSubreport.RootReport.Extensions.TryGetValue("StorageID", out storageID)) {
                    List<string> result = GetUrlsCore(CanPassId);
                    return result.ToArray();
                }
            }
            return GetUrls();
        }
        string storageID;
        bool CanPassId(string id) {
            return id != storageID;
        }
        string[] GetUrls() {
            return GetUrlsCore(null).ToArray();
        }
        List<string> GetUrlsCore(Predicate<string> method) {
            List<string> list = new List<string>();
            foreach (StorageDataSet.ReportStorageRow row in ReportStorage.Rows)
                if (method == null || method(row.ID.ToString()))
                    list.Add(row.Url);
            return list;
        }
    }
}

C#CopyCode image复制代码
 (ZipReportStorage.cs)
using System;
using System.IO;
using System.Windows.Forms;
using System.ComponentModel;
using System.IO.Compression;
using System.Collections.Generic;
using DevExpress.Xpo;
using DevExpress.Data.Filtering;
using DevExpress.XtraReports.UI;
using DevExpress.XtraReports.Extensions;
using DevExpress.Utils.Zip;
// ...

namespace ReportStorageSample {
    class ZipReportStorage : ReportStorageExtension {
        class ZipFilesHelper : IDisposable {
            Stream stream;
            ZipFileCollection zipFiles = new ZipFileCollection();
            public ZipFileCollection ZipFiles {
                get {
                    return zipFiles;
                }
            }
            public ZipFilesHelper(string path) {
                if (File.Exists(path)) {
                    stream = File.OpenRead(path);
                    zipFiles = ZipArchive.Open(stream);
                }
            }
            public virtual void Dispose() {
                if (stream != null)
                    stream.Dispose();
            }
        }
        const string fileName = "ReportStorage.zip";
        public ZipReportStorage() {
        }
        string StoragePath {
            get {
                string dirName = Path.GetDirectoryName(Application.ExecutablePath);
                return Path.Combine(dirName, fileName);
            }
        }
        public override bool CanSetData(string url) {
            return true;
        }
        public override bool IsValidUrl(string url) {
            return !string.IsNullOrEmpty(url);
        }
        public override byte[] GetData(string url) {
            using (ZipFilesHelper helper = new ZipFilesHelper(StoragePath)) {
                ZipFile zipFile = GetZipFile(helper.ZipFiles, url);
                if (zipFile != null)
                    return GetBytes(zipFile);
                return new byte[] { };
            }
        }
        static byte[] GetBytes(ZipFile zipFile) {
            return GetBytes(zipFile.FileDataStream, (int)zipFile.UncompressedSize);
        }
        static byte[] GetBytes(Stream stream, int length) {
            byte[] result = new byte[length];
            stream.Read(result, 0, result.Length);
            return result;
        }
        static ZipFile GetZipFile(ZipFileCollection zipFiles, string url) {
            foreach (ZipFile item in zipFiles) {
                if (StringsEgual(item.FileName, url))
                    return item;
            }
            return null;
        }
        static bool StringsEgual(string a, string b) {
            return string.Equals(a, b, StringComparison.OrdinalIgnoreCase);
        }
        public override void SetData(XtraReport report, string url) {
            report.Extensions["StorageID"] = url;
            SaveArchive(url, GetBuffer(report));
        }
        void SaveArchive(string url, byte[] buffer) {
            string tempPath = Path.ChangeExtension(StoragePath, "tmp");
            using (ZipArchive arch = new ZipArchive(tempPath)) {
                using (ZipFilesHelper helper = new ZipFilesHelper(StoragePath)) {
                    bool added = false;
                    foreach (ZipFile item in helper.ZipFiles) {
                        if (StringsEgual(item.FileName, url)) {
                            arch.Add(item.FileName, DateTime.Now, buffer);
                            added = true;
                        }
                        else
                            arch.Add(item.FileName, DateTime.Now, GetBytes(item));
                    }
                    if (!added)
                        arch.Add(url, DateTime.Now, buffer);
                }
            }
            if (File.Exists(StoragePath))
                File.Delete(StoragePath);
            File.Move(tempPath, StoragePath);
        }
        byte[] GetBuffer(XtraReport report) {
            using (MemoryStream stream = new MemoryStream()) {
                report.SaveLayout(stream);
                return stream.ToArray();
            }
        }
        public override string GetNewUrl() {
            StorageEditorForm form = CreateForm();
            form.textBox1.Enabled = false;
            if (form.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                return form.textBox1.Text;
            return string.Empty;
        }
        StorageEditorForm CreateForm() {
            StorageEditorForm form = new StorageEditorForm();
            foreach (string item in GetUrls())
                form.listBox1.Items.Add(item);
            return form;
        }
        public override string SetNewData(XtraReport report, string defaultUrl) {
            StorageEditorForm form = CreateForm();
            form.textBox1.Text = defaultUrl;
            form.listBox1.Enabled = false;
            if (form.ShowDialog() == DialogResult.OK) {
                string url = form.textBox1.Text;
                if (!string.IsNullOrEmpty(url) && !form.listBox1.Items.Contains(url)) {
                    TypeDescriptor.GetProperties(typeof(XtraReport))["DisplayName"].SetValue(report, url);
                    SetData(report, url);
                    return url;
                }
                else {
                    MessageBox.Show("Incorrect report name", "Error",
                        MessageBoxButtons.OKCancel, MessageBoxIcon.Error);
                }
            }
            return string.Empty;
        }
        public override bool GetStandardUrlsSupported(ITypeDescriptorContext context) {
            return true;
        }
        public override string[] GetStandardUrls(ITypeDescriptorContext context) {
            if (context != null && context.Instance is XRSubreport) {
                XRSubreport xrSubreport = context.Instance as XRSubreport;
                if (xrSubreport.RootReport !=
                    null && xrSubreport.RootReport.Extensions.TryGetValue("StorageID", out storageID)) {
                    List<string> result = GetUrlsCore(CanPassId);
                    return result.ToArray();
                }
            }
            return GetUrls();
        }
        string storageID;
        bool CanPassId(string id) {
            return id != storageID;
        }
        string[] GetUrls() {
            return GetUrlsCore(null).ToArray();
        }
        List<string> GetUrlsCore(Predicate<string> method) {
            List<string> list = new List<string>();
            using (ZipFilesHelper helper = new ZipFilesHelper(StoragePath)) {
                foreach (ZipFile item in helper.ZipFiles)
                    if (method == null || method(item.FileName))
                        list.Add(item.FileName);
                return list;
            }
        }
    }
}

C#CopyCode image复制代码
 (Program.cs)
using System;
using System.Windows.Forms;
using DevExpress.Xpo;
using DevExpress.XtraReports.Extensions;
// ...

namespace ReportStorageSample {
    static class Program {
        static ReportStorageExtension reportStorage;
        public static ReportStorageExtension ReportStorage {
            get {
                return reportStorage;
            }
        }

        [STAThread]
        static void Main() {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            // This code registers a report storage that uses System.DataSet.
            reportStorage = new DataSetReportStorage();

            // Uncomment this line to register a report storage that uses XPO.
            // reportStorage = new XpoReportStorage(new UnitOfWork());

            // Uncomment this line to register a report storage, which uses XPO.
            // reportStorage = new ZipReportStorage();


            ReportStorageExtension.RegisterExtensionGlobal(reportStorage);
            Application.Run(new Form1());
        }
    }
}
C#CopyCode image复制代码
 (XpoReportStorage.cs)
using System;
using System.IO;
using System.Windows.Forms;
using System.ComponentModel;
using System.Collections.Generic;
using DevExpress.Xpo;
using DevExpress.Data.Filtering;
using DevExpress.XtraReports.UI;
using DevExpress.XtraReports.Extensions;
// ...

namespace ReportStorageSample {
    class XpoReportStorage : ReportStorageExtension {
        XPCollection<StorageItem> items;
        UnitOfWork Session {
            get { return (UnitOfWork)items.Session; }
        }
        public StorageItem FindItem(string name) {
            return Session.FindObject<StorageItem>(new BinaryOperator("Url", name));
        }
        public XPCollection<StorageItem> Items {
            get { return items; }
        }
        public XpoReportStorage(UnitOfWork session) {
            items = new XPCollection<StorageItem>(session);
        }

        public override bool CanSetData(string url) {
            return true;
        }
        public override bool IsValidUrl(string url) {
            return !string.IsNullOrEmpty(url);
        }
        public override byte[] GetData(string url) {
            StorageItem item = FindItem(url);
            if (item != null)
                return item.Layout;
            return new byte[] { };
        }

        public override void SetData(XtraReport report, string url) {
            StorageItem item = FindItem(url);
            if (item != null)
                item.Layout = GetBuffer(report);
            else {
                item = new StorageItem(Session);
                item.Url = url;
                Session.CommitChanges();

                report.Extensions["StorageID"] = item.Oid.ToString();
                item.Layout = GetBuffer(report);
            }
            Session.CommitChanges();
            items.Reload();
        }
        byte[] GetBuffer(XtraReport report) {
            using (MemoryStream stream = new MemoryStream()) {
                report.SaveLayout(stream);
                return stream.ToArray();
            }
        }
        public override string GetNewUrl() {
            StorageEditorForm form = CreateForm();
            form.textBox1.Enabled = false;
            if (form.ShowDialog() == DialogResult.OK)
                return form.textBox1.Text;
            return string.Empty;
        }
        StorageEditorForm CreateForm() {
            StorageEditorForm form = new StorageEditorForm();
            foreach (string item in GetUrls())
                form.listBox1.Items.Add(item);
            return form;
        }
        public override string SetNewData(XtraReport report, string defaultUrl) {
            StorageEditorForm form = CreateForm();
            form.textBox1.Text = defaultUrl;
            form.listBox1.Enabled = false;
            if (form.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
                string url = form.textBox1.Text;
                if (!string.IsNullOrEmpty(url) && !form.listBox1.Items.Contains(url)) {
                    TypeDescriptor.GetProperties(typeof(XtraReport))["DisplayName"].SetValue(report, url);
                    SetData(report, url);
                    return url;
                }
                else {
                    MessageBox.Show("Incorrect report name", "Error",
                        MessageBoxButtons.OKCancel, MessageBoxIcon.Error);
                }
            }
            return string.Empty;
        }
        public override bool GetStandardUrlsSupported(ITypeDescriptorContext context) {
            return true;
        }
        public override string[] GetStandardUrls(ITypeDescriptorContext context) {
            if (context != null && context.Instance is XRSubreport) {
                XRSubreport xrSubreport = context.Instance as XRSubreport;
                if (xrSubreport.RootReport !=
                    null && xrSubreport.RootReport.Extensions.TryGetValue("StorageID", out storageID)) {
                    List<string> result = GetUrlsCore(CanPassId);
                    return result.ToArray();
                }
            }
            return GetUrls();
        }
        string storageID;
        bool CanPassId(string id) {
            return id != storageID;
        }
        string[] GetUrls() {
            return GetUrlsCore(null).ToArray();
        }
        List<string> GetUrlsCore(Predicate<string> method) {
            List<string> list = new List<string>();
            foreach (StorageItem item in Items)
                if (method == null || method(item.Oid.ToString()))
                    list.Add(item.Url);
            return list;
        }
    }
    public class StorageItem : XPObject {
        string url;
        byte[] layout = null;
        public string Url {
            get { return url; }
            set { SetPropertyValue("Url", ref url, value); }
        }
        public byte[] Layout {
            get { return layout; }
            set { SetPropertyValue("Layout", ref layout, value); }
        }
        public StorageItem(Session session)
            : base(session) {
        }
    }
}

C#CopyCode image复制代码
 (StorageEditorForm.cs)
using System;
using System.Windows.Forms;
// ...

namespace ReportStorageSample {
    public partial class StorageEditorForm : Form {
        public StorageEditorForm() {
            InitializeComponent();
        }

        private void listBox1_SelectedIndexChanged(object sender, EventArgs e) {
            textBox1.Text = listBox1.SelectedItem.ToString();
        }

        private void StorageEditorForm_Load(object sender, EventArgs e) {
            if (listBox1.Items.Count > 0 && string.IsNullOrEmpty(textBox1.Text))
                listBox1.SelectedIndex = 0;
        }

        private void textBox1_TextChanged(object sender, EventArgs e) {
            buttonOK.Enabled = !string.IsNullOrEmpty(textBox1.Text);
        }

        private void buttonOK_Click(object sender, EventArgs e) {

        }
    }
}
Visual BasicCopyCode image复制代码
 (ZipReportStorage.vb)
Imports Microsoft.VisualBasic
Imports System
Imports System.IO
Imports System.Windows.Forms
Imports System.ComponentModel
Imports System.IO.Compression
Imports System.Collections.Generic
Imports DevExpress.Xpo
Imports DevExpress.Data.Filtering
Imports DevExpress.XtraReports.UI
Imports DevExpress.XtraReports.Extensions
Imports DevExpress.Utils.Zip
' ...

Namespace ReportStorageSample
    Friend Class ZipReportStorage
        Inherits ReportStorageExtension
        Private Class ZipFilesHelper
            Implements IDisposable
            Private stream As Stream
            Private zipFiles_Renamed As New ZipFileCollection()
            Public ReadOnly Property ZipFiles() As ZipFileCollection
                Get
                    Return zipFiles_Renamed
                End Get
            End Property
            Public Sub New(ByVal path As String)
                If File.Exists(path) Then
                    stream = File.OpenRead(path)
                    zipFiles_Renamed = ZipArchive.Open(stream)
                End If
            End Sub
            Public Overridable Sub Dispose() Implements IDisposable.Dispose
                If stream IsNot Nothing Then
                    stream.Dispose()
                End If
            End Sub
        End Class
        Private Const fileName As String = "ReportStorage.zip"
        Public Sub New()
        End Sub
        Private ReadOnly Property StoragePath() As String
            Get
                Dim dirName As String = Path.GetDirectoryName(Application.ExecutablePath)
                Return Path.Combine(dirName, fileName)
            End Get
        End Property
        Public Overrides Function CanSetData(ByVal url As String) As Boolean
            Return True
        End Function
        Public Overrides Function IsValidUrl(ByVal url As String) As Boolean
            Return Not String.IsNullOrEmpty(url)
        End Function
        Public Overrides Function GetData(ByVal url As String) As Byte()
            Using helper As New ZipFilesHelper(StoragePath)
                Dim zipFile As ZipFile = GetZipFile(helper.ZipFiles, url)
                If zipFile IsNot Nothing Then
                    Return GetBytes(zipFile)
                End If
                Return New Byte() { }
            End Using
        End Function
        Private Shared Function GetBytes(ByVal zipFile As ZipFile) As Byte()
            Return GetBytes(zipFile.FileDataStream, CInt(Fix(zipFile.UncompressedSize)))
        End Function
        Private Shared Function GetBytes(ByVal stream As Stream, ByVal length As Integer) As Byte()
            Dim result(length - 1) As Byte
            stream.Read(result, 0, result.Length)
            Return result
        End Function
        Private Shared Function GetZipFile(ByVal zipFiles As ZipFileCollection, ByVal url As String) As ZipFile
            For Each item As ZipFile In zipFiles
                If StringsEgual(item.FileName, url) Then
                    Return item
                End If
            Next item
            Return Nothing
        End Function
        Private Shared Function StringsEgual(ByVal a As String, ByVal b As String) As Boolean
            Return String.Equals(a, b, StringComparison.OrdinalIgnoreCase)
        End Function
        Public Overrides Sub SetData(ByVal report As XtraReport, ByVal url As String)
            report.Extensions("StorageID") = url
            SaveArchive(url, GetBuffer(report))
        End Sub
        Private Sub SaveArchive(ByVal url As String, ByVal buffer() As Byte)
            Dim tempPath As String = Path.ChangeExtension(StoragePath, "tmp")
            Using arch As New ZipArchive(tempPath)
                Using helper As New ZipFilesHelper(StoragePath)
                    Dim added As Boolean = False
                    For Each item As ZipFile In helper.ZipFiles
                        If StringsEgual(item.FileName, url) Then
                            arch.Add(item.FileName, DateTime.Now, buffer)
                            added = True
                        Else
                            arch.Add(item.FileName, DateTime.Now, GetBytes(item))
                        End If
                    Next item
                    If (Not added) Then
                        arch.Add(url, DateTime.Now, buffer)
                    End If
                End Using
            End Using
            If File.Exists(StoragePath) Then
                File.Delete(StoragePath)
            End If
            File.Move(tempPath, StoragePath)
        End Sub
        Private Function GetBuffer(ByVal report As XtraReport) As Byte()
            Using stream As New MemoryStream()
                report.SaveLayout(stream)
                Return stream.ToArray()
            End Using
        End Function
        Public Overrides Function GetNewUrl() As String
            Dim form As StorageEditorForm = CreateForm()
            form.textBox1.Enabled = False
            If form.ShowDialog() = System.Windows.Forms.DialogResult.OK Then
                Return form.textBox1.Text
            End If
            Return String.Empty
        End Function
        Private Function CreateForm() As StorageEditorForm
            Dim form As New StorageEditorForm()
            For Each item As String In GetUrls()
                form.listBox1.Items.Add(item)
            Next item
            Return form
        End Function
        Public Overrides Function SetNewData(ByVal report As XtraReport, ByVal defaultUrl As String) As String
            Dim form As StorageEditorForm = CreateForm()
            form.textBox1.Text = defaultUrl
            form.listBox1.Enabled = False
            If form.ShowDialog() = DialogResult.OK Then
                Dim url As String = form.textBox1.Text
                If (Not String.IsNullOrEmpty(url)) AndAlso (Not form.listBox1.Items.Contains(url)) Then
                    TypeDescriptor.GetProperties(GetType(XtraReport))("DisplayName").SetValue(report, url)
                    SetData(report, url)
                    Return url
                Else
                    MessageBox.Show("Incorrect report name", "Error", MessageBoxButtons.OKCancel, MessageBoxIcon.Error)
                End If
            End If
            Return String.Empty
        End Function
        Public Overrides Function GetStandardUrlsSupported(ByVal context As ITypeDescriptorContext) As Boolean
            Return True
        End Function
        Public Overrides Function GetStandardUrls(ByVal context As ITypeDescriptorContext) As String()
            If context IsNot Nothing AndAlso TypeOf context.Instance Is XRSubreport Then
                Dim xrSubreport As XRSubreport = TryCast(context.Instance, XRSubreport)
                If xrSubreport.RootReport IsNot Nothing AndAlso xrSubreport.RootReport.Extensions.TryGetValue("StorageID", storageID) Then
                    Dim result As List(Of String) = GetUrlsCore(AddressOf CanPassId)
                    Return result.ToArray()
                End If
            End If
            Return GetUrls()
        End Function
        Private storageID As String
        Private Function CanPassId(ByVal id As String) As Boolean
            Return id <> storageID
        End Function
        Private Function GetUrls() As String()
            Return GetUrlsCore(Nothing).ToArray()
        End Function
        Private Function GetUrlsCore(ByVal method As Predicate(Of String)) As List(Of String)
            Dim list As New List(Of String)()
            Using helper As New ZipFilesHelper(StoragePath)
                For Each item As ZipFile In helper.ZipFiles
                    If method Is Nothing OrElse method(item.FileName) Then
                        list.Add(item.FileName)
                    End If
                Next item
                Return list
            End Using
        End Function
    End Class
End Namespace

Visual BasicCopyCode image复制代码
 (StorageEditorForm.vb)
Imports Microsoft.VisualBasic
Imports System
Imports System.Windows.Forms
' ...

Namespace ReportStorageSample
    Partial Public Class StorageEditorForm
        Inherits Form
        Public Sub New()
            InitializeComponent()
        End Sub

        Private Sub listBox1_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs) Handles listBox1.SelectedIndexChanged
            textBox1.Text = listBox1.SelectedItem.ToString()
        End Sub

        Private Sub StorageEditorForm_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
            If listBox1.Items.Count > 0 AndAlso String.IsNullOrEmpty(textBox1.Text) Then
                listBox1.SelectedIndex = 0
            End If
        End Sub

        Private Sub textBox1_TextChanged(ByVal sender As Object, ByVal e As EventArgs) Handles textBox1.TextChanged
            buttonOK.Enabled = Not String.IsNullOrEmpty(textBox1.Text)
        End Sub

        Private Sub buttonOK_Click(ByVal sender As Object, ByVal e As EventArgs) Handles buttonOK.Click

        End Sub
    End Class
End Namespace
Visual BasicCopyCode image复制代码
 (DataSetReportStorage.vb)
Imports Microsoft.VisualBasic
Imports System
Imports System.IO
Imports System.Data
Imports System.Windows.Forms
Imports System.ComponentModel
Imports System.Collections.Generic
Imports DevExpress.XtraReports.UI
Imports DevExpress.XtraReports.Extensions
' ...

Namespace ReportStorageSample
    Friend Class DataSetReportStorage
        Inherits ReportStorageExtension
        Private Const fileName As String = "ReportStorage.xml"
        Private dataSet_Renamed As StorageDataSet
        Public Sub New()
        End Sub
        Private ReadOnly Property StoragePath() As String
            Get
                Dim dirName As String = Path.GetDirectoryName(Application.ExecutablePath)
                Return Path.Combine(dirName, fileName)
            End Get
        End Property
        Private ReadOnly Property DataSet() As StorageDataSet
            Get
                If dataSet_Renamed Is Nothing Then
                    dataSet_Renamed = New StorageDataSet()
                    If File.Exists(StoragePath) Then
                        dataSet_Renamed.ReadXml(StoragePath, XmlReadMode.ReadSchema)
                    End If
                End If
                Return dataSet_Renamed
            End Get
        End Property
        Private ReadOnly Property ReportStorage() As StorageDataSet.ReportStorageDataTable
            Get
                Return DataSet.ReportStorage
            End Get
        End Property

        Public Overrides Function CanSetData(ByVal url As String) As Boolean
            Return True
        End Function
        Public Overrides Function IsValidUrl(ByVal url As String) As Boolean
            Return Not String.IsNullOrEmpty(url)
        End Function
        Public Overrides Function GetData(ByVal url As String) As Byte()
            Dim row As StorageDataSet.ReportStorageRow = FindRow(url)
            If row IsNot Nothing Then
                Return row.Buffer
            End If
            Return New Byte() { }
        End Function
        Private Function FindRow(ByVal url As String) As StorageDataSet.ReportStorageRow
            Dim result() As DataRow = ReportStorage.Select(String.Format("Url = '{0}'", url))
            If result.Length > 0 Then
                Return TryCast(result(0), StorageDataSet.ReportStorageRow)
            End If
            Return Nothing
        End Function
        Public Overrides Sub SetData(ByVal report As XtraReport, ByVal url As String)
            Dim row As StorageDataSet.ReportStorageRow = FindRow(url)
            If row IsNot Nothing Then
                row.Buffer = GetBuffer(report)
            Else
                Dim id As Integer = ReportStorage.Rows.Count
                report.Extensions("StorageID") = id.ToString()
                row = ReportStorage.AddReportStorageRow(id, url, GetBuffer(report))
            End If
            DataSet.WriteXml(StoragePath, XmlWriteMode.WriteSchema)
        End Sub
        Private Function GetBuffer(ByVal report As XtraReport) As Byte()
            Using stream As New MemoryStream()
                report.SaveLayout(stream)
                Return stream.ToArray()
            End Using
        End Function
        Public Overrides Function GetNewUrl() As String
            Dim form As StorageEditorForm = CreateForm()
            form.textBox1.Enabled = False
            If form.ShowDialog() = System.Windows.Forms.DialogResult.OK Then
                Return form.textBox1.Text
            End If
            Return String.Empty
        End Function
        Private Function CreateForm() As StorageEditorForm
            Dim form As New StorageEditorForm()
            For Each item As String In GetUrls()
                form.listBox1.Items.Add(item)
            Next item
            Return form
        End Function
        Public Overrides Function SetNewData(ByVal report As XtraReport, ByVal defaultUrl As String) As String
            Dim form As StorageEditorForm = CreateForm()
            form.textBox1.Text = defaultUrl
            form.listBox1.Enabled = False
            If form.ShowDialog() = DialogResult.OK Then
                Dim url As String = form.textBox1.Text
                If (Not String.IsNullOrEmpty(url)) AndAlso (Not form.listBox1.Items.Contains(url)) Then
                    TypeDescriptor.GetProperties(GetType(XtraReport))("DisplayName").SetValue(report, url)
                    SetData(report, url)
                    Return url
                Else
                    MessageBox.Show("Incorrect report name", "Error", MessageBoxButtons.OKCancel, MessageBoxIcon.Error)
                End If
            End If
            Return String.Empty
        End Function
        Public Overrides Function GetStandardUrlsSupported(ByVal context As ITypeDescriptorContext) As Boolean
            Return True
        End Function
        Public Overrides Function GetStandardUrls(ByVal context As ITypeDescriptorContext) As String()
            If context IsNot Nothing AndAlso TypeOf context.Instance Is XRSubreport Then
                Dim xrSubreport As XRSubreport = TryCast(context.Instance, XRSubreport)
                If xrSubreport.RootReport IsNot Nothing AndAlso xrSubreport.RootReport.Extensions.TryGetValue("StorageID", storageID) Then
                    Dim result As List(Of String) = GetUrlsCore(AddressOf CanPassId)
                    Return result.ToArray()
                End If
            End If
            Return GetUrls()
        End Function
        Private storageID As String
        Private Function CanPassId(ByVal id As String) As Boolean
            Return id <> storageID
        End Function
        Private Function GetUrls() As String()
            Return GetUrlsCore(Nothing).ToArray()
        End Function
        Private Function GetUrlsCore(ByVal method As Predicate(Of String)) As List(Of String)
            Dim list As New List(Of String)()
            For Each row As StorageDataSet.ReportStorageRow In ReportStorage.Rows
                If method Is Nothing OrElse method(row.ID.ToString()) Then
                    list.Add(row.Url)
                End If
            Next row
            Return list
        End Function
    End Class
End Namespace

Visual BasicCopyCode image复制代码
 (XpoReportStorage.vb)
Imports Microsoft.VisualBasic
Imports System
Imports System.IO
Imports System.Windows.Forms
Imports System.ComponentModel
Imports System.Collections.Generic
Imports DevExpress.Xpo
Imports DevExpress.Data.Filtering
Imports DevExpress.XtraReports.UI
Imports DevExpress.XtraReports.Extensions
' ...

Namespace ReportStorageSample
    Friend Class XpoReportStorage
        Inherits ReportStorageExtension
        Private items_Renamed As XPCollection(Of StorageItem)
        Private ReadOnly Property Session() As UnitOfWork
            Get
                Return CType(items_Renamed.Session, UnitOfWork)
            End Get
        End Property
        Public Function FindItem(ByVal name As String) As StorageItem
            Return Session.FindObject(Of StorageItem)(New BinaryOperator("Url", name))
        End Function
        Public ReadOnly Property Items() As XPCollection(Of StorageItem)
            Get
                Return items_Renamed
            End Get
        End Property
        Public Sub New(ByVal session As UnitOfWork)
            items_Renamed = New XPCollection(Of StorageItem)(session)
        End Sub

        Public Overrides Function CanSetData(ByVal url As String) As Boolean
            Return True
        End Function
        Public Overrides Function IsValidUrl(ByVal url As String) As Boolean
            Return Not String.IsNullOrEmpty(url)
        End Function
        Public Overrides Function GetData(ByVal url As String) As Byte()
            Dim item As StorageItem = FindItem(url)
            If item IsNot Nothing Then
                Return item.Layout
            End If
            Return New Byte() { }
        End Function

        Public Overrides Sub SetData(ByVal report As XtraReport, ByVal url As String)
            Dim item As StorageItem = FindItem(url)
            If item IsNot Nothing Then
                item.Layout = GetBuffer(report)
            Else
                item = New StorageItem(Session)
                item.Url = url
                Session.CommitChanges()

                report.Extensions("StorageID") = item.Oid.ToString()
                item.Layout = GetBuffer(report)
            End If
            Session.CommitChanges()
            items_Renamed.Reload()
        End Sub
        Private Function GetBuffer(ByVal report As XtraReport) As Byte()
            Using stream As New MemoryStream()
                report.SaveLayout(stream)
                Return stream.ToArray()
            End Using
        End Function
        Public Overrides Function GetNewUrl() As String
            Dim form As StorageEditorForm = CreateForm()
            form.textBox1.Enabled = False
            If form.ShowDialog() = DialogResult.OK Then
                Return form.textBox1.Text
            End If
            Return String.Empty
        End Function
        Private Function CreateForm() As StorageEditorForm
            Dim form As New StorageEditorForm()
            For Each item As String In GetUrls()
                form.listBox1.Items.Add(item)
            Next item
            Return form
        End Function
        Public Overrides Function SetNewData(ByVal report As XtraReport, ByVal defaultUrl As String) As String
            Dim form As StorageEditorForm = CreateForm()
            form.textBox1.Text = defaultUrl
            form.listBox1.Enabled = False
            If form.ShowDialog() = System.Windows.Forms.DialogResult.OK Then
                Dim url As String = form.textBox1.Text
                If (Not String.IsNullOrEmpty(url)) AndAlso (Not form.listBox1.Items.Contains(url)) Then
                    TypeDescriptor.GetProperties(GetType(XtraReport))("DisplayName").SetValue(report, url)
                    SetData(report, url)
                    Return url
                Else
                    MessageBox.Show("Incorrect report name", "Error", MessageBoxButtons.OKCancel, MessageBoxIcon.Error)
                End If
            End If
            Return String.Empty
        End Function
        Public Overrides Function GetStandardUrlsSupported(ByVal context As ITypeDescriptorContext) As Boolean
            Return True
        End Function
        Public Overrides Function GetStandardUrls(ByVal context As ITypeDescriptorContext) As String()
            If context IsNot Nothing AndAlso TypeOf context.Instance Is XRSubreport Then
                Dim xrSubreport As XRSubreport = TryCast(context.Instance, XRSubreport)
                If xrSubreport.RootReport IsNot Nothing AndAlso xrSubreport.RootReport.Extensions.TryGetValue("StorageID", storageID) Then
                    Dim result As List(Of String) = GetUrlsCore(AddressOf CanPassId)
                    Return result.ToArray()
                End If
            End If
            Return GetUrls()
        End Function
        Private storageID As String
        Private Function CanPassId(ByVal id As String) As Boolean
            Return id <> storageID
        End Function
        Private Function GetUrls() As String()
            Return GetUrlsCore(Nothing).ToArray()
        End Function
        Private Function GetUrlsCore(ByVal method As Predicate(Of String)) As List(Of String)
            Dim list As New List(Of String)()
            For Each item As StorageItem In Items
                If method Is Nothing OrElse method(item.Oid.ToString()) Then
                    list.Add(item.Url)
                End If
            Next item
            Return list
        End Function
    End Class
    Public Class StorageItem
        Inherits XPObject
        Private url_Renamed As String
        Private layout_Renamed() As Byte = Nothing
        Public Property Url() As String
            Get
                Return url_Renamed
            End Get
            Set(ByVal value As String)
                SetPropertyValue("Url", url_Renamed, value)
            End Set
        End Property
        Public Property Layout() As Byte()
            Get
                Return layout_Renamed
            End Get
            Set(ByVal value As Byte())
                SetPropertyValue("Layout", layout_Renamed, value)
            End Set
        End Property
        Public Sub New(ByVal session As Session)
            MyBase.New(session)
        End Sub
    End Class
End Namespace

Visual BasicCopyCode image复制代码
 (Program.vb)
Imports Microsoft.VisualBasic
Imports System
Imports System.Windows.Forms
Imports DevExpress.Xpo
Imports DevExpress.XtraReports.Extensions
' ...

Namespace ReportStorageSample
    Friend NotInheritable Class Program
        Private Shared reportStorage_Renamed As ReportStorageExtension
        Private Sub New()
        End Sub
        Public Shared ReadOnly Property ReportStorage() As ReportStorageExtension
            Get
                Return reportStorage_Renamed
            End Get
        End Property

        <STAThread> _
        Shared Sub Main()
            Application.EnableVisualStyles()
            Application.SetCompatibleTextRenderingDefault(False)

            ' This code registers a report storage that uses System.DataSet.
            reportStorage_Renamed = New DataSetReportStorage()

            ' Uncomment this line to register a report storage that uses XPO.
            ' reportStorage = new XpoReportStorage(new UnitOfWork());

            ' Uncomment this line to register a report storage, which uses XPO.
            ' reportStorage = new ZipReportStorage();


            ReportStorageExtension.RegisterExtensionGlobal(reportStorage_Renamed)
            Application.Run(New Form1())
        End Sub
    End Class
End Namespace
Visual BasicCopyCode image复制代码
 (StorageDataSet.vb)
Imports Microsoft.VisualBasic
Imports System
Namespace ReportStorageSample
End Namespace

Visual BasicCopyCode image复制代码
 (Form1.vb)
Imports Microsoft.VisualBasic
Imports System
Imports System.IO
Imports System.Windows.Forms
Imports DevExpress.XtraReports.UserDesigner
Imports DevExpress.XtraReports.UI
' ...

Namespace ReportStorageSample
    Partial Public Class Form1
        Inherits Form
        Public Sub New()
            InitializeComponent()
        End Sub

        Private Sub buttonDesign_Click(ByVal sender As Object, ByVal e As EventArgs) Handles buttonDesign.Click
            Dim form As New XRDesignForm()
            Dim url As String = GetSelectedUrl()
            If (Not String.IsNullOrEmpty(url)) Then
                form.OpenReport(url)
            End If
            form.ShowDialog(Me)

            Dim selectedItem As Object = listBox1.SelectedItem
            FillListBox()
            If selectedItem IsNot Nothing AndAlso listBox1.Items.Contains(selectedItem) Then
                listBox1.SelectedItem = selectedItem
            End If
        End Sub

        Private Sub buttonPreview_Click(ByVal sender As Object, ByVal e As EventArgs) Handles buttonPreview.Click
            Dim report As XtraReport = GetSelectedReport()
            If report IsNot Nothing Then
                report.ShowPreviewDialog()
            End If
        End Sub
        Private Function GetSelectedUrl() As String
            Return TryCast(listBox1.SelectedItem, String)
        End Function
        Private Function GetSelectedReport() As XtraReport
            Dim url As String = GetSelectedUrl()
            If String.IsNullOrEmpty(url) Then
                Return Nothing
            End If
            Using stream As New MemoryStream(Program.ReportStorage.GetData(url))
                Return XtraReport.FromStream(stream, True)
            End Using
        End Function
        Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
            FillListBox()
            If listBox1.Items.Count > 0 Then
                listBox1.SelectedIndex = 0
            End If
        End Sub
        Private Sub FillListBox()
            listBox1.Items.Clear()
            Dim urls() As String = Program.ReportStorage.GetStandardUrls(Nothing)
            For Each url As String In urls
                listBox1.Items.Add(url)
            Next url
        End Sub
        Private Sub listBox1_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs) Handles listBox1.SelectedIndexChanged
            buttonPreview.Enabled = listBox1.SelectedItem IsNot Nothing
        End Sub
    End Class
End Namespace