web-dev-qa-db-fra.com

Existe-t-il un moyen facile de réorganiser les colonnes de tablix en mode de conception SSRS?

J'ai un rapport SSRS qui contient plus de 20 colonnes dans un tableau matriciel. Nos utilisateurs ont décidé que les données sont correctes, mais ils veulent que les colonnes soient déplacées (soupir!).

Il semble qu'il devrait être facile de réorganiser les colonnes (déplacer la colonne 3 vers la colonne 1, permuter les colonnes 4 et 5, etc.). Mais, le glisser-déposer ne semble pas fonctionner et la seule solution semble être de supprimer la colonne d'origine et de la réinsérer au bon endroit (et de réappliquer toutes les expressions et la mise en forme déjà créées pour la colonne).

Existe-t-il un moyen plus simple de procéder? Veuillez noter que je ne veux pas de solution programmatique, mais qu'il suffit de la changer une fois en mode conception.

59
PaulStock

Il existe un moyen de déplacer des colonnes dans le concepteur:

  1. insérez le nombre de colonnes vides que vous souhaitez déplacer à votre destination
  2. maj-clic gauche sur les cellules (PAS la colonne d'en-tête) que vous souhaitez déplacer
  3. faites un clic droit et sélectionnez la commande Couper
  4. faites un clic droit en haut des colonnes de destination et sélectionnez Coller
  5. supprimer les anciennes colonnes maintenant vides
99
Scott Blasingame

Si vous pouvez lire XML (comprenez simplement où les balises commencent et/ou se terminent, etc.), vous pouvez facilement accomplir la tâche. Vous pouvez suivre les étapes suivantes:

  1. Tout d'abord, sauvegardez le rapport d'origine en le copiant dans un autre fichier.
  2. Faites un clic droit sur votre rapport dans l'Explorateur de solutions et sélectionnez "Afficher le code"
  3. Cela ouvre le RDL du rapport --- n'ayez pas peur c'est juste un simple fichier xml
  4. Localisez maintenant dans le fichier RDL la balise "Tablix1" - recherchez <Tablix Name="Tablix1"> ....</Tablix >
  5. Vous devez maintenant rechercher différents "<Textbox Name="...">...</Texbox> "balises imbriquées dans le <TablixCells><TablixCell><CellContents>.... Mots clés
  6. Vous pouvez désormais réorganiser facilement les colonnes du rapport en réorganisant simplement l'ordre de ces <Textbox...>...</Texbox> et vous aurez le nouveau rapport avec un nouvel ordre des colonnes.
29
rashkay

En fait, vous devez déplacer (couper et coller) la totalité du <TablixCell> élément pour la colonne (tout entre le <TablixCell> et </TablixCell> incluant le <TablixCell> et </TablixCell> se balise).

Par exemple, pour réorganiser les colonnes de l'exemple ci-dessous afin que la colonne "Product ID" apparaisse avant la colonne "Product Name", vous devez sélectionner et couper la section entière autour de l'élément de cellule "ProductName" (tout depuis le premier <TablixCell> au premier </TablixCell>) puis collez-le après le </TablixCell> pour la colonne "ProductID".
Notez qu'il existe un ensemble complet de <TablixCell> éléments pour chaque ligne définie dans le tableau matriciel; chacun se trouve dans un <TablixRow> élément. Si vous avez laissé la colonne d'en-tête par défaut (où les noms de colonne sont définis), le premier <TablixRow> définit cette ligne d'en-tête et la seconde définit les données dans les colonnes et c'est celle que vous souhaitez modifier. Une fois que vous avez réorganisé les colonnes de données, vous devrez soit faire la même chose pour la colonne d'en-tête (si vous l'avez), soit renommer simplement les colonnes à l'aide du concepteur pour faire correspondre les données maintenant dans les colonnes.

