вторник, 9 октября 2012 г.

DevExpress TreeList и его скролбары или как запретить программно изменять прокрутку

Я не знаю у кого как, а у меня с этим делом вылезли проблемы. В одном проекте требовалось сделать так чтобы нельзя было программно крутить вертикальный ScrollBar в TreeList-е. Требовалось потому, что при изменении свойства CurrentNode TreeList почему то начинал сам себя вертеть (добавлю что разобраться почему он так делает мне досконально не удалось ибо нужно было дизасэмблить библиотеку DevExpress да и создавать дочерний TreeList класс чтобы изменить это, что мне собственно очень не хотелось). Фигня, подумал я  и замутил событие MouseWheel от горячо любимого TreeList-а. Апосля, подумав, добавил TopVisibleNodeIndexChanged для контроля индекса ScrollBar-а.
Выглядело вот как то так:
//отлов пользовательского и программного сролинга при прокрутке колеса мыши
        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;
        }
Тут как все уже наверно догадались   fList - это объект класса DevExpress.XtraTreeList.TreeList и все описанные выше методы являются событиями от него. Поле wheeled  - говорит о том крутиться ли Scroll мышью или кто "другой"(один из разработчиков DevExpress?) внезапно захотел это сделать, а поле index запоминает позицию верхнего видимого узла TreeList, что и ясно из названия самого свойства 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.

вторник, 28 августа 2012 г.

Использование TFS c нескольких компьютеров в локальной сети с единым workspace

Небольшая заметка по поводу Team Foundation Server и его знаменитых workspaces:
Если вы программируете с контролером версии от Microsoft,  естественно c EDI Visual Studio, в локальной сети на нескольких компьютерах, то у вас могут возникнуть проблемы со средой разработки т.к. на один логин и пароль от TFS вас привяжут к одному компьютеру. И синхронихировать работу над одним проектом с двух машин непредставляется возможным. Но выход таки есть:
1. Вам понадобиться создать сетевой диск на всех машинах в локальной сети которые будут использовать единые логин и пароль для TFS. Данный сетевой диск слудует привязать к папке где лежит ваш проект. В моем случае я создал сетевой диск Z: и присвоил ему всю папку work  со всеми моими проектами для единого сервера TFS.
2. Далее на каждой машине кто будет юзать этот проект от одного пользователя, следует создать   Environmental variable для пользователя. а именно: _CLUSTER_NETWORK_NAME_=<имя компьютера с которого вы всегда пользовали TFS>

И вуоля! Теперь я могу работать и на стационаре и на лаптопе с одними пользовательскими данными.