这会让我发疯。我有一个WPF ListView,我尝试通过双击单元格覆盖TextBox来模拟编辑器。到目前为止这个工作正常。我调用ListView.InputHitTest(e.Position)来获取被点击的项目。从那里我使用VisualTreeHelper.GetParent()来浏览VisualTree并解析坐标。精细。
现在我想,如果用户按下光标,该TextBox将移动到下一个Item。我尝试了以下尝试:
ListView.ItemContainerGenerator.ContainerFromIndex(index + 1)
ListView.ItemContainerGenerator.ContainerFromItem(…)
但是两个方法都返回null(VB中没有Nothing),但ListView.ItemContainerGenerator.Status返回ContainersGenerated。 如何获取特定ListViewItem的坐标?
顺便说一句:我仅限于Framework 3.5,因此4.0中的Grid不可用。另外,我不想使用第三方工具。
修改
这是我使用的一些(实验性)代码:
我使用周围的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
所以当我需要重新安排TextBox时,我在代码中的位置(PreviewKeyDown-Event),但在这个例程中,我无法获得方法的结果
ListView.ItemContainerGenerator.ContainerFromIndex(index + 1)和
ListView.ItemContainerGenerator.ContainerFromItem(...)
进一步测试:
我在ListViewItem的简单列表中创建了一个继承ListView并缓存ListViewItems的类
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)开始。我不知道为什么。我希望它们在有效位置的可视树中。 有什么建议可以解决这个问题吗?
答案 0 :(得分:2)
不要那样做。
好的,如果你真的想,那就去做吧。但是有一种更容易的方式。
向视图模型添加布尔IsEditing
和字符串EditableContent
属性。创建一个如下所示的数据模板:
<DataTemplate>
<Grid>
<Border>
<!-- normal cell content goes here -->
</Border>
<TextBox Text="{Binding EditableContent, Mode=TwoWay}">
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="Visibility" Value="Hidden"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsEditing}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox>
<Grid>
</DataTemplate>
当IsEditing
属性为true时,将显示TextBox
,用户可以编辑EditableContent
属性中的任何内容。当它为假时,将显示普通的单元格内容。
我不知道你在这个边界内的内容是什么,但是当我这样做以在TextBlock
和TextBox
之间交替时,它看起来与(比如)重命名文件在Windows资源管理器,我认为是你想要的。
您需要处理按键和丢失焦点事件以实现其他编辑就地功能,但是一旦您的布局正常工作,这些问题就相对简单了。