36

ListBox コントロールがあり、一定数の ListBoxItem オブジェクトをグリッド レイアウトで表示しています。そこで、ItemsPanelTemplate をグリッドに設定しました。

コード ビハインドからグリッドにアクセスして、RowDefinitions と ColumnDefinitions を構成しています。

これまでのところ、すべてが期待どおりに機能しています。各 ListBoxItem が表示される Grid.Row と Grid.Column を返すためのカスタム IValueConverter 実装がいくつかあります。

ただし、奇妙なバインディング エラーが発生することがあります。エラーが発生している理由や、コード内にエラーがあるかどうかさえも正確にわかりません。

エラーは次のとおりです。

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.ItemsControl', AncestorLevel='1''. BindingExpression:Path=HorizontalContentAlignment; DataItem=null; target element is 'ListBoxItem' (Name=''); target property is 'HorizontalContentAlignment' (type 'HorizontalAlignment')

誰が何が起こっているのか説明できますか?

ああ、これが私の XAML です。

<UserControl.Resources>
    <!-- Value Converters -->
    <v:GridRowConverter x:Key="GridRowConverter" />
    <v:GridColumnConverter x:Key="GridColumnConverter" />
    <v:DevicePositionConverter x:Key="DevicePositionConverter" />
    <v:DeviceBackgroundConverter x:Key="DeviceBackgroundConverter" />

    <Style x:Key="DeviceContainerStyle" TargetType="{x:Type ListBoxItem}">
        <Setter Property="FocusVisualStyle" Value="{x:Null}" />
        <Setter Property="Background" Value="Transparent" />

        <Setter Property="Grid.Row" Value="{Binding Path=DeviceId, Converter={StaticResource GridRowConverter}}" />
        <Setter Property="Grid.Column" Value="{Binding Path=DeviceId, Converter={StaticResource GridColumnConverter}}" />

        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ListBoxItem}">
                    <Border CornerRadius="2" BorderThickness="1" BorderBrush="White" Margin="2" Name="Bd"
                            Background="{Binding Converter={StaticResource DeviceBackgroundConverter}}">
                        <TextBlock FontSize="12" HorizontalAlignment="Center" VerticalAlignment="Center" 
                                Text="{Binding Path=DeviceId, Converter={StaticResource DevicePositionConverter}}" >
                            <TextBlock.LayoutTransform>
                                <RotateTransform Angle="270" />
                            </TextBlock.LayoutTransform>
                        </TextBlock>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsSelected" Value="true">
                            <Setter TargetName="Bd" Property="BorderThickness" Value="2" />
                            <Setter TargetName="Bd" Property="Margin" Value="1" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>            
    </Style>        
</UserControl.Resources>

<Border CornerRadius="3" BorderThickness="3" Background="#FF333333" BorderBrush="#FF333333" >
    <Grid ShowGridLines="False">
        <Grid.RowDefinitions>
            <RowDefinition Height="15" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <StackPanel Grid.Row="0" Orientation="Horizontal">
            <Image Margin="20,3,3,3" Source="Barcode.GIF" Width="60" Stretch="Fill" />
        </StackPanel>

        <ListBox ItemsSource="{Binding}" x:Name="lstDevices" Grid.Row="1" 
                 ItemContainerStyle="{StaticResource DeviceContainerStyle}"
                 Background="#FF333333"
                 SelectedItem="{Binding SelectedDeviceResult, ElementName=root, Mode=TwoWay}" >
            <ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <Grid>
                        <Grid.LayoutTransform>
                            <RotateTransform Angle="90" />
                        </Grid.LayoutTransform>                            
                    </Grid>
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>
        </ListBox>
    </Grid>
</Border>

4

12 に答える 12

31

バインディングの問題は、ListBoxItem のデフォルト スタイルに起因します。既定では、要素にスタイルを適用するときに、WPF は既定のスタイルを探し、カスタム スタイルで特に設定されていない各プロパティを既定のスタイルから適用します。この動作の詳細については、Ian Griffiths によるこの素晴らしいブログ投稿を参照してください。

私たちの問題に戻りましょう。ListBoxItem のデフォルト スタイルは次のとおりです。

<Style
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:s="clr-namespace:System;assembly=mscorlib"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    TargetType="{x:Type ListBoxItem}">
    <Style.Resources>
       <ResourceDictionary/>
    </Style.Resources>
    <Setter Property="Panel.Background">
       <Setter.Value>
          <SolidColorBrush>
        #00FFFFFF
          </SolidColorBrush>
       </Setter.Value>
    </Setter>
    <Setter Property="Control.HorizontalContentAlignment">
       <Setter.Value>
          <Binding Path="HorizontalContentAlignment" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=ItemsControl, AncestorLevel=1}"/>
       </Setter.Value>
    </Setter>
    <Setter Property="Control.VerticalContentAlignment">
       <Setter.Value>
          <Binding Path="VerticalContentAlignment" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=ItemsControl, AncestorLevel=1}"/>
       </Setter.Value>
    </Setter>
    <Setter Property="Control.Padding">
       <Setter.Value>
          <Thickness>
        2,0,0,0
          </Thickness>
       </Setter.Value>
    </Setter>
    <Setter Property="Control.Template">
       <Setter.Value>
          <ControlTemplate TargetType="{x:Type ListBoxItem}">
             ...
          </ControlTemplate>
       </Setter.Value>
    </Setter>
 </Style>

