Восстановить положение прокрутки в LongListSelector после tombstone

#windows-phone-7 #silverlight-toolkit #tombstoning

#windows-phone-7 #silverlight-инструментарий #надгробие

Вопрос:

Я пытаюсь работать с элементом управления LongListSelector из инструментария WP7 Silverlight Toolkit. Потребовалось немного поработать, но я наконец-то заставил это работать с моим приложением. К сожалению, у меня возникли некоторые проблемы с правильной обработкой процесса надгробия.

Когда приложение запускает tombstones (или пользователь переходит на другую страницу, выбирая элемент в списке), я сохраняю копию самого верхнего видимого элемента в списке. Я сохраняю его как в переменной класса, так и в коллекции состояний приложения.

 ICollection<object> visibleItems = myLongList.GetItemsInView();
_lastItem = null;
if (visibleItems.Count > 0)
    _lastItem = visibleItems.First();
IDictionary<string, object> state = 
              Microsoft.Phone.Shell.PhoneApplicationService.Current.State;
state["IndexByName_LastTopItem"] = _lastItem;
  

Затем, когда пользователь возвращается на страницу, я проверяю одно из двух значений (состояние или переменная) и использую его для восстановления последнего положения прокрутки.

 if (_lastItem == null) 
{ 
    if (state.ContainsKey("IndexByName_LastTopItem")) 
    { 
        _lastItem = state["IndexByName_LastTopItem"] as Chemical; 
    } 
} 

if (_lastItem != null) 
    Dispatcher.BeginInvoke(() => { myLongList.ScrollTo(_lastItem); }); 
  

Это отлично работает, если только приложение tombstones. В этом случае я не получаю никаких ошибок, но список полностью пуст, пока я не коснусь его и не перетащу. Как только я это сделаю, он повторно отобразится вверху списка. Я взглянул на источник элемента управления и обнаружил, что при вызове .scrollTo (объект) не находит соответствия. Дальнейшее расследование показало, что при поиске элемента для прокрутки сравнивается использование == вместо Equals. Я только переопределил Equals, и, по-видимому, default == сравнивает (по дизайну) ссылки. При восстановлении элемента состояния после надгробия ссылки не совпадают.
Я могу переопределить ==, но это кажется неправильным. Я могу изменить и перестроить источник управления, чтобы вместо этого вызывать equals (я пытался, и это сработало), но это было написано людьми намного умнее меня, и мне интересно, может быть, я просто не понимаю.
Есть ли способ лучше?

Ответ №1:

Это исправление, к которому я в конечном итоге пришел…

Поскольку исходный код находится в свободном доступе для инструментария, я закончил редактированием исходного кода LongListSelector для вызова .Равно вместо ==. Кажется, это работает правильно для моего варианта использования, и я подумал, что поделюсь на случай, если кто-нибудь еще сочтет это полезным…

в LongListSelector.cs найдите функцию GetFlattenedIndex (элемент объекта) и замените

 if (item == _flattenedItems[index].Item)
  

с

 if (item.Equals(_flattenedItems[index].Item))
  

а затем в том же файле найдите функцию GetResolvedIndex(object item, out ContentPresenter ContentPresenter) и замените

 if (node.Value.Content == item)  // Nov 2010 Release
// OR
if (_flattenedItems[index].Item == item)  // Feb 2011 Release
  

с

 if (item.Equals(node.Value.Content))  // Nov 2010 Release
// OR
if (item.Equals(_flattenedItems[index].Item))  // Feb 2011 Release
  

ОБРАТИТЕ внимание, что замена зависит от того, какой набор инструментов вы используете!

Как только вы внесете эти изменения в элемент управления, он будет правильно сопоставлять объекты, указанные в scrollTo (object), даже если ссылки не равны, если вы правильно переопределите Equals для всех типов объектов, отображаемых в вашем LongListSelector. Не забывайте, что это относится к вашему классу группировки, а также к вашему классу элементов, если у вас есть сгруппированный список!

Ответ №2:

Можете ли вы попытаться получить элемент в новом списке?

 var _goodReference = myList.FirstOrDefault(x => x.id == _lastItem.Id);

if (_goodReference != null)     
Dispatcher.BeginInvoke(() => { myLongList.ScrollTo(_goodReference); }); 
  

Комментарии:

1. На первый взгляд это выглядело неплохо. К сожалению, элементы в LongListSelector немного сложнее. Источником списка, по сути, является список <Список<элемент>>, где внешний список — это группировки (отображаются в виде заголовков групп), а внутренний список — элементы для каждой группировки. Таким образом, переменная _lastItem может содержать элемент или список<элемент> в зависимости от текущего положения прокрутки.

2. Можете ли вы обернуть список<Список<Элемент>> в класс с каким-либо пользовательским идентификатором?

3. ДА. Вероятно, вы на пути к решению, которое могло бы сработать. Я просто надеялся получить отзыв о том, что я просто пропустил что-то простое. Восстановление с tombstone кажется излишне сложным. Теперь мне нужно будет обрабатывать восстановление отдельно в зависимости от того, является ли самый верхний видимый элемент заголовком группы или элементом. Это не ракетостроение, но, похоже, его можно улучшить с помощью чего-то такого простого, как scrollTo (intPositionOffsetForTopmostVisibleItem).