Итак, я нашел решение, которое работает довольно хорошо. Я создал свое собственное «дерево групп», используя ListBox
, и расположил его рядом с CrystalReportViewer
, скрывая зрителей GroupTree
. ListBox
поддерживает как собственную позицию прокрутки, так и текущий выбор. Дополнительный бонус при таком подходе заключается в том, что пользователи могут использовать клавиши со стрелками для навигации по GroupTree
, если он имеет фокус.
Мой метод реализации выглядит следующим образом:
Я добавил на страницу стандартный элемент управления ListBox
и расположил его слева от CrystalReportViewer
. Разметка выглядит следующим образом:
<asp:ListBox ID="lstStockCode" runat="server" Width="185px" Height="760px" Font-Size="10pt" AutoPostBack="true" OnSelectedIndexChanged="lstStockCode_SelectedIndexChanged" DataTextField="StockCode" DataValueField="ID" BackColor="#E4E4EC" style="position: relative; top: 30px; border-width: 0px;" Visible="false"></asp:ListBox>
CrystalReportViewer
изначально скрыт до тех пор, пока не будут выбраны критерии отчета, и в этот момент как Viewer, так и ListBox
станут видимыми.
Затем свяжите ListBox
с источником данных, который возвращает те же данные, что и отчет. В моем случае я создал метод для получения фондовых кодов, используя тот же SQL-запрос, что и хранимая процедура, с которой связан мой отчет.
Наконец, найдите в отображаемом отчете значение, выбранное в ListBox
. Ниже приведен пример события SelectedIndexChanged:
protected void lstStockCode_SelectedIndexChanged(object sender, EventArgs e)
{
if (ViewState["PrevListIndex"] == null)
CrystalReportViewer1.SearchAndHighlightText(lstStockCode.SelectedItem.Text, CrystalDecisions.Shared.SearchDirection.Forward);
else if (Convert.ToInt32(ViewState["PrevListIndex"]) < lstStockCode.SelectedIndex)
CrystalReportViewer1.SearchAndHighlightText(lstStockCode.SelectedItem.Text, CrystalDecisions.Shared.SearchDirection.Forward);
else if (Convert.ToInt32(ViewState["PrevListIndex"]) > lstStockCode.SelectedIndex)
CrystalReportViewer1.SearchAndHighlightText(lstStockCode.SelectedItem.Text, CrystalDecisions.Shared.SearchDirection.Backward);
ViewState["PrevListIndex"] = lstStockCode.SelectedIndex;
CrystalReportViewer1.ToolbarStyle.Width = Unit.Parse("1096px");
lstStockCode.Focus();
}
Поскольку для CrystalReportViewer
необходимо указать направление поиска, я просто сохраняю свой текущий поисковый индекс и определяю, веду ли я поиск вниз или назад в отчете, поскольку мой ListBox
возвращается с использованием того же самого запрос как мой отчет и, следовательно, в том же порядке, что и данные отчета.
Несколько вещей, представляющих интерес для этой реализации, в основном с точки зрения стиля. Прилагаемый код не предусматривает изменение положения CrystalReportViewer Toolbar
. В то время как ListBox
находится в соответствии с отчетом, над ним есть только те пробелы, где обычно находится Toolbar
. Кроме того, TreeView-подобные пунктирные линии не отображаются внутри ListBox
. Я не играл с использованием TreeView
элемента управления вместо ListBox
для достижения того же эффекта, но я считаю, что это очень выполнимо.
Даже с учетом этих различий с точки зрения внешнего вида клиент не знал, что для достижения этой цели был создан новый элемент управления.