MVVM - Use Report Designer API from ViewModel
- 5 minutes to read
The DevExpress MVVM Framework allows you to access the ReportDesigner methods from commands defined in the ViewModel. You can develop your own API that extends the built-in functionality of ReportDesigner and optimally meets your requirements.
In this example the Behavior
mechanism initializes a service that implements ReportDesigner actions. The service is defined as follows:
using DevExpress.Mvvm.UI;
using DevExpress.Mvvm.UI.Interactivity;
using DevExpress.Xpf.Reports.UserDesigner;
using DevExpress.XtraReports.UI;
using System;
using System.Collections.Generic;
using System.IO;
namespace ManipulateReportDesignerDocuments_MVVM {
public interface IReportDesignerAPIService {
IEnumerable<ReportDesignerDocument> Documents { get; }
ReportDesignerDocument ActiveDocument { get; }
ReportDesignerDocument NewReport(XtraReport report = null);
ReportDesignerDocument Open();
ReportDesignerDocument Open(Stream stream);
}
public class ReportDesignerAPIService : ServiceBase, IReportDesignerAPIService {
ReportDesigner Designer => (ReportDesigner)AssociatedObject;
public IEnumerable<ReportDesignerDocument> Documents => Designer.Documents;
public ReportDesignerDocument ActiveDocument => Designer.ActiveDocument;
public ReportDesignerDocument NewReport(XtraReport report = null) {
Func<XtraReport> reportFactory = null;
if(report != null)
reportFactory = () => report;
return Designer.NewDocument(reportFactory);
}
public ReportDesignerDocument Open() {
return Designer.OpenDocument();
}
public ReportDesignerDocument Open(Stream stream) {
return Designer.OpenDocument(stream);
}
}
}
The ReportDesignerAPIService is specified as custom behavior. For more information on the Behavior mechanism in DevExpress MVVM Framework, review the following help topic: Behaviors.
The following code uses the ReportDesignerAPIService class as a custom Behavior for the ReportDesigner element in the View:
<dx:ThemedWindow x:Class="ManipulateReportDesignerDocuments_MVVM.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:ManipulateReportDesignerDocuments_MVVM"
xmlns:dxrud="http://schemas.devexpress.com/winfx/2008/xaml/reports/userdesigner"
xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm"
xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
mc:Ignorable="d" WindowKind="Tabbed" WindowState="Maximized"
Title="MainWindow" Height="450" Width="800">
<!-- ... -->
<dxrud:ReportDesigner>
<dxrud:ReportDesignerBrowserView CloseWindowWhenLastTabIsClosed="False" />
<dxrud:ReportDesigner.DocumentSource>
<Binding Path="DefaultReport" />
</dxrud:ReportDesigner.DocumentSource>
<dxmvvm:Interaction.Behaviors>
<local:ReportDesignerAPIService />
</dxmvvm:Interaction.Behaviors>
</dxrud:ReportDesigner>
<!-- ... -->
</dx:ThemedWindow>
The MainViewModel ViewModel class gets the ReportDesignerAPIService
service and implements MVVM commands based on the service methods:
using DevExpress.Mvvm;
using DevExpress.Mvvm.DataAnnotations;
using DevExpress.Xpf.Reports.UserDesigner;
using DevExpress.XtraReports.UI;
using System;
using System.Linq;
using System.Windows;
using System.Windows.Resources;
namespace ManipulateReportDesignerDocuments_MVVM {
public class MainViewModel : ViewModelBase {
public XtraReport DefaultReport { get; set; }
IReportDesignerAPIService ReportDesignerAPI => ServiceContainer.GetService<IReportDesignerAPIService>();
protected override void OnInitializeInRuntime() {
base.OnInitializeInRuntime();
DefaultReport = new XtraReport();
}
[Command]
public void NewReport() {
ReportDesignerAPI.NewReport();
}
public bool CanNewReport() => ReportDesignerAPI != null;
[Command]
public void OpenReport() {
ReportDesignerAPI.Open();
}
public bool CanOpenReport() => ReportDesignerAPI != null;
[Command]
public void OpenReportFromStream() {
var stream = Application.GetResourceStream(new Uri("Resources/Invoice.repx", UriKind.Relative))?.Stream;
if(stream != null) {
using(stream) {
ReportDesignerAPI.Open(stream);
}
}
}
public bool CanOpenReportFromStream() => ReportDesignerAPI != null;
[Command]
public void CloseActiveDocument() {
ReportDesignerAPI.ActiveDocument.Close(true);
}
public bool CanCloseActiveDocument() => ReportDesignerAPI?.ActiveDocument != null;
[Command]
public void ActivateFirstDocumentTab() {
ReportDesignerDocument firstTab = ReportDesignerAPI.Documents.First();
firstTab.Activate();
}
public bool CanActivateFirstDocumentTab() => ReportDesignerAPI?.Documents.Any() ?? false;
[Command]
public void SwitchActiveDocumentView() {
ReportDesignerDocument activeDocument = ReportDesignerAPI.ActiveDocument;
activeDocument.ViewKind = activeDocument.ViewKind == ReportDesignerDocumentViewKind.Designer
? ReportDesignerDocumentViewKind.Preview
: ReportDesignerDocumentViewKind.Designer;
}
public bool CanSwitchActiveDocumentView() => ReportDesignerAPI?.ActiveDocument != null;
}
}
For more information on auto-generated commands, review the following help topic: POCO Commands.
The application appears as follows: