特定ListViewItem的坐标

时间:2011-08-23 05:03:55

标签: wpf listview gridview .net-3.5 listviewitem

这会让我发疯。我有一个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)开始。我不知道为什么。我希望它们在有效位置的可视树中。 有什么建议可以解决这个问题吗?

1 个答案:

答案 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属性中的任何内容。当它为假时,将显示普通的单元格内容。

我不知道你在这个边界内的内容是什么,但是当我这样做以在TextBlockTextBox之间交替时,它看起来与(比如)重命名文件在Windows资源管理器,我认为是你想要的。

您需要处理按键和丢失焦点事件以实现其他编辑就地功能,但是一旦您的布局正常工作,这些问题就相对简单了。