Vraiment cependant, c'est tellement compliqué qu'il est probablement plus facile de déplacer une colonne en utilisant simplement le concepteur pour insérer une nouvelle colonne où vous voulez que la colonne soit déplacée, la définir avec la source de données appropriée pour cette colonne, puis supprimer la colonne d'origine . Pour l'exemple ci-dessous, vous inséreriez une nouvelle colonne après Product ID, la définissez dans la colonne de source de données ProductName (qui la définirait "Product Name" dans la ligne d'en-tête). ), puis supprimez la colonne d'origine Product Name à gauche.

...
<TablixCell>
  <CellContents>
    <Textbox Name="ProductName">
      <CanGrow>true</CanGrow>
      <KeepTogether>true</KeepTogether>
      <Paragraphs>
        <Paragraph>
          <TextRuns>
            <TextRun>
              <Value>=Fields!ProductName.Value</Value>
              <Style />
            </TextRun>
          </TextRuns>
          <Style />
        </Paragraph>
      </Paragraphs>
      <rd:DefaultName>ProductName</rd:DefaultName>
      <Style>
        <Border>
          <Color>LightGrey</Color>
          <Style>Solid</Style>
        </Border>
        <PaddingLeft>2pt</PaddingLeft>
        <PaddingRight>2pt</PaddingRight>
        <PaddingTop>2pt</PaddingTop>
        <PaddingBottom>2pt</PaddingBottom>
      </Style>
    </Textbox>
  </CellContents>
</TablixCell>
<TablixCell>
  <CellContents>
    <Textbox Name="ProductID">
      <CanGrow>true</CanGrow>
      <KeepTogether>true</KeepTogether>
      <Paragraphs>
        <Paragraph>
          <TextRuns>
            <TextRun>
              <Value>=Fields!ProductID.Value</Value>
              <Style />
            </TextRun>
          </TextRuns>
          <Style />
        </Paragraph>
      </Paragraphs>
      <rd:DefaultName>ProductID</rd:DefaultName>
      <Style>
        <Border>
          <Color>LightGrey</Color>
          <Style>Solid</Style>
        </Border>
        <PaddingLeft>2pt</PaddingLeft>
        <PaddingRight>2pt</PaddingRight>
        <PaddingTop>2pt</PaddingTop>
        <PaddingBottom>2pt</PaddingBottom>
      </Style>
    </Textbox>
  </CellContents>
</TablixCell>
...

après le couper/coller, vous vous retrouveriez alors avec:

...
<TablixCell>
  <CellContents>
    <Textbox Name="ProductID">
      <CanGrow>true</CanGrow>
      <KeepTogether>true</KeepTogether>
      <Paragraphs>
        <Paragraph>
          <TextRuns>
            <TextRun>
              <Value>=Fields!ProductID.Value</Value>
              <Style />
            </TextRun>
          </TextRuns>
          <Style />
        </Paragraph>
      </Paragraphs>
      <rd:DefaultName>ProductID</rd:DefaultName>
      <Style>
        <Border>
          <Color>LightGrey</Color>
          <Style>Solid</Style>
        </Border>
        <PaddingLeft>2pt</PaddingLeft>
        <PaddingRight>2pt</PaddingRight>
        <PaddingTop>2pt</PaddingTop>
        <PaddingBottom>2pt</PaddingBottom>
      </Style>
    </Textbox>
  </CellContents>
</TablixCell>
<TablixCell>
  <CellContents>
    <Textbox Name="ProductName">
      <CanGrow>true</CanGrow>
      <KeepTogether>true</KeepTogether>
      <Paragraphs>
        <Paragraph>
          <TextRuns>
            <TextRun>
              <Value>=Fields!ProductName.Value</Value>
              <Style />
            </TextRun>
          </TextRuns>
          <Style />
        </Paragraph>
      </Paragraphs>
      <rd:DefaultName>ProductName</rd:DefaultName>
      <Style>
        <Border>
          <Color>LightGrey</Color>
          <Style>Solid</Style>
        </Border>
        <PaddingLeft>2pt</PaddingLeft>
        <PaddingRight>2pt</PaddingRight>
        <PaddingTop>2pt</PaddingTop>
        <PaddingBottom>2pt</PaddingBottom>
      </Style>
    </Textbox>
  </CellContents>
</TablixCell>
...
5
DizGrizz

Une autre note sur le travail dans le RDL:
Si vous vous trompez, le rapport affichera un message d'erreur et il n'affichera pas les données.

À moins que vous ne soyez familier avec RDL (Report Definition Language, un type de XML), ces types d'erreurs peuvent être très frustrants à gérer, rendant parfois le rapport inutilisable.

Il est beaucoup plus sûr d'utiliser l'ajout de nouvelles colonnes et de supprimer l'ancienne méthode dans le concepteur mentionné ci-dessus. Cela vous tient à l'écart du RDL, ce qui réduit vos risques d'endommager le rapport.

3
Mac

J'ai rencontré cette situation aujourd'hui alors que j'essayais de réorganiser les colonnes en faisant glisser l'en-tête de colonne du tablix, cela ne fonctionne pas! Cependant, j'ai découvert qu'il est possible de faire glisser une cellule et de la déposer (avec précaution) sur une autre cellule, puis les cellules s'échangent. De cette façon, vous pouvez réorganiser les colonnes en échangeant les cellules d'en-tête et de contenu sans avoir à créer de nouvelles colonnes vides, ce qui est préférable si vous ne voulez pas que la largeur du corps du rapport augmente et produise des pages vides en PDF = le rendu, bien sûr, il peut être corrigé à nouveau. Pour faire glisser une cellule, cliquez une seule fois sur la cellule mais n'entrez pas en mode édition, puis passez la souris sur les bordures et faites glisser une fois que vous obtenez le curseur "Déplacer". Ceci s'applique à concepteur de rapports disponible pour Visual Studio 2017.

1
Rajeesh

Ma solution:

using System;
using System.IO;
using System.Linq;
using System.Xml;

namespace MoveSsrsColumns
{
    class TablixColumnReorderer
    {
        readonly XmlDocument _xData = new XmlDocument();
        readonly XmlNamespaceManager _nsManager;
        readonly XmlElement _tablixNode;

        public TablixColumnReorderer(string rdlFileName, string tablixName)
        {
            using (var fs = new FileStream(rdlFileName, FileMode.Open))
            using (var xr = XmlReader.Create(fs))
                _xData.Load(xr);
            _nsManager = new XmlNamespaceManager(_xData.NameTable);
            _nsManager.AddNamespace("def", "http://schemas.Microsoft.com/sqlserver/reporting/2010/01/reportdefinition");
            _tablixNode =
                _xData.SelectNodes(string.Format(TablixXPath, tablixName)_nsManager)
                ?.Cast<XmlElement>().FirstOrDefault()
                ?? throw new ApplicationException("Tablix node notfound");
        }

        const string TablixXPath = @"
            /def:Report
                /def:ReportSections
                    /def:ReportSection
                        /def:Body
                            /def:ReportItems
                                /def:Tablix[@Name='{0}']";

        const string SearchColumnXPath = @"
            def:TablixBody
                /def:TablixRows
                    /def:TablixRow
                        /def:TablixCells
                            /def:TablixCell
                                /def:CellContents
                                    /def:*[@Name='{0}']";

        const string ParentTablixCellXPath = "parent::def:CellContents/parent::def:TablixCell";

        int FindColumn(string columnControlName)
        {
            var columnControl = _tablixNode
                .SelectNodes(string.Format(SearchColumnXPath, columnControlName), _nsManager)
                ?.Cast<XmlElement>()
                .Single();
            if (columnControl==null)
                throw new ArgumentException($"Column with control {columnControlName} notfound");
            if (!(columnControl.SelectSingleNode(ParentTablixCellXPath, _nsManager) is XmlElement tablixCell))
                throw new ArgumentException($"Tablix cell for column with control {columnControlName} notfound");
            var columnIndex = ((XmlElement) tablixCell.ParentNode)
                ?.ChildNodes
                .Cast<XmlElement>()
                .TakeWhile(e=>e!=tablixCell)
                .Count() ?? -1;
            if (columnIndex==-1)
                throw new ArgumentException($"Cannot get index for column with control {columnControlName}");
            return columnIndex;
        }

        public void SetPosition(string sourceColumnControlName, string destinationColumnControlName)
        {
            SetPosition(FindColumn(sourceColumnControlName), FindColumn(destinationColumnControlName));
        }

        public void SetPosition(string sourceColumnControlName, int destinationColumnIndex)
        {
            SetPosition(FindColumn(sourceColumnControlName), destinationColumnIndex);
        }

        public void SetPosition(int sourceColumnIndex, string destinationColumnControlName)
        {
            SetPosition(sourceColumnIndex, FindColumn(destinationColumnControlName));
        }

        const string TablixCellsXPath = "def:TablixBody/def:TablixColumns";
        const string TablixRowCellsXPath = "def:TablixBody/def:TablixRows/def:TablixRow/def:TablixCells";
        public void SetPosition(int sourceColumnIndex, int destinationColumnIndex)
        {
            var tablixColumnsNode = _tablixNode
                .SelectSingleNode(TablixCellsXPath, _nsManager) as XmlElement
                ?? throw new ApplicationException("TablixColumns node notfound");
            tablixColumnsNode.InsertBefore(
                tablixColumnsNode.ChildNodes[sourceColumnIndex],
                tablixColumnsNode.ChildNodes[destinationColumnIndex]
            );
            var tablixRowsCells = _tablixNode
                .SelectNodes(TablixRowCellsXPath, _nsManager)
                ?.Cast<XmlElement>()
                ?? throw new ApplicationException("Tablix rows cells notfound");
            foreach (var cells in tablixRowsCells)
                cells.InsertBefore(
                    cells.ChildNodes[sourceColumnIndex],
                    cells.ChildNodes[destinationColumnIndex]
                );
        }

        public void Save(string rdlFileName)
        {
            using (var fs = new FileStream(rdlFileName, FileMode.Create))
            using (var xw = XmlWriter.Create(fs, new XmlWriterSettings
            {
                Indent = true,
                IndentChars = "  "
            }))
                _xData.Save(xw);
        }
    }
}

Usage:

public static void Main(string[] args)
{
    var tcr = new TablixColumnReorderer("myreport.rdl", "Tablix1");
    tcr.SetPosition("bill_number", 0);
    tcr.SetPosition("account", 1);
    tcr.SetPosition("to_date", 2);
    tcr.Save("myreport#2.rdl");
    Console.WriteLine("done");
    Console.ReadKey(true);
}
0
user11354240