web-dev-qa-db-de.com

Gibt es eine einfache Möglichkeit, Tablix-Spalten im SSRS-Entwurfsmodus neu anzuordnen?

Ich habe einen SSRS-Bericht, der mehr als 20 Spalten in einem Tablix enthält. Unsere Benutzer haben entschieden, dass die Daten in Ordnung sind, aber sie möchten, dass die Spalten verschoben werden (seufz!).

Es scheint, als ob es einfach sein sollte, die Spalten neu anzuordnen (Spalte 3 in Spalte 1 verschieben, Spalten 4 und 5 tauschen usw.). Drag & Drop scheint jedoch nicht zu funktionieren, und die einzige Lösung scheint darin zu bestehen, die ursprüngliche Spalte zu löschen und an der richtigen Stelle einzufügen (und bereits für die Spalte erstellte Ausdrücke und Formatierungen erneut anzuwenden).

Gibt es einen einfacheren Weg, dies zu tun? Bitte beachten Sie, dass ich keine programmgesteuerte Lösung möchte, sondern diese nur einmal im Entwurfsmodus ändern muss.

59
PaulStock

Es gibt eine Möglichkeit, Spalten im Designer zu verschieben:

  1. geben Sie die Anzahl der leeren Spalten ein, die Sie an Ihrem Zielort verschieben möchten
  2. klicken Sie bei gedrückter Umschalttaste mit der linken Maustaste auf die Zellen (NICHT die Kopfzeile), die Sie verschieben möchten
  3. klicken Sie mit der rechten Maustaste und wählen Sie den Befehl Ausschneiden
  4. klicken Sie mit der rechten Maustaste auf die Zielspalten und wählen Sie Einfügen
  5. lösche die jetzt leeren alten Spalten
99

Wenn Sie XML lesen können (verstehen Sie einfach, wo Tags beginnen und/oder enden usw.), können Sie die Aufgabe problemlos ausführen. Sie können die folgenden Schritte ausführen:

  1. Sichern Sie zunächst den Originalbericht, indem Sie ihn in eine andere Datei kopieren.
  2. Klicken Sie mit der rechten Maustaste auf Ihren Bericht im Projektmappen-Explorer und wählen Sie "Code anzeigen".
  3. Dies öffnet die RDL des Berichts - keine Angst, es ist nur eine einfache XML-Datei
  4. Suchen Sie nun in der RDL-Datei das "Tablix1" -Tag - suchen Sie nach <Tablix Name="Tablix1"> ....</Tablix >
  5. Sie müssen nun nach verschiedenen "<Textbox Name="...">...</Texbox>" - Tags suchen, die in den <TablixCells><TablixCell><CellContents>.... - Tags verschachtelt sind
  6. Jetzt können Sie die Spalten des Berichts auf einfache Weise neu anordnen, indem Sie einfach die Reihenfolge dieser <Textbox...>...</Texbox> Ändern. Der neue Bericht wird dann in einer neuen Spaltenreihenfolge angezeigt.
29
rashkay

Eigentlich müssen Sie das gesamte <TablixCell> Element für die Spalte (alles zwischen dem <TablixCell> und </TablixCell> einschließlich der <TablixCell> und </TablixCell> markiert sich selbst).

Um beispielsweise die Spalten im folgenden Beispiel neu anzuordnen, damit die Spalte "Produkt-ID" vor der Spalte "Produktname" angezeigt wird, müssen Sie den gesamten Abschnitt um das Zellenelement "Produktname" auswählen und ausschneiden (alles vom ersten <TablixCell> zum ersten </TablixCell>) und dann einfügen nach das </TablixCell> für die Spalte "ProductID".
Beachten Sie, dass es einen vollständigen Satz von <TablixCell> -Elemente für jede in Tablix definierte Zeile; jeder ist in einem separaten <TablixRow> Element. Wenn Sie die Standardüberschriftenspalte (in der die Spaltennamen festgelegt sind) verlassen haben, wird das erste <TablixRow> definiert diese Kopfzeile und die zweite definiert die Daten in den Spalten und ist diejenige, die Sie bearbeiten möchten. Nachdem Sie die Datenspalten neu angeordnet haben, müssen Sie entweder dasselbe für die Kopfspalte tun (sofern vorhanden) oder die Spalten einfach mit dem Designer umbenennen, damit sie den Daten in den Spalten entsprechen.

In Wirklichkeit ist dies jedoch so kompliziert, dass es wahrscheinlich einfacher ist, eine Spalte zu verschieben, indem Sie mit dem Designer eine neue Spalte einfügen, in die die Spalte verschoben werden soll, diese mit der richtigen Datenquelle für diese Spalte festlegen und dann die ursprüngliche Spalte löschen . Für das folgende Beispiel fügen Sie eine neue Spalte nach Produkt-ID ein und setzen sie in die Datenquellenspalte Produktname (wodurch in der Kopfzeile "Produktname" festgelegt wird) ), und löschen Sie dann die ursprüngliche Spalte Produktname auf der linken Seite.

...
<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>
...

nach dem Ausschneiden/Einfügen erhalten Sie dann:

...
<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

Ein weiterer Hinweis zur Arbeit in der RDL:
Wenn Sie einen Fehler machen, wird im Bericht eine Fehlermeldung angezeigt und die Daten werden nicht angezeigt.

Sofern Sie nicht mit RDL (Report Definition Language, eine Art von XML) vertraut sind, können diese Arten von Fehlern sehr frustrierend sein, wenn Sie den Bericht manchmal unbrauchbar machen.

Es ist weitaus sicherer, die oben genannten Methoden zum Hinzufügen neuer Spalten und Löschen der alten Spalten im Designer zu verwenden. Dies hält Sie von der RDL fern und verringert die Wahrscheinlichkeit, dass der Bericht beschädigt wird.

3
Mac

Ich bin heute auf diese Situation gestoßen, als ich versuchte, Spalten durch Ziehen der Spaltenüberschrift des Tablix neu anzuordnen. Das funktioniert nicht! Ich habe jedoch festgestellt, dass es möglich ist, eine Zelle zu ziehen und (vorsichtig) auf eine andere Zelle abzulegen, bevor die Zellen vertauscht werden. Auf diese Weise können Sie Spalten neu anordnen, indem Sie die Kopf- und Inhaltszellen vertauschen, ohne neue leere Spalten erstellen zu müssen. Dies ist besser, wenn Sie nicht möchten, dass die Breite des Berichtskörpers zunimmt und leere Seiten in PDF = Das Rendern kann natürlich wieder repariert werden. Um eine Zelle zu ziehen, klicken Sie einfach auf die Zelle, gehen Sie aber nicht in den Bearbeitungsmodus, bewegen Sie die Maus über die Ränder und ziehen Sie, sobald Sie den 'Verschieben'-Cursor erhalten. Dies gilt für Berichtsdesigner für Visual Studio 2017 verfügbar.

1
Rajeesh

Meine Lösung:

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);
        }
    }
}

Verwendung:

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