10

1 日か 2 日、奇妙な WPF バグを見つけようとしてきました。これは、INotifyProperty と IEquatable の両方を実装するクラスであり、Id (文字列) と呼ばれるフィールドが 1 つだけあります。PolicyId は、プログラムの他の部分でワークフローを変更するさまざまなポリシー項目へのポインターです。

ListBox はコレクションにバインドされており、Id を ListBox に追加および削除するだけの追加および削除ボタンがあります。ListBox 内の selectedItem の PolicyId を別の Id に変更するために使用できるドロップダウン ComboBox もあります (選択に使用できる Id は別の場所で変更されます)。ListBox.SelectedItem.Id プロパティの値の設定は、ComboBox.SelectionChanged イベントがトリガーされたときにバックエンドで行われ、ListBox.SelectionChanged イベントがトリガーされたときに ComboBox の値が変更されます。 ListBox は常に同一です。

現在、この実装はほとんどの場合機能しています。すべてのポリシーが ListBox に一覧表示され、新しいポリシーを追加したり (以前に選択されていない最初の使用可能なポリシーがリストの下部に追加されます)、必要なポリシーを選択して削除したりできます。

ただし、comboBox を使用して 1 つのポリシーを別のポリシーに置き換えていない限りは、そうです。これを行うと、インデックスは変更したものに固執し、別のポリシーを選択するためにできることはありません (ListBox.SelectedIndex を設定しても効果はありません)。しばらくクリックすると、最終的に次の例外がスローされます:「System.ArgumentException: 同じキーを持つ項目が既に追加されています。」アイテムが既に存在する場合でも、WPFが選択したアイテムをlistBoxの「selectedItems」コレクションに追加しようとしているためにエラーが発生したと思われます。

このバグは、PolicyId が Equals をオーバーライドすることと関係があることを知っています (はい、Equals が 2 つのオブジェクトが互いに等しいと言う場合、GetHashCode も 2 つのオブジェクトに対して同じ値を返す必要があるという制約を思い出しました。そのため、GetHashCode もオーバーライドされます)。同様の設定がプログラムの他の場所で問題なく使用されているためです。特にコレクションに重複がないため、それがどのように混乱するかはわかりません。

これはリストボックスです:

<ListBox Name="policyIdList" MinHeight="50" ItemsSource="{Binding Path=DataItem}" IsSynchronizedWithCurrentItem="True" SelectionChanged="policyIdList_SelectionChanged">
    <ListBox.Resources>
        <Style TargetType="ScrollViewer">
            <Setter Property="HorizontalScrollBarVisibility" Value="Hidden" />
        </Style>
    </ListBox.Resources>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock DataContext="{Binding Path=Id}" Text="{Binding Converter={StaticResource PolicyIdToName}}">
                <TextBlock.ToolTip>
                    <ContentControl Content="{Binding}" ContentTemplate="{StaticResource PolicyByOidListItem}" />
                </TextBlock.ToolTip>
            </TextBlock>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

そして、適切な手段として、コンボボックス:

<ComboBox Name="policyIdCombo" Grid.Row="1" Grid.Column="0"
ItemTemplate="{StaticResource PolicyByOidListItem}" SelectionChanged="policyIdCombo_SelectionChanged" />
4

1 に答える 1