DevExpress Report

De Banane Atomic
Révision datée du 14 décembre 2015 à 22:45 par Nicolas (discussion | contributions) (→‎DataSource: Wrapper dynamique)
(diff) ← Version précédente | Voir la version actuelle (diff) | Version suivante → (diff)
Aller à la navigationAller à la recherche

Liens utiles

Généré un PDF depuis un template (*.repx)

Csharp.svg
XtraReport reportDevExpress = XtraReport.FromFile(@"C:\Template.repx", true);

// it has to be an ArrayList, otherwise the report is not well filled
reportDevExpress.DataSource = new ArrayList(MyDataList);

reportDevExpress.ExportToPdf(@"C:\File.pdf");
XtraReport Class
  • Namespace: DevExpress.XtraReports.UI
  • Assembly: DevExpress.XtraReports.v15.1.dll

PDF/A

Csharp.svg
// PDF/A-2b
PdfExportOptions options = new PdfExportOptions()
{
    PdfACompatible = true
};
reportDevExpress.ExportToPdf(@"C:\File.pdf", options);

// PDF/A-3b
string additionalMetadata =
    File.ReadAllText("DocumentInfo.txt") +
    File.ReadAllText("PdfASchema.txt");

PdfExportOptions options = new PdfExportOptions()
{
    PdfACompatible = true,
    AdditionalMetadata = additionalMetadata,
};

reportDevExpress.ExportToPdf(@"C:\File.pdf", options);
PDF/A-3b v 14.2.6
PDF/A-2b v 14.1.3
PdfExportOptions Class
  • Namespace: DevExpress.XtraPrinting
  • Assembly: DevExpress.Printing.v15.1.Core.dll

Designer WinForm dans une fenêtre WPF

Xaml.svg
<Window xmlns:userDesigner="clr-namespace:DevExpress.XtraReports.UserDesigner;assembly=DevExpress.XtraReports.v13.2.Extensions" 
        xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms">

    <Grid>
        <WindowsFormsHost>
            <WindowsFormsHost.Child>

                <wf:UserControl x:Name="ucDockingWindows">
                    <wf:UserControl.Controls>
                        <userDesigner:XRDesignPanel x:Name="panel" Dock="Fill" />
                    </wf:UserControl.Controls>
                </wf:UserControl>

            </WindowsFormsHost.Child>
        </WindowsFormsHost>
    </Grid>
