DevExpress XtraGrid FocusedRowChanged проблема события при изменении источника данных
Эта проблема беспокоит меня уже несколько лет, и, возможно, кто-то здесь знает простое решение, так как я только что столкнулся с ней снова.
Вопрос: есть ли способ заставить XtraGrid "забыть" текущий индекс сфокусированной строки, прежде чем Новый (другой) источник данных будет назначен сетке?
Фон
Мы используем XtraGrid как своего рода контроллер для того, что отображается на другой панели многопанельной Winform.
Теперь представьте себе гипотетический сценарий, в котором источник данных XtraGrid продолжает изменяться в соответствии с выбором меню. Пункт меню 1 заполняет сетку списком сегодняшних блюд в кафетерии: Id, имя. Пункт меню 2 заполняет сетку списком клиентов, которым пользователь должен позвонить в этот день: ID, имя. Важно то, что это отдельные различные источники данных, и источник данных сетки назначается и переназначается.
КРИТИЧЕСКИЙ ФАКТ ДЛЯ ЭТОГО ВОПРОСА:
Мы хотим, чтобы событие FocusedRowChanged сетки было единственным местом , где мы ловим выбор пользователя в сетке контроллера. Мы-магазин "без спагетти-кода". FocusedRowChanged лучше, чем событие click, потому что он также обрабатывает навигацию по клавиатуре. Строка с фокусом содержит идентификатор детальной записи, которую мы должны извлечь из базы данных для отображения на панели № 2. Это работает - большую часть времени.
Вот как это не работает: предположим, что в определенный день список клиентов, с которыми пользователь должен связаться, содержит только одну строку. Итак, первое (и только) строка в сетке является сфокусированной строкой. Теперь предположим, что пользователь подходит к меню и выбирает пункт меню, чтобы отобразить основные блюда кафетерия за день. Когда пользователь нажимает на первый элемент в списке Entrees, событие FocusedRowChanged не запускается, поскольку сетка сохранила память индекса сфокусированной строки из предыдущего источника данных. Индекс сфокусированной строки не изменился. И, таким образом, выбор пользователя ничего не вызывает.
Я пытался получить Частое предложить второй ряд более-объектно-ориентированный режим (в отличие от строки-индекс-ориентированный подход), в которой каждая строка в таблице будет иметь GUID и FocusedRowChanged событие будет срабатывать каждый раз, когда идентификатор GUID в настоящее время сосредоточены подряд отличается от идентификатора GUID ранее ориентировались подряд, независимо от того, сосредоточен ряд индекса было то же. Это позволило бы динамическим изменениям источника данных и включило бы желаемое поведение. Но они возражали.
Так что я спрошу своего опять же, есть ли способ заставить XtraGrid "забыть" текущий индекс сфокусированной строки, прежде чем новый источник данных будет назначен сетке?
4 ответов:
Я думаю, что лучшим решением этой проблемы является создание нового объекта GridView и переопределение его метода DoChangeFocusedRowInternal. Ниже вы найдете реализацию этого метода по умолчанию. Все, что вам нужно сделать, это изменить отмеченную строку так, как диктуют ваши потребности. Кроме того, взгляните на статью Как создать класс-потомок GridView и зарегистрировать его для использования во время разработки, она содержит некоторую полезную информацию.
public class MyGridView : GridView { protected override void DoChangeFocusedRowInternal(int newRowHandle, bool updateCurrentRow) { if(this.lockFocusedRowChange != 0) return; if(!IsValidRowHandle(newRowHandle)) newRowHandle = DevExpress.Data.DataController.InvalidRow; if(FocusedRowHandle == newRowHandle) return; // <<<<<< int currentRowHandle = FocusedRowHandle; BeginLockFocusedRowChange(); try { DoChangeFocusedRow(FocusedRowHandle, newRowHandle, updateCurrentRow); } finally { EndLockFocusedRowChange(); } RaiseFocusedRowChanged(currentRowHandle, newRowHandle); } }Обновить
Мой код:
namespace MyXtraGrid { public class MyGridControl : GridControl { protected override BaseView CreateDefaultView() { return CreateView("MyGridView"); } protected override void RegisterAvailableViewsCore(InfoCollection collection) { base.RegisterAvailableViewsCore(collection); collection.Add(new MyGridViewInfoRegistrator()); } } public class MyGridViewInfoRegistrator : GridInfoRegistrator { public override string ViewName { get { return "MyGridView"; } } public override BaseView CreateView(GridControl grid) { return new MyGridView(grid as GridControl); } } public class MyGridView : GridView { public MyGridView(GridControl ownerGrid) : base(ownerGrid) { } public MyGridView() { } protected virtual bool RowEqual(int focusedRowHandle, int newRowHandle) { if(IsDesignMode) return focusedRowHandle == newRowHandle; DataRow row1 = GetDataRow(focusedRowHandle); DataRow row2 = GetDataRow(newRowHandle); return row1 == row2; } protected override void DoChangeFocusedRowInternal(int newRowHandle, bool updateCurrentRow) { if(this.lockFocusedRowChange != 0) return; if(!IsValidRowHandle(newRowHandle)) newRowHandle = DevExpress.Data.DataController.InvalidRow; if(RowEqual(FocusedRowHandle, newRowHandle)) return; int currentRowHandle = FocusedRowHandle; BeginLockFocusedRowChange(); try { DoChangeFocusedRow(FocusedRowHandle, newRowHandle, updateCurrentRow); } finally { EndLockFocusedRowChange(); } RaiseFocusedRowChanged(currentRowHandle, newRowHandle); } } }
Тим, у меня была точно такая же проблема, когда в сетке была только одна строка данных, а затем изменились источники данных. Я решил ее, установив вид сетки.FocusedRowHandle = -1 после установки нового источника данных.
В аналогичной ситуации я подписываюсь на
FocusedRowObjectChangedСобытие (с помощью DevExpress 16.1).
Вы можете подписаться на событие DataSourceChanged, которое будет срабатывать при изменении источника данных (вы угадали!) таким образом, вы можете получить с помощью GetFocusedObject() объект и отобразить соответствующие элементы для другой сетки...
Comments