Tablixに20を超える列を含むSSRSレポートがあります。ユーザーはデータは問題ないと判断しましたが、列を移動することを望んでいます(sigh!)。
列を簡単に再配置する必要があるようです(列3を列1に移動し、列4と5を交換するなど)。しかし、ドラッグアンドドロップは機能していないようで、唯一の解決策は元の列を削除して正しい場所に再挿入することです(そして列に対して既に作成された式と書式を再適用します)。
これを行う簡単な方法はありますか?プログラムによる解決策は必要ないが、デザインモードで一度変更するだけでよいことに注意してください。
デザイナーを介して列を移動する方法があります。
XMLを読み取ることができる場合(タグの開始位置または終了位置などを理解するだけ)、タスクを簡単に達成できます。次の一連の手順を実行できます。
<Tablix Name="Tablix1"> ....</Tablix >
を探します<Textbox Name="...">...</Texbox>
タグ内にネストされたさまざまな「<TablixCells><TablixCell><CellContents>....
」タグを探す必要があります<Textbox...>...</Texbox>
の順序を再配置するだけで、レポートの列を簡単に再配置でき、新しい列の順序で新しいレポートを作成できます。実際には、列の<TablixCell>
要素全体(<TablixCell>
と</TablixCell>
を含む<TablixCell>
と</TablixCell>
の間のすべてを移動(カットアンドペースト)する必要があります。タグ自体)。
たとえば、次の例の列を並べ替えて「製品ID」列を作成するには、「before「製品名」列」を選択し、「ProductName」セル要素の周りのセクション全体を選択して切り取ります。 (最初の<TablixCell>
から最初の</TablixCell>
まで)を貼り付け、それを貼り付けます後「ProductID」列の</TablixCell>
.
Tablixで定義されている各行には、<TablixCell>
要素の完全なセットがあることに注意してください。それぞれが個別の<TablixRow>
要素にあります。デフォルトのヘッダー列(列名が設定されている)を残した場合、最初の<TablixRow>
はそのヘッダー行を定義し、2番目は列のデータを定義し、それが編集したいものです。データ列を再配置したら、ヘッダー列(同じ場合)に対して同じことを行うか、デザイナーを使用して列の名前を変更し、列のデータを一致させる必要があります。
実際には、これは非常に複雑であるため、列を移動する場所にデザイナーを使用して新しい列を挿入し、その列の適切なデータソースで設定してから元の列を削除するだけで、列を移動する方がおそらく簡単です。以下の例では、製品IDの後に新しい列を挿入し、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>
...
RDLでの作業に関する別の注意:
間違えた場合、レポートにはエラーメッセージが表示され、データは表示されません。
RDL(XMLの一種であるレポート定義言語)に精通していない限り、これらのタイプのエラーは、レポートを使用できなくすることがあるため、非常にイライラする可能性があります。
上記のように、デザイナーで新しい列を追加して古い列を削除する方がはるかに安全です。これにより、RDLにアクセスできなくなり、レポートが破損する可能性が低くなります。
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);
}