コンパクトにするために ControlTemplate を削除したことに注意してください (スタイルを取得するためにStyleSnooperを使用しました)。相対ソースが ItemsControl タイプの祖先に設定されたバインディングがあることがわかります。したがって、あなたの場合、バインディング時に作成された ListBoxItems は、ItemsControl を見つけられませんでした。ListBox の ItemsSource について詳しく教えてください。

PS: エラーを取り除く 1 つの方法は、カスタム スタイルで Horizo​​ntalContentAlignment と VerticalContentAlignment の新しいセッターを作成することです。

于 2008-10-06T22:10:40.527 に答える
23

に設定OverridesDefaultStyleすると、これらの問題も修正さTrueれます。ItemContainerStyle

<Style TargetType="ListBoxItem">
    <Setter Property="OverridesDefaultStyle" Value="True"/>
    <!-- set the rest of your setters, including Template, here -->
</Style>
于 2009-03-12T00:07:44.740 に答える
7

これは、およびその他の一時的なコンテナーでよくある問題です。それらは、ロード/レンダリング中に非同期/オンザフライで作成されます。のイベントにアタッチし、それらにアクセスしようとする前にステータスがなるのを待つ必要があります。ListBoxItem*ItemItemsControlListBox.ItemContainerGeneratorStatusChangedItemsGenerated

于 2008-10-20T13:23:05.033 に答える
4

私はあなたと同じ問題を抱えていたので、私の解決策を共有したかっただけです. この投稿のすべてのオプションを試しましたが、最後のオプションが私にとって最高でした-thx Chris。

だから私のコード:

<ListBox.Resources>
    <Style x:Key="listBoxItemStyle" TargetType="ListBoxItem">
        <Setter Property="HorizontalContentAlignment" Value="Center" />
        <Setter Property="VerticalContentAlignment" Value="Center" />
        <Setter Property="MinWidth" Value="24"/>
        <Setter Property="IsEnabled" Value="{Binding IsEnabled}"/>
    </Style>

    <Style TargetType="ListBoxItem" BasedOn="{StaticResource listBoxItemStyle}"/>
</ListBox.Resources>

<ListBox.ItemContainerStyle>
    <Binding Source="{StaticResource listBoxItemStyle}"/>
</ListBox.ItemContainerStyle>

<ListBox.ItemsPanel>
    <ItemsPanelTemplate>
        <WrapPanel Orientation="Horizontal" IsItemsHost="True" MaxWidth="170"/>
    </ItemsPanelTemplate>
</ListBox.ItemsPanel>

カスタムが存在しない場合、このバグは表示されないことも発見しましたItemsPanelTemplate

于 2014-07-26T11:23:01.110 に答える
3

これは私にとってはうまくいきました。これを Application.xaml ファイルに入れます。

<Application.Resources>
    <Style TargetType="ListBoxItem">
        <Setter Property="HorizontalContentAlignment" Value="Left" />
        <Setter Property="VerticalContentAlignment" Value="Center" />
    </Style>
</Application.Resources>

から...

http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/42cd1554-de7a

于 2012-02-15T00:01:13.093 に答える
2

同じタイプのエラーが発生しました:

System.Windows.Data エラー: 4 : 参照 'RelativeSource FindAncestor、AncestorType='System.Windows.Controls.ItemsControl'、AncestorLevel='1'' でバインディングのソースが見つかりません。BindingExpression:Path=Horizo​​ntalContentAlignment; DataItem=null; ターゲット要素は 'ListBoxItem' (Name='') です。ターゲット プロパティは 'Horizo​​ntalContentAlignment' (タイプ 'Horizo​​ntalAlignment') です

これは、次のようなバインディングを行っているときに発生しました。

<ListBox ItemsSource="{Binding Path=MyListProperty}"  />

私のデータ コンテキスト オブジェクトのこのプロパティに:

public IList<ListBoxItem> MyListProperty{ get; set;}

いくつかの実験の後、項目の数が ListBox の表示可能な高さを超えた場合 (垂直スクロールバーが表示された場合など) にのみエラーが発生することがわかりました。そこで私はすぐに仮想化について考え、これを試しました:

<ListBox ItemsSource="{Binding Path=MyListProperty}" VirtualizingStackPanel.IsVirtualizing="False" />

