5

如何提取 ListBoxItem 的父容器?在下面的示例中,我可以一直到 ListBoxItem,比我得到的更高:

<ListBox Name="lbAddress">
  <ListBox.ItemTemplate>
    <DataTemplate>
      <Button Click="Button_Click"/>
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>

Private Sub Button_Click(sender As Button, e As RoutedEventArgs)
  Dim lbAddress = GetAncestor(Of ListBox) 'Result: Nothing
End Sub

Public Shared Function GetAncestor(Of T)(reference As DependencyObject) As T
  Dim parent = GetParent(reference)

  While parent IsNot Nothing AndAlso Not parent.GetType.Equals(GetType(T))
    parent = GetAncestor(Of T)(parent)
  End While

  If parent IsNot Nothing Then _
    Return If(parent.GetType Is GetType(T), parent, Nothing) 

  Return Nothing    
End Sub

Public Function GetParent(reference As DependencyObject) As DependencyObject
  Dim parent As DependencyObject = Nothing

 If TypeOf reference Is FrameworkElement Then
    parent = DirectCast(reference, FrameworkElement).Parent
  ElseIf TypeOf reference Is FrameworkContentElement Then
    parent = DirectCast(reference, FrameworkContentElement).Parent
  End If

  Return If(parent, VisualTreeHelper.GetParent(reference))
End Function

更新

这就是发生的事情(请注意,“父”变量保持为空):

这是它的样子

4

4 回答 4

4

lbAddress.ItemsSource很明显,在单击按钮期间正在删除某个项目。问题是,什么?仔细查看您发布的图像会发现答案。这是您的代码中的错误:

My.Context.DeleteObject(context)
My.Context.SaveChanges()

   ...

btn.GetVisualAncestor(...)

前两行更新您的数据模型。这会立即从可视树中删除 ListBoxItem。当您稍后调用 GetVisualAncestor 以查找 ListBox 时,它会失败,因为 ListBoxItem 不再具有任何类型的父级。

我确信解决方案现在对您来说是显而易见的:只需在从数据模型中删除数据之前找到 ListBox 祖先,您就可以开始了。

于 2010-04-15T00:52:15.663 回答
3

罪魁祸首似乎是您的 GetParent 函数,它使用 Parent 属性而不是 VisualTreeHelper.GetParent。Parent 属性返回逻辑父级,而不是可视父级,因此在尝试遍历 DataTemplate 时将返回 null。(也不清楚 GetVisualAncestor 是如何实现的——或者这是 GetAncestor 的拼写错误?)始终使用 VisualTreeHelper.GetParent,忘记 Parent 属性。例如,以下代码适用于我:

XAML:

<DataTemplate x:Key="SimpleItemTemplate">
  <Button Click="Button_Click">In DataTemplate</Button>
</DataTemplate>

后面的代码:

private void Button_Click(object sender, RoutedEventArgs e)
{
  Button btn = (Button)sender;
  ListBox lb = FindAncestor<ListBox>(btn);
  Debug.WriteLine(lb);
}

public static T FindAncestor<T>(DependencyObject from)
  where T : class
{
  if (from == null)
  {
    return null;
  }

  T candidate = from as T;
  if (candidate != null)
  {
    return candidate;
  }

  return FindAncestor<T>(VisualTreeHelper.GetParent(from));
}

当我运行它时,lbClick 处理程序中的 ListBox 变量 () 被设置为正确的非空值。

于 2010-04-13T21:37:31.253 回答
1

Parent属性返回逻辑父级。您应该使用可视父级,因为在某些情况下逻辑父级将为空。例如,在您的情况下Parent,按钮的属性返回 null。

来自 MSDN

在元素被实例化但未附加到最终连接到页面级根元素或应用程序对象的任何逻辑树的情况下,Parent 可能为 null。

由于该FrameworkElement.VisualParent属性受到保护,您可以使用以下VisualTreeHelper.GetParent方法:

<System.Runtime.CompilerServices.Extension> _
Public Shared Function FindAncestor(Of T As DependencyObject)(ByVal obj As DependencyObject) As T
    Return TryCast(obj.FindAncestor(GetType(T)), T)
End Function

<System.Runtime.CompilerServices.Extension> _
Public Shared Function FindAncestor(ByVal obj As DependencyObject, ByVal ancestorType As Type) As DependencyObject
    Dim tmp = VisualTreeHelper.GetParent(obj)
    While tmp IsNot Nothing AndAlso Not ancestorType.IsAssignableFrom(tmp.[GetType]())
        tmp = VisualTreeHelper.GetParent(tmp)
    End While
    Return tmp
End Function
于 2010-04-13T21:38:17.003 回答
1

至于公认的 hacky 仅限 XAML 的解决方案,您可以使用 Style setter 将父级填充ListBoxListBoxItem's Tag属性中(如果您没有将其用于任何其他目的):

<ListBox Name="w_listbox" ItemsSource="{Binding MyItems}">
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
            <Setter Property="Tag" Value="{Binding ElementName=w_listbox}" />
        </Style>
    </ListBox.ItemContainerStyle>
    <!-- etc, i.e.... !-->
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <TextBlock Grid.Column="0" Text="{Binding MyFoo}"></TextBlock>
            <TextBlock Grid.Column="1" Text="{Binding MyBar}"></TextBlock>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>
于 2012-01-10T08:36:08.713 回答