Я не знаю у кого как, а у меня с этим делом вылезли проблемы. В одном проекте требовалось сделать так чтобы нельзя было программно крутить вертикальный ScrollBar в TreeList-е. Требовалось потому, что при изменении свойства CurrentNode TreeList почему то начинал сам себя вертеть (добавлю что разобраться почему он так делает мне досконально не удалось ибо нужно было дизасэмблить библиотеку DevExpress да и создавать дочерний TreeList класс чтобы изменить это, что мне собственно очень не хотелось). Фигня, подумал я и замутил событие MouseWheel от горячо любимого TreeList-а. Апосля, подумав, добавил TopVisibleNodeIndexChanged для контроля индекса ScrollBar-а.
Выглядело вот как то так:
Тут как все уже наверно догадались fList - это объект класса DevExpress.XtraTreeList.TreeList и все описанные выше методы являются событиями от него. Поле wheeled - говорит о том крутиться ли Scroll мышью или кто "другой"(один из разработчиков DevExpress?) внезапно захотел это сделать, а поле index запоминает позицию верхнего видимого узла TreeList, что и ясно из названия самого свойства TopVisibleNodeIndex (Ваш К.О.).Выглядело вот как то так:
//отлов пользовательского и программного сролинга при прокрутке колеса мыши private bool wheeled = false; private int index =0; void fList_MouseWheel(object sender, MouseEventArgs e) { wheeled = true; } void fList_TopVisibleNodeIndexChanged(object sender, EventArgs e) { if (!wheeled ) { if (fList.TopVisibleNodeIndex != index) fList.TopVisibleNodeIndex = index; } wheeled = false; } void fList_MouseDown(object sender, MouseEventArgs e) { index = fList.TopVisibleNodeIndex; }
Я сначала было подумал что все уже готово, колесом прокручивается, при селекте узла прокрутки нет, но при экспресс тестировании выявилось, что колесом то прокручивается, а вот мышью прокручивать нажатием на сам ScrollBar нельзя, и вот тут то и понеслась.
Поначалу я хотел использовать тот же MouseDown, ан нет - почему то он при нажатии на ScrollBar не обрабатывается. Да и вообще, как оказалось, public свойства отображающее контрол ScrollBara нет, есть только несколько булевых свойств для управлением видимости вертикального и горизонтального ScrollBara и собственно событие MouseWheel, а так же свойство TopVisibleNodeIndex.
В общем, на то чтобы узнать как это можно сделать, у меня ушло немало времени для такой простейшей задачи, в конце я уже все таки начал гладить взглядом рефлектор и внезапно гугл выдал невиданную вещь. Оказывается таки есть там свойство со ScrollBar-ом и зовут его ScrollInfo. Проблема изначально была в том что оно private и фиг ты его найдешь. В общем остальное оказалось делом техники. Данное свойство содержит объект класса DevExpress.XtraTreeList.Scrolling.ScrollInfo. Собственно при просмотре документации именно он и навел меня на подозрительные мысли по поводу того что там как бы все таки что то да быть должно.
using DevExpress.XtraTreeList;
using DevExpress.XtraTreeList.Scrolling;
class DynamicScrollBlocker
{
//отлов пользовательского и программного сролинга при прокрутке колеса мыши
private bool wheeled = false;
private int index =0;
private bool scrollBarClicked = false;
private TreeList fList;
public DynamicScrollBlocker(TreeList listTree)
{
if(listTree==null) throw new Exception("WTF???!!!11");
fList = listTree;
//находим таки треклятое свойство
var pi = typeof(DevExpress.XtraTreeList.TreeList).GetProperty("ScrollInfo", BindingFlags.NonPublic | BindingFlags.Instance);
//получаем объект ScrollInfo
var info = pi.GetValue(fList, null) as ScrollInfo;
//
info.VScroll.MouseDown += new MouseEventHandler(VScroll_MouseDown);
info.VScroll.MouseUp += new MouseEventHandler(VScroll_MouseUp);
fList.MouseDown += new MouseEventHandler(fList_MouseDown);
fList.TopVisibleNodeIndexChanged += new EventHandler(fList_TopVisibleNodeIndexChanged);
fList.MouseWheel += new MouseEventHandler(fList_MouseWheel);
}
void fList_MouseWheel(object sender, MouseEventArgs e)
{
wheeled = true;
}
void VScroll_MouseUp(object sender, MouseEventArgs e)
{
scrollBarClicked = false;
}
void VScroll_MouseDown(object sender, MouseEventArgs e)
{
scrollBarClicked = true;
}
void fList_TopVisibleNodeIndexChanged(object sender, EventArgs e)
{
if (!wheeled&&!
scrollBarClicked)
{
if (fList.TopVisibleNodeIndex != index)
fList.TopVisibleNodeIndex = index;
}
wheeled = false;
}
void fList_MouseDown(object sender, MouseEventArgs e)
{
index = fList.TopVisibleNodeIndex;
}
}
Волшебство начинается в конструкторе. Примечательно что у объекта ScrollInfo есть свойство VScroll - которое является стандартным Windows.Forms ScrollBar-ом. от него мы и привязываем нужные нам события VScroll_MouseUp и VScroll_MouseDown. Так же легким движением руки в fList_TopVisibleNodeIndexChanged в условие добавляем scrollBarClicked и таки все готово. Наш класс не позволяет неизвестным потокам прокручивать самого себя без помощи пользователя. Единственное замечание касается того что если вы вдруг заходите программно изменять Scroll позицию, например с помощью TopVisibleNodeIndex то тут конечно же все решаемо добавлением какого нибудь булева public свойства для контроля в уже не раз оговоренном событии fList_TopVisibleNodeIndexChanged.