これで問題は解決しました。仮想化をオンにしておくことを望んでいましたが、それ以上の時間は使用しませんでした。私のアプリケーションは、複数のレベルのグリッド、ドック パネルなど、およびいくつかの非同期メソッド呼び出しを含む、少し複雑な面があります。単純なアプリケーションでは問題を再現できませんでした。

于 2011-08-16T13:08:26.577 に答える
1

選択範囲が表示されないようにテンプレートを完全に置き換えたい場合ListBoxItem(おそらくItemsControl、 のグループ化/etc 動作での外観が必要なListBox場合)、次のスタイルを使用できます。

<Style TargetType="ListBoxItem">
  <Setter Property="Margin" Value="2" />
  <Setter Property="FocusVisualStyle" Value="{x:Null}" />
  <Setter Property="OverridesDefaultStyle" Value="True" />
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type ListBoxItem}">
        <ContentPresenter Content="{TemplateBinding ContentControl.Content}" 
                          HorizontalAlignment="Stretch" 
                          VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}" 
                          SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

Borderこのテンプレートは、標準のラッパーも除外します。それが必要な場合は、テンプレートを次のように置き換えることができます。

<Border BorderThickness="{TemplateBinding Border.BorderThickness}" 
        Padding="{TemplateBinding Control.Padding}" 
        BorderBrush="{TemplateBinding Border.BorderBrush}" 
        Background="{TemplateBinding Panel.Background}" 
        SnapsToDevicePixels="True">
  <ContentPresenter Content="{TemplateBinding ContentControl.Content}" 
                    ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}" 
                    HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}" 
                    VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}" 
                    SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</Border>

TemplateBindingこれらの値がすべて必要ない場合は、パフォーマンスのために一部を削除できます。

于 2009-10-16T16:06:38.540 に答える
1

私にとってうまくいった別の回避策/解決策は、クラスまたはトップレベルウィンドウのコンストラクターでデータバインディングソーススイッチレベルをクリティカルとして設定することにより、これらのエラーを抑制することでした(実際には、警告と呼ぶ方が適切だと思われます)。

#if DEBUG     
    System.Diagnostics.PresentationTraceSources.DataBindingSource.Switch.Level =
        System.Diagnostics.SourceLevels.Critical;
#endif

参照: System.Windows.Data エラー警告メッセージを抑制する方法

于 2011-11-30T12:34:43.950 に答える
1

MSDNのデータ テンプレートの概要によると、 は、データの表示方法を定義するDataTemplatesとして使用する必要があります。ItemTemplateStyleItemContainerStyleListBoxItem

ただし、後者を使用して前者の仕事をしようとしているようです。コードを追加せずに状況を再現することはできませんが、コンテナー スタイルでデータ バインディングを行うと、想定されるビジュアル/論理ツリーにレンチが投げられる可能性があると思われます。

また、アイテムの情報に基づいてアイテムをカスタム レイアウトするには、カスタム を作成する必要があると思わざるを得ませんPanelPanelアイテムがルーブ・ゴールドバーグの品揃えで自分自身をレイアウトするよりも、カスタムがアイテムをレイアウトする方がおそらく良いでしょうIValueConverters.

于 2008-10-02T18:04:04.863 に答える
0

ListBox に Style と ItemContainerStyle の両方が設定されていて、これらの名前付きスタイルが既に Horizo​​ntalContentAlignment を定義していたにもかかわらず、この問題に遭遇し始めました。CheckBox コントロールを使用して ListBox のライブ フィルタリングをオン/オフしていましたが、これにより、割り当てられたスタイルではなくデフォルト スタイルから項目がプルされるように見えました。ほとんどのエラーは、ライブ フィルタリングが最初に開始されたときに発生しますが、その後は変更のたびに 2 つのエラーがスローされ続けます。コレクション内のちょうど 2 つのレコードが空で、アイテムに何も表示されていないのは興味深いことです。だからこれが貢献したようです。レコードが空のときに表示されるデフォルト データを作成する予定です。

カーターの提案は私にとってはうまくいきました。キーのない別の「デフォルト」スタイルと、Horizo​​ntalContentAlignment プロパティを定義した TargetType="ListBoxItem" を追加すると、問題が解決しました。OverridesDefaultStyle プロパティを設定する必要さえありませんでした。

于 2014-07-03T18:52:26.497 に答える
0

タイプ「ComboBoxItem」のデフォルト スタイルを作成するだけでは機能しません。これは、ComboBox のデフォルトの「ItemContainerStyle」によって上書きされるためです。これを本当に取り除くには、ComboBox のデフォルトの「ItemContainerStyle」を次のように変更する必要があります。

<Style TargetType="ComboBox">
    <Setter Property="ItemContainerStyle">
        <Setter.Value>                
            <Style TargetType="ComboBoxItem">
                <Setter Property="HorizontalContentAlignment" Value="Left" />
                <Setter Property="VerticalContentAlignment" Value="Center" />
            </Style>
        </Setter.Value>
    </Setter>
</Style>
于 2012-02-21T16:41:03.173 に答える