web-dev-qa-db-ja.com

ObservableCollectionをWPFリストボックスにバインド

以下のコードビハインドがあります:

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        ObservableCollection<int> sampleData = new ObservableCollection<int>();
        public ObservableCollection<int> SampleData
        {
            get
            {
                if (sampleData.Count <= 0)
                {
                    sampleData.Add(1);
                    sampleData.Add(2);
                    sampleData.Add(3);
                    sampleData.Add(4);
                }
                return sampleData;
            }
        }
    }

私のxamlは:

<Window x:Class="Sandbox.MainWindow"
        xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <ListBox ItemsSource="{Binding Path=SampleData}"/>
    </Grid>
</Window>

リストには、コレクション内の値(または何でも)は表示されません。誰かが私の間違いを指摘できますか?

DataContextを明示的に設定する必要がありますか?何も設定されていない場合、コントロールはそれ自体をDataContextとして使用するだけだと思いました。

15
Flack

はい、DataContextを何らかの方法で設定する必要があります。設定されていない限り、ウィンドウにはDataContextがないため、DataContextはありません。コンストラクターでこれを行うと、ListBoxはDataContextを取得します。

public MainWindow() 
{ 
    InitializeComponent(); 
    this.DataContext = this;
} 

それ以外の場合は、バインディングでRelativeSource、ElementNameなどを使用できますが、=)は知っていると思います。

20
Fredrik Hedblad

私は通常、ビューモデルをコンストラクターに渡し、渡されたビューモデルにデータコンテキストを設定します。その後、ObservableCollectionをビューの外に移動して、ビューモデルに配置できます。これにより、ビューとロジックが分離され、viewmodelコードの単体テストも可能になります。

public MainWindow(SomeViewModel viewModel) 
{ 
    DataContext = viewModel;

    InitializeComponent(); 
} 
4
ihatemash

MvvMパターンを使用して、ビューで次のようにListBoxを定義できるようにします。

<ListBox ItemsSource="{Binding Path=Log, UpdateSourceTrigger=PropertyChanged}"/>

その場合、ビューにはバインディングソースに関連するコードビハインドがなくてもかまいません。関連するViewModelに次のようなものを追加します。

public class ViewModel : ViewModelBase
{
    //...
    private ObservableCollection<string> p_Log;

    /// <summary>
    /// A log of a starting process
    /// </summary>
    public ObservableCollection<string> Log
    {
        get { return p_Log; }

        set
        {
            base.RaisePropertyChangingEvent("Log");
            p_Log.Add(value.ToString());
            base.RaisePropertyChangedEvent("Log");
        }
    }
    //....
    /// <summary>
    /// Initializes this view model.
    /// </summary>
    /// <param name="mainWindowViewModel">The view model for this application's main window.</param>
    private void Initialize(MainWindowViewModel mainWindowViewModel)
    {  
        //...
        p_Log = new ObservableCollection<string>();
    }

そして、ViewModelBaseで定義されたイベントは、新しい文字列が監視可能なコレクションp_logに追加されるたびにビューの背後にコードを置く必要なしに、ビューのバインディングを更新し続けます。

2
jortizromo