У меня есть отчет о SSRS, который содержит больше чем 20 столбцов в tablix. Наши пользователи решили, что данные в порядке, но они хотят перемещенные столбцы (вздох!).
Кажется, что должно быть легко перестроить столбцы (переместите столбец 3 в столбец 1, подкачайте столбцы 4 и 5 и т.д.). Но, перетаскивание, кажется, не работает, и единственное решение, кажется, удаляет первоначальный столбец и повторно вставляет его в корректное место (и повторно применяет любые выражения и форматирует уже созданный для столбца).
Есть ли какой-либо более легкий способ сделать это? Обратите внимание на то, что я не хочу программного решения, но просто должен изменить его однажды в режиме проектирования.
Я столкнулся с этой ситуацией сегодня, когда я пытался переупорядочить столбцы путем перетаскивания заголовка столбца tablix, это не работает! Однако я обнаружил, что возможно перетащить ячейку и (тщательно) отбросить его на другой ячейке затем подкачка ячеек. Таким образом, можно перестроить столбцы путем свопинга заголовка и ячеек содержания, не имея необходимость создавать новые пустые столбцы, который лучше, если Вы не хотите, чтобы ширина тела отчета увеличила и произвела пустые страницы в рендеринге PDF, конечно, это может быть зафиксировано снова. Чтобы перетащить ячейку, одиночное нажатие на ячейке, но не ввести режим редактирования, затем мышь при наведении курсора вокруг границ и перетащить после того как, Вы получаете курсор 'перемещения'. Это применимо к конструктору отчетов, доступному для Visual Studio 2017.
Мое решение:
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);
}