Подтвердить что ты не робот

Есть ли простой способ переупорядочить столбцы таблиц в режиме проектирования SSRS?

У меня есть отчет SSRS, содержащий более 20 столбцов в таблице. Наши пользователи решили, что данные в порядке, но они хотят, чтобы столбцы перемещались (вздох!).

Кажется, что нужно легко перестроить столбцы (переместить столбец 3 в столбец 1, обменять столбцы 4 и 5 и т.д.). Но перетаскивание не работает, и единственное решение, похоже, удаляет исходный столбец и снова вставляет его в нужное место (и повторно применяет любые выражения и форматирование, уже созданные для столбца).

Есть ли более простой способ сделать это? Обратите внимание, что я не хочу программного решения, но просто нужно изменить его один раз в режиме разработки.

4b9b3361

Ответ 1

Существует способ перемещения столбцов через конструктор:

  1. введите количество пустых столбцов, которые вы хотите переместить в место назначения
  2. shift-left-click на ячейки (НЕ в столбце заголовка), которые вы хотите переместить
  3. щелкните правой кнопкой мыши и выберите команду "Вырезать"
  4. щелкните правой кнопкой мыши в верхней части столбцов назначения и выберите Вставить
  5. удалить теперь пустые старые столбцы

Ответ 2

Если вы можете читать XML (просто понимаете, где начинаются и заканчиваются теги и т.д.), Вы легко можете выполнить задачу. Вы можете предпринять следующие шаги:

  1. Прежде всего сделайте резервную копию исходного отчета, скопировав его в другой файл.
  2. Щелкните правой кнопкой мыши свой отчет в обозревателе решений и выберите "Просмотреть код"
  3. Это открывает RDL отчета - не пугайтесь, это всего лишь простой XML файл
  4. Теперь найдите в файле RDL тег "Tablix1" - найдите <Tablix Name="Tablix1">....</Tablix >
  5. Теперь вам нужно искать разные теги " <Textbox Name="...">...</Texbox> ", вложенные в теги <TablixCells><TablixCell><CellContents>....
  6. Теперь вы можете легко изменить порядок столбцов отчета, просто изменив порядок этих <Textbox...>...</Texbox> и вы получите новый отчет с новым порядком столбцов.

Ответ 3

На самом деле вам нужно переместить (вырезать и вставить) весь элемент <TablixCell> для столбца (все между <TablixCell> и </TablixCell>, включая теги <TablixCell> и </TablixCell>).

Например, чтобы переупорядочить столбцы в приведенном ниже примере, чтобы столбец "Идентификатор продукта" пришел до в столбце "Имя продукта", вы должны выбрать и разрезать весь раздел вокруг "ProductName" "элемент ячейки (все от первого <TablixCell> до первого </TablixCell>), а затем вставьте после </TablixCell> для столбца" ProductID ".
Обратите внимание, что существует полный набор элементов <TablixCell> для каждой строки, определенной в Tablix; каждый из них находится в отдельном элементе <TablixRow>. Если вы оставили столбец заголовка по умолчанию (где установлены имена столбцов), то первый <TablixRow> определяет эту строку заголовка, а второй определяет данные в столбцах, и это тот, который вы хотите отредактировать. После того, как вы изменили столбцы данных, вам потребуется либо сделать то же самое для столбца заголовка (если он у вас есть), либо просто переименовать столбцы, используя конструктор, чтобы сопоставлять данные в столбцах.

Действительно, это настолько запутанно, что, возможно, проще перемещать столбец, просто используя конструктор, чтобы вставить новый столбец, куда вы хотите переместить столбец, установить его с соответствующим источником данных для этого столбца, а затем удалить оригинальная колонка. В следующем примере вы введете новый столбец после Идентификатор продукта, установите его в столбец источника данных ProductName (который будет устанавливать его "Имя продукта" в строке заголовка), а затем удалите исходный столбец Имя продукта слева.

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

после вырезания/вставки, вы в итоге получите:

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

Ответ 4

Еще одна заметка о работе в RDL:
Если вы ошибетесь, отчет отобразит сообщение об ошибке и не отобразит данные.

Если вы не знакомы с RDL (языком определения отчета, типом XML), эти типы ошибок могут очень расстраивать, чтобы иногда обрабатывать отчет, который не может использоваться.

Намного безопаснее использовать новые столбцы и удалить старый метод в упомянутом выше дизайнере. Это избавляет вас от RDL, уменьшая ваши шансы повредить отчет.

Ответ 5

Я столкнулся с этой ситуацией сегодня, когда пытался изменить порядок столбцов, перетаскивая заголовок столбца таблицы, это не работает! Однако я обнаружил, что можно перетащить ячейку и (осторожно) поместить ее в другую ячейку, а затем поменять ячейки. Таким образом, вы можете переупорядочивать столбцы, меняя ячейки заголовка и содержимого без необходимости создавать новые пустые столбцы, что лучше, если вы не хотите, чтобы ширина тела отчета увеличивалась, и создавались пустые страницы при рендеринге PDF, конечно, это можно исправить снова. Чтобы перетащить ячейку, щелкните ее один раз, но не переходите в режим редактирования, затем наведите курсор мыши на границы и перетащите, как только вы получите курсор перемещения. Это применимо к конструктору отчетов, доступному для Visual Studio 2017.

Ответ 6

Мое решение:

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

Использование:

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