SSRS 디자인 모드에서 테이블 릭스 열을 쉽게 재 배열 할 수있는 방법이 있습니까?
테이블 릭스에 20 개 이상의 열이 포함 된 SSRS 보고서가 있습니다. 사용자는 데이터가 정상이라고 결정했지만 열을 이동하기를 원합니다 ( 한숨! ).
열을 다시 정렬하는 것이 쉬운 것 같습니다 (열 3을 열 1로 이동, 열 4 및 5 교체 등). 그러나 끌어서 놓기가 작동하지 않는 것 같고 유일한 해결책은 원래 열을 삭제하고 올바른 위치에 다시 삽입하는 것입니다 (그리고 열에 대해 이미 생성 된 표현식 및 서식을 다시 적용).
이 작업을 수행하는 더 쉬운 방법이 있습니까? 프로그래밍 방식 솔루션을 원하지는 않지만 디자인 모드에서 한 번만 변경하면됩니다.
디자이너를 통해 열을 이동하는 방법이 있습니다.
- 이동하려는 빈 열의 수를 목적지 지점에 삽입하십시오.
- 이동하려는 셀 (헤더 열 아님)을 Shift- 왼쪽 클릭
- 마우스 오른쪽 버튼을 클릭하고 잘라 내기 명령을 선택합니다.
- 대상 열 상단을 마우스 오른쪽 버튼으로 클릭하고 붙여 넣기를 선택합니다.
- 이제 비어있는 이전 열 삭제
XML을 읽을 수 있다면 (태그의 시작과 끝 등을 이해하기 만하면됩니다) 작업을 쉽게 수행 할 수 있습니다. 다음과 같은 일련의 단계를 수행 할 수 있습니다.
- 먼저 원본 보고서를 다른 파일에 복사하여 백업하십시오.
- 솔루션 탐색기에서 보고서를 마우스 오른쪽 단추로 클릭하고 "코드보기"를 선택합니다.
- 이것은 보고서의 RDL을 엽니 다 --- 단순한 xml 파일 일뿐입니다.
- 이제 RDL 파일에서 "Tablix1"태그를 찾습니다.
<Tablix Name="Tablix1"> ....</Tablix >
- 이제
<Textbox Name="...">...</Texbox>
태그 내에 중첩 된 다른 " "태그 를 찾아야<TablixCells><TablixCell><CellContents>....
합니다. - 이제 단순히 순서를 재정렬하여 보고서의 열을 쉽게 재정렬 할 수
<Textbox...>...</Texbox>
있으며 새 열 순서가 지정된 새 보고서를 갖게됩니다.
사실, 당신은 전체 (잘라 내기 및 붙여 넣기)로 이동해야 <TablixCell>
합니다 (사이에있는 모든 열의 요소 <TablixCell>
와 </TablixCell>
포함 <TablixCell>
및 </TablixCell>
태그 자체).
예를 들어 아래 예의 열을 재 배열하여 "제품 ID"열이 "제품 이름"열 앞에 오도록 하려면 "제품 이름"셀 요소 주변의 전체 섹션을 선택하고 잘라냅니다 (처음 <TablixCell>
부터 제 </TablixCell>
)하고 붙여 후</TablixCell>
은 "제품 ID"열의. 테이블 릭스에 정의 된 각 행에 대한
전체 <TablixCell>
요소 집합이 있습니다. 각각은 별도의 <TablixRow>
요소에 있습니다. 기본 헤더 열 (열 이름이 설정된 위치)을 그대로 둔 경우 첫 번째<TablixRow>
해당 헤더 행을 정의하고 두 번째 행은 열의 데이터를 정의하며 편집하려는 행입니다. 데이터 열을 다시 정렬 한 후에는 헤더 열 (있는 경우)에 대해 동일한 작업을 수행하거나 디자이너를 사용하여 열의 이름을 변경하여 지금 열에있는 데이터와 일치시켜야합니다.
그러나 이것은 너무 복잡해서 디자이너를 사용하여 열을 이동할 새 열을 삽입하고 해당 열에 대한 적절한 데이터 소스로 설정 한 다음 원래 열을 삭제하는 것만으로 열을 이동하는 것이 더 쉬울 것입니다. . 아래 예에서는 Product ID 뒤에 새 열을 삽입 하고 ProductName 데이터 소스 열 (헤더 행에 "Product Name"로 설정 됨)으로 설정 한 다음 왼쪽 의 원래 Product Name 열 을 삭제합니다 .
...
<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 (Report Definition Language, XML 유형)에 익숙하지 않은 경우 이러한 유형의 오류는 보고서를 사용할 수 없게 만드는 경우를 처리하기가 매우 어려울 수 있습니다.
위에서 언급 한 디자이너에서 새 열 추가 및 이전 항목 삭제 방법을 사용하는 것이 훨씬 안전합니다. 이렇게하면 RDL에서 벗어날 수 있으므로 보고서가 손상 될 가능성이 줄어 듭니다.
테이블 릭스의 열 머리글을 끌어서 열 순서를 변경하려고 할 때이 상황이 발생했습니다. 작동하지 않습니다! 그러나 셀을 드래그하여 다른 셀에 (조심스럽게) 드롭 한 다음 셀을 교체 할 수 있음을 발견했습니다. 이렇게하면 새로운 빈 열을 만들지 않고도 머리글과 콘텐츠 셀을 교체하여 열을 다시 정렬 할 수 있습니다. 보고서 본문 너비를 늘리지 않고 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);
}
'programing' 카테고리의 다른 글
Generic Intellisense의 새롭고 완전한 구현 (0) | 2020.11.30 |
---|---|
xpath에서 not contains ()를 사용하는 방법은 무엇입니까? (0) | 2020.11.30 |
Java : String split () : 끝에 빈 문자열을 포함하고 싶습니다. (0) | 2020.11.30 |
null 일 수있는 값을 반환하는 간단한 방법이 있습니까? (0) | 2020.11.29 |
Xcode 9 버그 : cdtool을 찾을 수 없습니다. (0) | 2020.11.29 |