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つのアイテムが表示されます。
編集
TopicList
をObservableCollection
に変更しました。それでも動作しません。
public ObservableCollection<CheckedListItem> TopicList;
編集#2
役立つ2つの変更を加えました。
.xamlファイル:
ListBox ItemsSource="{Binding}"
リストに入力した後のソースコード:
listTopics.DataContext = TopicList;
リストを取得していますが、チェックボックスの状態を更新しても、チェックボックスの状態が自動的に更新されません。私の側でもう少し読むことでこれを解決すると思います。
_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));
_
編集
アイテムの変更を確認するには
INotifyPropertyChanged
にCheckedListItem
インターフェースを実装します(各セッターはPropertyChanged(this, new PropertyChangedEventArgs(<property name as string>))
イベントを呼び出す必要があります)CheckedListItem
からDependencyObject
を派生させ、Name
、ID
、IsChecked
を依存関係プロパティに変換するtopicList[0] = new CheckedListItem() { Name = ..., ID = ... }
)TopicList
はObservableCollection<T>
ではないと想定しているため、アイテムを追加しても、バインディングエンジンに値を更新するように通知するためにINotifyCollection
が変更されません。
現在の問題を解決するTopicList
をObservableCollection<T>
に変更します。また、List<T>
を事前に入力しておくと、OneWayを介してバインディングが機能します。ただし、ObservableCollection<T>
はより堅牢なアプローチです。
編集:
TopicList
は、メンバー変数ではなくプロパティである必要があります。バインディングにはプロパティが必要です。 notはDependencyProperty
である必要があります。
編集2:
ItemTemplate
である必要はないため、HierarchicalDataTemplate
を変更してください
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
他のユーザーはすでに便利な提案をしています(監視可能なコレクションを使用してリスト変更通知を取得し、コレクションをフィールドではなくプロパティにします)。彼らが持っていない2つはここにあります:
1)データバインディングに問題がある場合は、出力ウィンドウを調べて、バインディングエラーが発生していないことを確認してください。これを行わないと、間違った問題を修正するために多くの時間を費やす可能性があります。
2)バインディングで果たす役割変更通知を理解します。データソースの変更は、データソースが変更通知を実装しない限り、UIに伝達できません。これを通常のプロパティに対して行う方法は2つあります。データソースをDependencyObject
から派生させ、バインドされたプロパティを依存関係プロパティにするか、またはデータソースにINotifyPropertyChanged
を実装してPropertyChanged
イベント。 ItemsControl
をコレクションにバインドするときは、INotifyCollectionChanged
を実装するコレクションクラス(ObservableCollection<T>
など)を使用して、コレクションの内容と順序の変更がコレクションに反映されるようにします。バインドされたコントロール。 (アイテムへの変更が必要な場合inコレクションがバインドされたコントロールに伝達されるようにするには、それらのアイテムも変更通知を実装する必要があることに注意してください。)
まず、これには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 );
}
}
バインディングをに変更
<ListBox ItemsSource="{Binding Path=TopicList}"