</Window>
Csharp.svg
public MainWindow()
{
    InitializeComponent();

    var dockManager = new XRDesignDockManager();
    dockManager.Form = ucDockingWindows;
    dockManager.Initialize(panel, DesignDockPanelType.All);

    var barManager = new XRDesignBarManager();
    barManager.Form = ucDockingWindows;
    barManager.Initialize(panel);
    barManager.DockManager = dockManager;

    // Remove tool bar stuff
    panel.SetCommandVisibility(ReportCommand.AddNewDataSource, CommandVisibility.None);

    // Close GroupAndSort DesignDockPanel
    var designDockPanel = (GroupAndSortDockPanel)dockManager[DesignDockPanelType.GroupAndSort];
    designDockPanel.Close();

    // get a specific DesignDockPanel from its name
    var designDockPanel = dockManager.Panels.OfType<TypedDesignDockPanel>().FirstOrDefault(p => p.GetType().Name.StartsWith(DesignDockPanelType.GroupAndSort.ToString()));

    // set report datasource
    report.DataSource = dataSource;

Afficher une preview

Csharp.svg
var report = XtraReport.FromFile(@"Chemin\vers\le\fichier.repx", true);
using (ReportPrintTool printTool = new ReportPrintTool(report))
{
    printTool.ShowPreviewDialog();
}

Éditer avec le designer classique

Csharp.svg
var report = XtraReport.FromFile(@"Chemin\vers\le\fichier.repx", true);
using (ReportPrintTool printTool = new ReportPrintTool(report))
{
    printTool.ShowDesignerDialog();
}

Masquer des boutons dans le ruban

Bash.svg
reportDesigner1.SetCommandVisibility(ReportCommand.SaveAll, CommandVisibility.None);

Rafraichir le nom du rapport dans un onglet

Csharp.svg
XRDesignMdiController _controller;
var host = (IDesignerHost)_controller.ActiveDesignPanel.GetService(typeof(IDesignerHost));
var changeSrv = (IComponentChangeService)host.GetService(typeof(IComponentChangeService));

changeSrv.OnComponentChanging(_controller.ActiveDesignPanel.Report, null);
_controller.ActiveDesignPanel.Report.DisplayName = "Nouveau nom de rapport";
changeSrv.OnComponentChanged(_controller.ActiveDesignPanel.Report, null, null, null);

Ajouter une dropdown list dans le menu

Override Commands in the End-User Designer (Custom Saving)

New

Csharp.svg
public ReportsDesigner()
    {
        reportDesigner1.AddCommandHandler(new MainCommandHandler(reportDesigner1);

/* ** */
public class MainCommandHandler : ICommandHandler
{
    private XRDesignMdiController _controller;

    public bool CanHandleCommand(ReportCommand command, ref bool useNextHandler)
    {
        useNextHandler = command != ReportCommand.NewReport;
        return !useNextHandler;
    }

    public void HandleCommand(ReportCommand command, object[] args)
    {
        _controller.CreateNewReport();
        _controller.ActiveDesignPanel.Report.DataSource = ...;

        // Update the Field List
        var host = (IDesignerHost)_controller.ActiveDesignPanel.GetService(typeof(IDesignerHost));
        _fieldList.UpdateDataSource(host);

        // Change the DisplayName
        var changeSrv = (IComponentChangeService)host.GetService(typeof(IComponentChangeService));
        changeSrv.OnComponentChanging(_controller.ActiveDesignPanel.Report, null);
        _controller.ActiveDesignPanel.Report.DisplayName = ...;
        changeSrv.OnComponentChanged(_controller.ActiveDesignPanel.Report, null, null, null);

        // Change the FileName
        _controller.ActiveDesignPanel.FileName = ...;

        // display a star at the right of the name in the tab to inform that the file is not saved yet
        _controller.ActiveDesignPanel.ReportState = ReportState.Changed;

Save

Csharp.svg
private void reportDesigner1_DesignPanelLoaded(object sender, DesignerLoadedEventArgs e)
{
    XRDesignPanel panel = (XRDesignPanel)sender;
    reportDesigner1.AddCommandHandler(new SaveCommandHandler(reportDesigner1, panel));

/* ** */
public class SaveCommandHandler : ICommandHandler
{
    private XRDesignMdiController _controller;
    private XRDesignPanel _panel;    

    public bool CanHandleCommand(ReportCommand command, ref bool useNextHandler)
    {
        // ici on choisit les commandes qui seront gérées
        useNextHandler = command != ReportCommand.SaveFile && 
          command != ReportCommand.SaveFileAs &&
          command != ReportCommand.Closing;
        return !useNextHandler;
    }

    public void HandleCommand(ReportCommand command, object[] args)
    {
        switch (command)
        {
            case ReportCommand.SaveFile:
                HandleSave();
                break;
            case ReportCommand.SaveFileAs:
                HandleSaveAs();
                break;
            case ReportCommand.Closing:
                HandleClosing(args);
                break;
            default:
                break;
        }
    }

    private void HandleSave()
    {
        if (File.Exists(_panel.FileName))
        {
            // Save template
            _panel.Report.SaveLayout(_panel.FileName, true);

            // Prevent the "Report has been changed" dialog from being shown.
            _panel.ReportState = ReportState.Saved;
        }
        else
        {
            HandleSaveAs();
        }
    }

    private void HandleClosing(object[] args)
    {
        if (_panel.ReportState == ReportState.Changed)
        {
            if (args.Length == 2)
            {
                var panelForm = args[0] as XRDesignPanelForm;
                var cancelEventArgs = args[1] as CancelEventArgs;

                if (panelForm != null && cancelEventArgs != null)
                {
                    // Select the report in the tabs
                    _panel.Select();

                    MessageBoxResult messageBoxResult = MessageBox.Show(
                      String.Format("The template '{0}' has changed. Do you want to save it?", 
                        panelForm.ReportDisplayName),
                        "Template has changed",
                        MessageBoxButton.YesNoCancel);

                    if (messageBoxResult == MessageBoxResult.Cancel)
                    {
                        cancelEventArgs.Cancel = true;
                    }
                }
            }
        }
    }
}

Field List

Provide Custom Names for Data Items in the Field List

DataSource: Wrapper dynamique

Pour chaque élément de DataList, on créé un wrapper: pour chaque propriété marquée de l'attribut [Field("Nom affiché", "Groupe")]

  • on créé un groupe s'il n'existe pas déjà
  • où on y ajoute une propriété "Nom affiché"
  • avec la valeur de la propriété.
Csharp.svg
XtraReport reportDevExpress = XtraReport.FromFile(templateFilePath, true);
reportDevExpress.DataSource = GetDataSource();

public object GetDataSource()
{
    var wrapperArrayList = new DataWrapperArrayList("Nom de la Field List");
    // wrap chaque élément de DataList
    foreach (var wrapper in DataList.Select(r => DataWrapperForDesigner<FieldAttribute>.BuildDynamicWrapper(r, true)))
    {
        wrapperArrayList.Add(wrapper);
    }

    return wrapperArrayList;
}

// pour le Designer on n'a besoin juste d'un élément (data) et pas de la liste de tous les éléments (DataList)
// on a besoin de la structure de l'élément (liste des propriétés mais pas des valeurs)
public object GetDataSourceSkeleton()
{
    var dynamicWrapper = DataWrapperForDesigner<FieldAttribute>.BuildDynamicWrapper(data, false);
    var dynamicWrapperArrayList = new DataWrapperArrayList("Nom de la Field List") { dynamicWrapper };
    dynamicWrapperArrayList.DisplayNames = DataWrapperForDesigner<FieldAttribute>.DisplayNames;

    return dynamicWrapperArrayList;
}
Csharp.svg
public class DataWrapperArrayList : ArrayList, IDisplayNameProvider
{
    private string _dataSourceDisplayName;

    public DataWrapperArrayList(string dataSourceDisplayName)
    {
        _dataSourceDisplayName = dataSourceDisplayName;
    }

    public string GetDataSourceDisplayName()
    {
        return _dataSourceDisplayName;
    }

    public string GetFieldDisplayName(string[] fieldAccessors)
    {
        var fieldName = fieldAccessors[fieldAccessors.Length - 1];
        if (DisplayNames != null && DisplayNames.ContainsKey(fieldName))
        {
            return DisplayNames[fieldName];
        }
        else
        {
            // Inserts spaces in the field names.
            return SpaceFieldNames(fieldName);
        }
    }

    private string SpaceFieldNames(string fieldName)
    {
        string result = string.Empty;
        bool isPrevLow = false;

        foreach (char symb in fieldName)
        {
            // Check if a character is of upper case.
            // To avoid spaces inside abbreviations, 
            // check if the previous character is of upper case, too.
            if (Char.IsUpper(symb) && isPrevLow)
            {
                result += " " + symb;
            }
            else
            {
                result += symb;
            }
            isPrevLow = Char.IsLower(symb);
        }
        return result;
    }

    public IDictionary<string, string> DisplayNames { get; set; }
}
Csharp.svg
public class DataWrapperForDesigner<A>
    where A : Attribute, IFieldAttribute
{
    /// <summary>
    /// Store the dynamic wrapper type after it has been build the first time.
    /// This to avoid creating a different type each type.
    /// </summary>
    private static IDictionary<Type, Type> _dynamicWrapperTypes;

    /// <summary>
    /// Builds the type of the dynamic wrapper or get the previously built type.
    /// </summary>
    /// <returns></returns>
    private static Type BuildDynamicWrapperType(Type reportType)
    {
        // create once the dynamicWrapperType for a report type
        if (!_dynamicWrapperTypes.ContainsKey(reportType))
        {
            ModuleBuilder moduleBuilder;
            TypeBuilder typeBuilder = CreateTypeBuilder("DynamicWrapper", "DynamicWrapper.dll", "DynamicWrapper", out moduleBuilder);

            var propertiesGroups = new Dictionary<string, List<PropertyInfo>>();

            // for each properties with the attribute Field
            foreach (var propertyInfo in reportType.GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(p => Attribute.IsDefined(p, typeof(A))))
            {
                var fieldAttribute = (A)Attribute.GetCustomAttribute(propertyInfo, typeof(A), false);
                if (!propertiesGroups.ContainsKey(fieldAttribute.Group))
                {
                    propertiesGroups[fieldAttribute.Group] = new List<PropertyInfo>();
                }
                propertiesGroups[fieldAttribute.Group].Add(propertyInfo);

                DisplayNames[propertyInfo.Name] = fieldAttribute.DisplayName;
            }

            // for each group create a dynamic class
            foreach (var group in propertiesGroups.Keys)
            {
                TypeBuilder groupTypeBuilder = CreateTypeBuilder(group, moduleBuilder);

                foreach (var propertyInfo in propertiesGroups[group])
                {
                    AddProperty(groupTypeBuilder, propertyInfo.Name, propertyInfo.PropertyType);
                }

                Type groupType = groupTypeBuilder.CreateType();

                // add the new type as property into the DynamicWrapper
                AddProperty(typeBuilder, group, groupType);
            }

            _dynamicWrapperTypes[reportType] = typeBuilder.CreateType();
        }

        return _dynamicWrapperTypes[reportType];
    }

    /// <summary>
    /// A dictionary which keys are property names and values names to display in the DevExpress designer.
    /// </summary>
    public static IDictionary<string, string> DisplayNames { get; private set; }

    static DataWrapperForDesigner()
    {
        _dynamicWrapperTypes = new Dictionary<Type, Type>();
        DisplayNames = new Dictionary<string, string>();
    }

    /// <summary>
    /// Create the dynamic wrapper object and fill it if needed.
    /// </summary>
    public static object BuildDynamicWrapper(object data, bool fillTheWrapperWithData)
    {
        var dynamicWrapperType = BuildDynamicWrapperType(data.GetType());
        var dynamicWrapper = Activator.CreateInstance(dynamicWrapperType);

        if (fillTheWrapperWithTheReportData)
        {
            var propertiesGroups = new Dictionary<string, List<PropertyNameAndValue>>();

            // for each properties of data with the attribute Field
            foreach (var propertyInfo in report.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(p => Attribute.IsDefined(p, typeof(A))))
            {
                var fieldAttribute = (A)Attribute.GetCustomAttribute(propertyInfo, typeof(A), false);
                if (!propertiesGroups.ContainsKey(fieldAttribute.Group))
                {
                    propertiesGroups[fieldAttribute.Group] = new List<PropertyNameAndValue>();
                }
                propertiesGroups[fieldAttribute.Group].Add(new PropertyNameAndValue() { PropertyName = propertyInfo.Name, PropertyValue = propertyInfo.GetValue(report, null) });
            }

            foreach (var group in propertiesGroups.Keys)
            {
                var groupProperty = dynamicWrapperType.GetProperty(group);

                var groupInstance = Activator.CreateInstance(groupProperty.PropertyType);

                foreach (PropertyNameAndValue propertyNameAndValue in propertiesGroups[group])
                {
                    if (propertyNameAndValue.PropertyValue != null)
                    {
                        var wrapperProperty = groupProperty.PropertyType.GetProperty(propertyNameAndValue.PropertyName);
                        if (wrapperProperty != null)
                        {
                            wrapperProperty.SetValue(groupInstance, propertyNameAndValue.PropertyValue, null);
                        }
                        else
                        {
                            log.ErrorFormat("Unable to retrieve the property {0} in the class {1}.", propertyNameAndValue.PropertyName, report.GetType().Name);
                        }
                    }
                }

                groupProperty.SetValue(dynamicWrapper, groupInstance, null);
            }
        }

        return dynamicWrapper;
    }

    /// <summary>
    /// Creates an assembly, a module and a type builder.
    /// </summary>
    /// <param name="assemblyName">Name of the assembly.</param>
    /// <param name="moduleName">Name of the module.</param>
    /// <param name="typeName">Name of the type.</param>
    /// <param name="moduleBuilder">The module builder.</param>
    /// <returns></returns>
    private static TypeBuilder CreateTypeBuilder(string assemblyName, string moduleName, string typeName, out ModuleBuilder moduleBuilder)
    {
        var assemblyNameObject = new AssemblyName() { Name = assemblyName };
        AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assemblyNameObject, AssemblyBuilderAccess.Run);
        moduleBuilder = assemblyBuilder.DefineDynamicModule(moduleName);
        return moduleBuilder.DefineType(typeName, TypeAttributes.Public | TypeAttributes.Class);
    }

    /// <summary>
    /// Creates a type builder from a module.
    /// </summary>
    /// <param name="typeName">Name of the type.</param>
    /// <param name="moduleBuilder">The module builder.</param>
    /// <returns></returns>
    private static TypeBuilder CreateTypeBuilder(string typeName, ModuleBuilder moduleBuilder)
    {
        return moduleBuilder.DefineType(typeName, TypeAttributes.Public | TypeAttributes.Class);
    }

    /// <summary>
    /// Adds the property to the class.
    /// </summary>
    /// <param name="typeBuilder">The type builder.</param>
    /// <param name="propertyName">Name of the property.</param>
    /// <param name="propertyType">Type of the property.</param>
    private static void AddProperty(TypeBuilder typeBuilder, string propertyName, Type propertyType)
    {
        FieldBuilder fieldBuilder = typeBuilder.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);

        PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);

        MethodBuilder getPropMthdBldr = typeBuilder.DefineMethod("get_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, propertyType, Type.EmptyTypes);
        ILGenerator getIl = getPropMthdBldr.GetILGenerator();
        getIl.Emit(OpCodes.Ldarg_0);
        getIl.Emit(OpCodes.Ldfld, fieldBuilder);
        getIl.Emit(OpCodes.Ret);

        MethodBuilder setPropMthdBldr = typeBuilder.DefineMethod("set_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, null, new[] { propertyType });
        ILGenerator setIl = setPropMthdBldr.GetILGenerator();
        Label modifyProperty = setIl.DefineLabel();
        Label exitSet = setIl.DefineLabel();
        setIl.MarkLabel(modifyProperty);
        setIl.Emit(OpCodes.Ldarg_0);
        setIl.Emit(OpCodes.Ldarg_1);
        setIl.Emit(OpCodes.Stfld, fieldBuilder);
        setIl.Emit(OpCodes.Nop);
        setIl.MarkLabel(exitSet);
        setIl.Emit(OpCodes.Ret);

        propertyBuilder.SetGetMethod(getPropMthdBldr);
        propertyBuilder.SetSetMethod(setPropMthdBldr);
    }
}

/// <summary>
/// A class used to store the property name with its value.
/// </summary>
class PropertyNameAndValue
{
    public string PropertyName { get; set; }
    public object PropertyValue { get; set; }
}

public interface IFieldAttribute
{
    string DisplayName { get; }
    string Group { get; }
}