fc2ブログ

CollectionViewSourceをバインディングする際の注意点

 ソースのコレクション(ObservableCollection等)を変更することなく並べ替えやフィルター等を行えるとても便利なCollectionViewSourceですが、コレクションのデータバインディングとは異なる点があります。
 以下のサンプルコードはコレクションをバインディングした場合、CollectionViewをバインディングした場合を比較するものです。
using Livet;
using System.Collections.ObjectModel;
using System.Windows.Data;

namespace CollectionViewSourceDemo4.ViewModels
{
    public class MainWindowViewModel : ViewModel
    {
        public MainWindowViewModel()
        {
            Items = new ObservableCollection<string>()
            {
                "A", "B", "C", "D", "E"
            };

            ItemsViewSource = new CollectionViewSource()
            {
                Source = Items
            };
        }

        public ObservableCollection<string> Items { get; private set; }

        public CollectionViewSource ItemsViewSource { get; private set; }   
    }
}
<Window x:Class="CollectionViewSourceDemo4.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
        xmlns:l="http://schemas.livet-mvvm.net/2011/wpf"
        xmlns:v="clr-namespace:CollectionViewSourceDemo4.Views"
        xmlns:vm="clr-namespace:CollectionViewSourceDemo4.ViewModels"
        Title="MainWindow" Height="350" Width="525">
    
    <Window.DataContext>
        <vm:MainWindowViewModel/>
    </Window.DataContext>
    
    <Window.Resources>
        <CollectionViewSource x:Key="source1" Source="{Binding Items}"/>
        <CollectionViewSource x:Key="source2" Source="{Binding Items}"/>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <GroupBox Grid.Row="0" Header="Itemsをバインディング">
            <StackPanel>
                <ComboBox ItemsSource="{Binding Items}"/>
                <ComboBox ItemsSource="{Binding Items}"/>
            </StackPanel>
        </GroupBox>
        <GroupBox Grid.Row="1" Header="ItemsViewSourceをバインディング">
            <StackPanel>
                <ComboBox ItemsSource="{Binding ItemsViewSource.View}"/>
                <ComboBox ItemsSource="{Binding ItemsViewSource.View}"/>
            </StackPanel>
        </GroupBox>
        <GroupBox Grid.Row="2" Header="source1/2をバインディング">
            <StackPanel>
                <ComboBox ItemsSource="{Binding Source={StaticResource source1}}"/>
                <ComboBox ItemsSource="{Binding Source={StaticResource source2}}"/>
            </StackPanel>
        </GroupBox>
    </Grid>
</Window>
CollectionViewSource4.png
 このコードを実行し、コンボボックスを操作すると「Itemsをバインディング」と「source1/2をバインディング」のコンボボックスはそれぞれ違う値を選択できますが、「ItemsViewSourceをバインディング」した場合は片方を動かすともう片方のコンボボックスも連動して動きます。
 コレクションをデータバインディングする場合、そのコレクションが直接バインディングされるのではなく内部でCollectionViewが作成されます。実際にデータバインディングされているのは内部で作成されたCollectionViewになります。
 そのため複数のItemsControl(ListBoxやComboBox等)に同じコレクションを指定しても、内部的には異なるCollectionViewなので別物として扱われます。
 CollectionViewSourceを利用する場合は指定したCollectionViewが直接バインディングされます。
 そのため複数のItemsControlに同じCollectionViewを指定した場合、片方のItemsControlを操作するともう片方のItemsControlも連動して動きます。(当たり前ですが)
 連動させたくない場合は必要な分だけCollectionViewを作成する必要があります。(サンプルコードのsource1, 2の様に)
 CollectionViewSourceはViewModel、XAMLどちらで作成してもかまいませんが、単純な並べ替えを行う程度ならばXAMLで定義した方が簡単です。
スポンサーサイト



カレンダー
10 | 2015/11 | 12
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 - - - - -
全記事表示リンク

全ての記事を表示する

カテゴリ
タグリスト

月別アーカイブ
04  10  11  09  08  07  06  05  04  03  02  01  12  11  10  09  08  07  06  04  03  02  01  12  11  10  09  08  07  06  05  04  03  02  01  12  11  10  09 
最新記事
リンク
最新コメント
検索フォーム
Amazon