2012-06-15 1 views
8

XAMLのObservableCollectionにバインドし、そこにグループ化したいと考えました。原則として、これはうまくいきました。 XAMLで定義されているCollectionViewを取得するには

<UserControl.Resources> 
    <CollectionViewSource x:Key="cvs" Source="{Binding Path=TestTemplates}"> 
     <CollectionViewSource.SortDescriptions> 
      <scm:SortDescription PropertyName="Title"/> 
     </CollectionViewSource.SortDescriptions> 
     <CollectionViewSource.GroupDescriptions> 
      <PropertyGroupDescription PropertyName="TestCategory"/> 
     </CollectionViewSource.GroupDescriptions> 
    </CollectionViewSource> 
</UserControl.Resources> 

は、その後、データバインディング式は ItemsSource="{Binding Source={StaticResource ResourceKey=cvs}}"の代わり ItemsSource="{Binding Path=TestTemplates}"となりました。

ビューモデルからUIをリフレッシュするまで、最初はすべてがクールだと思われました。問題は、CollectionViewSource.GetDefaultView(TestTemplates)が、グループ化が適用されたXAMLのビューとは異なるビューを返したことです。したがって、私は選択をすることができなかったし、それに役立つものは何もしなかった。

リストを直接ビューモデルのプロパティにバインドし、コードビハインドでグループを設定することで修正できます。しかし、私はこの解決策に満足していません。

private void UserControlLoaded(object sender, RoutedEventArgs e) 
{ 
    IEnumerable source = TemplateList.ItemsSource; 
    var cvs = (CollectionView)CollectionViewSource.GetDefaultView(source); 
    if (cvs != null) 
    { 
     cvs.SortDescriptions.Add(new SortDescription("Title", ListSortDirection.Ascending)); 
     cvs.GroupDescriptions.Add(new PropertyGroupDescription("TestCategory")); 
    } 
} 

私はその理由がすでにgiven by John Skeet hereであると仮定します。

しかし、私は正しい見方をする方法があるはずです。私が間違っている?

+0

あなたは間違った方向に向かっています。 VMはビューの知識がないはずです。ビューを更新する場合は、バインドするプロパティがObservableCollectionであることを確認するか、コレクションを変更するときにNotifyPropertyChangedを明示的に呼び出します。 –

+0

@PanagiotisKanavos:リストビュー内のものは実際にはObservableCollection内に*あり、UI内の項目はプロパティの変更時に更新されます。しかし、グループ分けはそれを尊重しない。回避策としては、強制的に更新を行うこと、つまり 'CollectionViewSource.GetDefaultView(...).Refresh'があります。 – primfaktor

+0

.NET 4.5では、これは[ICollectionViewLiveShaping](http://msdn.microsoft.com/en-us/library/system.componentmodel.icollectionviewliveshaping(v = vs.110).aspx)で修正されます。 – primfaktor

答えて

1

答えはJ. Lennon'sに基づいています。自分のコマンドでリソースにアクセスできるものを渡すと、そこでCollectionViewSourceを参照することができます。 XAMLで

(上記のようにCollectionViewResource):

<Button Command="{Binding Command}" CommandParameter="{Binding RelativeSource={RelativeSource Self}}">Do it!</Button> 

およびVMコードで:

private void Execute(object parm) 
{ 
    var fe = (FrameworkElement)parm; 
    var cvs = (CollectionViewSource)fe.FindResource("cvs"); 
    cvs.View.Refresh(); 
} 

ExecuteRelayCommandに与えられるものです。

これは質問に答えるだろうが、私はそれが大好きです。意見ですか?

+0

これは[J.のベースよりも完全で(動作しているので)レノン](http://stackoverflow.com/users/1128106/j-lennon)、私はこれをマーク(しかし、彼は賞金を得た)。 – primfaktor

5

私はVMからのコレクションビューを公開するのではなくビューがそれを定義持っている傾向がある:

public ICollection<Employee> Employees 
{ 
    get { ... } 
} 

public ICollectionView EmployeesView 
{ 
    get { ... } 
} 

方法あなたのVMがビューにさらされているものを完全に制御を持っていること。たとえば、ユーザーの操作に応じてソート順を変更することができます。

+0

これは良い方法ですが、質問には答えません。私はまだ知りたいと思う。 – primfaktor

+0

「ビューをリフレッシュする」とは何を意味し、なぜそれをやりたいのですか?あなたのVMによって公開されている基底のコレクションが 'ObservableCollection 'などで 'INotifyCollectionChanged'を実装している場合、ビューによって作成されたコレクションビューは最新の状態に保たれるので、ビューを更新する手間が省けます。 –

+1

私は上記の資格を持つ必要があります。アイテムを追加/削除している限り、コレクションビューはソートされたままになります。ソートしている基本プロパティを変更している場合は、それが「リフレッシュ」する必要がある理由の1つです。実際にビューでVMではなくCVを作成したい場合は、ビューをリフレッシュする必要があるときはいつでもVMでイベントを発生させる必要があります。 IMHO、それはビジネス・ロジックなので、VMはそれをすべて処理しているだけです。 –

5

あなたはそれだけではできませんでしたか?

var _viewSource = this.FindResource("cvs") as CollectionViewSource; 

データが接続されている場合は、更新されたビューがあると想定します。

+0

これはまた、同僚によって育てられました。問題は、VMでは、 'FrameworkElement'(別々のアセンブリ、Vs参照VMのみ)の' FindResource'に到達しないということです。 – primfaktor

+0

あなたの答えが最も近づくにつれて、あなたは恩恵を受けなければなりません。それを賢く過ごす。 ;-) – primfaktor

関連する問題