web-dev-qa-db-ja.com

WPFでチェックボックスのリストボックスを実装する方法

Winformsアプリケーションの作成には多少の経験はありますが、WPFの「あいまいさ」は、ベストプラクティスとデザインパターンの観点からはまだわかりません。

実行時にリストにデータを入力しているにもかかわらず、リストボックスに何も表示されません。

私は この役立つ記事 からの簡単な指示に従いましたが、役に立ちませんでした。基になるリストの変更が完了したことをリストボックスに通知するDataBind()メソッドの一部が欠けていると思います。

私のMainWindow.xamlには、次のものが含まれています。

    <ListBox ItemsSource="{Binding TopicList}" Height="177" HorizontalAlignment="Left" Margin="15,173,0,0" Name="listTopics" VerticalAlignment="Top" Width="236" Background="#0B000000">
        <ListBox.ItemTemplate>
            <HierarchicalDataTemplate>
                <CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked}"/>
            </HierarchicalDataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

私のコードビハインドでは、次のようにしています。

    private void InitializeTopicList( MyDataContext context )
    {
        List<Topic> topicList = ( from topic in context.Topics select topic ).ToList();

        foreach ( Topic topic in topicList )
        {
            CheckedListItem item = new CheckedListItem();
            item.Name = topic.DisplayName;
            item.ID = topic.ID;
            TopicList.Add( item );
        }
    }

トレースすると、4つのアイテムが表示されます。

編集

TopicListObservableCollectionに変更しました。それでも動作しません。

    public ObservableCollection<CheckedListItem> TopicList;

編集#2

役立つ2つの変更を加えました。

.xamlファイル:

ListBox ItemsSource="{Binding}"

リストに入力した後のソースコード:

listTopics.DataContext = TopicList;

リストを取得していますが、チェックボックスの状態を更新しても、チェックボックスの状態が自動的に更新されません。私の側でもう少し読むことでこれを解決すると思います。

21
Bob Kaufman

_ObservableCollection<Topic>_の代わりに_List<Topic>_を使用する

編集

iNotifyCollectionChangedインターフェイスを実装して、アイテムを追加/削除/変更したときにWPFに通知する

編集2

コードでTopicListを設定するため、これは共通フィールドではなく、依存関係プロパティである必要があります

_    public ObservableCollection<CheckedListItem> TopicList {
        get { return (ObservableCollection<CheckedListItem>)GetValue(TopicListProperty); }
        set { SetValue(TopicListProperty, value); }
    }
    public static readonly DependencyProperty TopicListProperty =
        DependencyProperty.Register("TopicList", typeof(ObservableCollection<CheckedListItem>), typeof(MainWindow), new UIPropertyMetadata(null));
_

編集

アイテムの変更を確認するには

  1. INotifyPropertyChangedCheckedListItemインターフェースを実装します(各セッターはPropertyChanged(this, new PropertyChangedEventArgs(<property name as string>))イベントを呼び出す必要があります)
  2. またはCheckedListItemからDependencyObjectを派生させ、NameIDIsCheckedを依存関係プロパティに変換する
  3. またはそれらを完全に更新します(topicList[0] = new CheckedListItem() { Name = ..., ID = ... }
5
Mykola Bogdiuk

TopicListObservableCollection<T>ではないと想定しているため、アイテムを追加しても、バインディングエンジンに値を更新するように通知するためにINotifyCollectionが変更されません。

現在の問題を解決するTopicListObservableCollection<T>に変更します。また、List<T>を事前に入力しておくと、OneWayを介してバインディングが機能します。ただし、ObservableCollection<T>はより堅牢なアプローチです。

編集:

TopicListは、メンバー変数ではなくプロパティである必要があります。バインディングにはプロパティが必要です。 notDependencyPropertyである必要があります。

編集2:

ItemTemplateである必要はないため、HierarchicalDataTemplateを変更してください

   <ListBox.ItemTemplate>
     <DataTemplate>
       <StackPanel>
         <CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked}"/>
       </StackPanel>
     </DataTemplate>
   </ListBox.ItemTemplate>
8
Aaron McIver

他のユーザーはすでに便利な提案をしています(監視可能なコレクションを使用してリスト変更通知を取得し、コレクションをフィールドではなくプロパティにします)。彼らが持っていない2つはここにあります:

1)データバインディングに問題がある場合は、出力ウィンドウを調べて、バインディングエラーが発生していないことを確認してください。これを行わないと、間違った問題を修正するために多くの時間を費やす可能性があります。

2)バインディングで果たす役割変更通知を理解します。データソースの変更は、データソースが変更通知を実装しない限り、UIに伝達できません。これを通常のプロパティに対して行う方法は2つあります。データソースをDependencyObjectから派生させ、バインドされたプロパティを依存関係プロパティにするか、またはデータソースにINotifyPropertyChangedを実装してPropertyChangedイベント。 ItemsControlをコレクションにバインドするときは、INotifyCollectionChangedを実装するコレクションクラス(ObservableCollection<T>など)を使用して、コレクションの内容と順序の変更がコレクションに反映されるようにします。バインドされたコントロール。 (アイテムへの変更が必要な場合inコレクションがバインドされたコントロールに伝達されるようにするには、それらのアイテムも変更通知を実装する必要があることに注意してください。)

3
Robert Rossney

まず、これにはHeirarchicalDataTemplateは必要ありません。 Aaronが指定した通常のDataTemplateで十分です。次に、クラスのコンストラクター内のどこかにTopicList ObservableCollectionをインスタンス化する必要があります。これにより、データを追加する前でもObservableCollectionが有効になり、バインディングシステムはコレクションを認識します。次に、すべてのTopic/CheckedListItemを追加すると、UIに自動的に表示されます。

TopicList = new ObservableCollection<CheckedListItem>(); //This should happen only once

private void InitializeTopicList( MyDataContext context )
{
    TopicList.Clear();

    foreach ( Topic topic in topicList )
    {
        CheckedListItem item = new CheckedListItem();
        item.Name = topic.DisplayName;
        item.ID = topic.ID;
        TopicList.Add( item );
    }
}
3
Jobi Joy

バインディングをに変更

 <ListBox ItemsSource="{Binding Path=TopicList}"
0
Binil