Это сведет меня с ума. У меня есть WPF ListView, и я пытаюсь наложить TextBox на ячейку с двойным щелчком для эмуляции редактора. Пока все работает нормально. Я вызываю ListView.InputHitTest (e.Position), чтобы получить нажатый элемент. Оттуда я использую VisualTreeHelper.GetParent (), чтобы перемещаться по VisualTree и разрешать координаты. Хорошо.
Теперь я хочу, чтобы, если пользователь нажимал курсор вниз, этот TextBox перемещался к следующему элементу. Я попробовал следующие попытки:
ListView.ItemContainerGenerator.ContainerFromIndex(index + 1)
ListView.ItemContainerGenerator.ContainerFromItem(…)
Но оба метода возвращают ноль (Ничего в VB), но ListView.ItemContainerGenerator.Status возвращает ContainersGenerated.
Как я могу получить координаты определенного ListViewItem?
Кстати: я ограничен Framework 3.5, поэтому Grid в 4.0 недоступен. Кроме того, я не хочу использовать сторонние инструменты.
Редактировать
Вот некоторый (экспериментальный) код, который я использую:
Я использую окружающий Canvas, чтобы легко расположить TextBox над ListView. Я включил DataTemplate первого столбца. Остальное довольно похоже, поэтому я удалил этот код. Кроме того, я удалил некоторые определения стилей и конвертеры - я не думаю, что они здесь представляют какой-либо интерес.
<Canvas x:Name="Canvas">
<ListView ItemsSource="{Binding MyListViewList}"
Name="ListView"
MouseDoubleClick="ListView_MouseDoubleClick">
<ListView.Resources>
<DataTemplate x:Key="NameTemplate">
<Border Name="NameBorder">
<!-- Some content for this cell here -->
</Border>
</DataTemplate>
</ListView.Resources>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
<Setter Property="VerticalContentAlignment" Value="Stretch"></Setter>
<Setter Property="IsSelected" Value="{Binding IsSelected}"></Setter>
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="Name" x:Name="colName"
CellTemplate="{StaticResource NameTemplate}"></GridViewColumn>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
<TextBox Name="EditorTextBox"
Visibility="Hidden"
BorderThickness="0">
</TextBox>
</Canvas>
Я регистрирую PreviewKeyDown, чтобы перехватить нажатие клавиши Cursor-Down:
Private Sub TextBox_PreviewKeyDown(ByVal sender As Object, ByVal e As KeyEventArgs)
Dim model As MyListViewModel
model = CType(DataContext, MyListViewModel)
Select Case e.Key
Case Key.Down
Dim lvp As MyListViewParameter
If Me.editorSelectedItemIndex + 1 < model.MyListViewList.Count Then
lvp = model.MyListViewList(Me.editorSelectedItemIndex + 1)
' How to position EditorTextBox to the next ListViewItem here?
' The following methods return null/Nothing:
' ListView.ItemContainerGenerator.ContainerFromIndex(editorSelectedItemIndex + 1)
' ListView.ItemContainerGenerator.ContainerFromItem(lvp)
End If
e.Handled = True
Case Key.Up
End Select
End Sub
Итак, у меня есть позиция в коде (PreviewKeyDown-Event), когда мне нужно переставить TextBox, но внутри этой процедуры я не могу получить результат от методов
ListView.ItemContainerGenerator.ContainerFromIndex (index + 1) и
ListView.ItemContainerGenerator.ContainerFromItem (...)
Дальнейшие испытания:
Я написал класс, который наследует ListView и кэширует ListViewItems, когда они создаются в простом списке ListViewItem
Public Class ExtListView
Inherits ListView
Public Sub New()
Dim ic = TryCast(Me.Items, System.Collections.Specialized.INotifyCollectionChanged)
If Not ic Is Nothing Then
AddHandler ic.CollectionChanged, AddressOf NotifyCollectionChangedEventHandler
End If
AddHandler Me.ItemContainerGenerator.StatusChanged, AddressOf ItemContainerGenerator_ItemsChanged
_ListViewItems = New List(Of ListViewItem)
End Sub
Private _listViewItems As List(Of ListViewItem)
Public ReadOnly Property ListViewItems As List(Of ListViewItem)
Get
Return _listViewItems
End Get
End Property
Private Sub ItemContainerGenerator_ItemsChanged(ByVal sender As Object, ByVal e As EventArgs)
If Me.ItemContainerGenerator.Status = Primitives.GeneratorStatus.ContainersGenerated Then
_listViewItems.Clear()
For index = 0 To Me.Items.Count - 1
_listViewItems.Add(CType(ItemContainerGenerator.ContainerFromIndex(index), ListViewItem))
Next
End If
End Sub
End Class
При наличии этих ListViewItems я попытался определить их границы:
Dim bounds As Rect = VisualTreeHelper.GetDescendantBounds(ListView.ListViewItems(editorSelectedItemIndex + 1))
Но, тем не менее, все прямоугольники начинаются с x, y-позиции (0, 0). Понятия не имею почему. Я ожидал, что они будут в визуальном дереве в правильной позиции.
Любые предложения, чтобы решить эту проблему?