Похоже, это связано с своего рода известным, но недостаточно хорошо описанным проблемным поведением с ListView (и, возможно, некоторыми другими элементами управления WPF).Требуется, чтобы приложение вызывало Focus()
для определенного ListViewItem после программной установки SelectedItem.
Но сам SelectedItem не является элементом UIE.Это элемент того, что вы отображаете в ListView, часто это пользовательский тип.Поэтому вы не можете позвонить this.listView1.SelectedItem.Focus()
.Это не сработает.Вам нужно получить UIElement (или элемент управления), который отображает этот конкретный элемент.Темный угол интерфейса WPF называется ItemContainerGenerator , который предположительно позволяет получить элемент управления, отображающий определенный элемент в ListView.
Примерно так:
this.listView1.SelectedItem = thing;
// *** WILL NOT WORK!
((UIElement)this.listView1.ItemContainerGenerator.ContainerFromItem(thing)).Focus();
Но есть и вторая проблема - она не работает сразу после установки SelectedItem.ItemContainerGenerator.ContainerFromItem () всегда возвращает null.В других местах гуглпространства люди сообщали, что он возвращает значение null с установленным GroupStyle.Но это проявилось со мной, без группировки.
ItemContainerGenerator.ContainerFromItem()
возвращает ноль для всех объектов, отображаемых в списке.Также ItemContainerGenerator.ContainerFromIndex()
возвращает ноль для всех признаков.Что необходимо, это вызывать эти вещи только после того, как ListView будет визуализирован (или что-то еще).
Я пытался сделать это напрямую через Dispatcher.BeginInvoke()
, но это тоже не работает.
По предложению некоторых других потоков я использовал Dispatcher.BeginInvoke()
из события StatusChanged
на ItemContainerGenerator
.Да, просто, да?(Не)
Вот как выглядит код.
MyComplexType current;
private void SelectThisItem(string value)
{
foreach (var item in collectionView) // for the ListView in question
{
var thing = item as MyComplexType;
if (thing.StringProperty == value)
{
this.listView1.ItemContainerGenerator.StatusChanged += icg_StatusChanged;
this.listView1.SelectedItem = thing;
current = thing;
return;
}
}
}
void icg_StatusChanged(object sender, EventArgs e)
{
if (this.listView1.ItemContainerGenerator.Status
== System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated)
{
this.listView1.ItemContainerGenerator.StatusChanged
-= icg_StatusChanged;
Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Input,
new Action(()=> {
var uielt = (UIElement)this.listView1.ItemContainerGenerator.ContainerFromItem(current);
uielt.Focus();}));
}
}
Это некрасивый код.Но программная установка SelectedItem таким образом позволяет последующей навигации по стрелкам работать в ListView.