5

ListBoxItemの親コンテナを抽出するにはどうすればよいですか?次の例では、ListBoxItemまで移動できますが、それより高い場合はNothingを取得します。

<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

アップデート

これが起こります(「親」変数はnullのままであることに注意してください):

こんな感じ

4

4 に答える 4

4

lbAddress.ItemsSourceボタンのクリック中に何かがアイテムを削除していることは明らかです。問題は、ですか?あなたが投稿した画像をよく見ると、答えが明らかになります。コードのバグは次のとおりです。

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

   ...

btn.GetVisualAncestor(...)

最初の 2 行は、データ モデルを更新します。これにより、ビジュアル ツリーから ListBoxItem がすぐに削除されます。後で GetVisualAncestor を呼び出して ListBox を見つけると、ListBoxItem にはどのような種類の親も存在しないため失敗します。

データ モデルからデータを削除する前に、ListBox の祖先を見つけるだけでよいのです。

于 2010-04-15T00:52:15.663 に答える
3

犯人は、VisualTreeHelper.GetParent の代わりに Parent プロパティを使用する 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));
}

これを実行するとlb、Click ハンドラーの ListBox 変数 ( ) が null 以外の正しい値に設定されます。

于 2010-04-13T21:37:31.253 に答える
1

Parentプロパティは論理を返します。論理的な親がnullになる場合があるため、視覚的な親を使用する必要があります。たとえば、あなたの場合、Parentボタンのプロパティはnullを返します。

MSDNから

要素がインスタンス化されたが、最終的にページレベルのルート要素またはアプリケーションオブジェクトに接続する論理ツリーに接続されていない場合、親は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

確かにハックな XAML のみのソリューションについては、Style セッターを使用して、親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 に答える