2011-03-01 14 views
5

CollectionViewSourceを使用してコンボボックスソートを実装しようとしています。このコンボボックスは実際にはデータテンプレートの一部であり、リストビューで繰り返されます。私の最初のアプローチは、(CollectionViewSourceを使用して)動作するようでしたが、私のすべてのコンボボックスは同じデータコンテキストを共有していました。これは、他のボックスのいずれかが変更されたときはいつでも反映されるように変更されました。CollectionViewSourceを使用したバインド

私は、静的リソースとしてcvsを作成するのではなく、CollectionViewSourceを指定するためにインラインxamlを使用して基本コンボボックス(データテンプレート内ではありません)を実装しようとしました。データを正常に表示することができませんでした。私はおそらくWPFをまだ慣れていないので、これはまったく間違っていると思います。ここで

は私のコンボボックスのXAMLです:

<ComboBox> 
    <ComboBox.ItemsSource> 
     <Binding> 
      <Binding.Source> 
       <CollectionViewSource Source="{Binding Path=Configurations}"> 
        <CollectionViewSource.SortDescriptions> 
         <scm:SortDescription PropertyName="AgencyName" /> 
        </CollectionViewSource.SortDescriptions> 
       </CollectionViewSource> 
      </Binding.Source> 
     </Binding> 
    </ComboBox.ItemsSource> 
</ComboBox> 

このコンボボックスが住んでいるユーザーコントロールのDataContextのは、コンフィギュレーションと呼ばれるのObservableCollectionを持っており、各設定はAgencyNameと呼ばれるプロパティを持つオブジェクトにバインドされています。私はcvsのない標準バインディングを使ってうまく動作することを確認しました。

私の上司に言い訳が不足しているので、どんな助力があれば幸いです。私はまた、コードにドロップダウンし、コードの背後にあるソートを行う必要はありません(ObservableCollectionを構築するときには可能ですが、DRYの原則に違反するIMHO)。

答えて

3

どういう意味ですか反映する "?あなたはSelectedItemについて話していますか? その場合は、ComboBoxにIsSynchronizedWithCurrentItem = falseを設定してください。

それ以外にも、ICollectionViewをコード内に1回だけ作成して並べ替えるのであれば、DRYの原則に違反することはありません。しかし、Model-View-ViewModelの観点から言えば、Viewで並べ替えのような機能を実行する必要があると言える他の理由があるかもしれません。

+0

ああ、IsSynchronizedWithCurrentItemは魅力的に機能します。これはリストと同期せず、ModelViewのプロパティへのバインドを妨げません。私はちょうどそれを確認し終わった。それは優雅さで私の問題を解決します。私はもっ​​と頼むことができない、ありがとう。 – SRM

+0

あなたは、私はWPFの制限に遭遇したと思っていました。この制限では、各テンプレートのスポーンに対してviewswource全体のコピーを使用する必要がありました。 Googleでさえ問題を説明するのは難しいでしょう。 –

+0

PS。これはデフォルトのWPFの動作であるか、少なくともTemplatesへのデフォルトですが、まあまあです。 –

1

あなたの投稿全体を読むことはできませんでしたが、リソースはデフォルトで共有されるという問題があります。したがって、各コンボボックスは同じコレクションビューを参照していました。コレクションビューにはトラッキング選択が含まれているため、1つのコンボボックスで選択を変更すると他のコンボボックスに影響します。

よりもむしろローカルリソースにCVSを移動し、あなただけの共有されているからそれを防ぐことができます:あなたは、他のボックスのいずれかが他のすべてに変更変更された時はいつでも」によって正確に

<CollectionViewSource x:Key="whatever" x:Shared="False" .../> 
+0

これは有望そうです。私はそのショットを与える(私のCVは共有されている面以外では完全に動作していたので)。ありがとう! – SRM

+0

それは有望そうに見えましたが、うまくいかなかったようです。私はx:Shared属性(何らかの理由でintelisenseで表示されなかった)を追加し、コンボボックスはコンテンツのレンダリングを停止しました。フラグをTrueに変更するとすべて正常に動作します。 – SRM

0

おそらく遅すぎますが、私はこの問題に遭遇する可能性がある他の人にこの回答を残しています。 CollectionViewSource.Source.Source.Source.Source.Source.Source.Source.Source.Source.Source.Source.Source.Source.Source.Source.Source.Source.Sourceのバインドは、ビジュアル/論理ツリーに属しておらず、データコンテキストを継承せず、バインディングのソースとしてComboBoxを参照することもできません。私は醜いでこの問題を解決することができたが、次のクラス使用して簡単な方法:ここ

/// <summary> 
/// Provides a way to set binding between a control 
/// and an object which is not part of the visual tree. 
/// </summary> 
/// <remarks> 
/// A bright example when you need this class is having an 
/// <see cref="ItemsControl"/> bound to a <see cref="CollectionViewSource"/>. 
/// The tricky thing arises when you want the <see cref="CollectionViewSource.Source"/> 
/// to be bound to some property of the <see cref="ItemsControl"/> 
/// (e.g. to its data context, and to the view model). Since 
/// <see cref="CollectionViewSource"/> doesn't belong to the visual/logical tree, 
/// its not able to reference the <see cref="ItemsControl"/>. To stay in markup, 
/// you do the following: 
/// 1) Add an instance of the <see cref="BindingBridge"/> to the resources 
/// of some parent element; 
/// 2) On the <see cref="ItemsControl"/> set the <see cref="BindingBridge.BridgeInstance"/> attached property to the 
/// instance created on step 1) using <see cref="StaticResourceExtension"/>; 
/// 3) Set the <see cref="CollectionViewSource.Source"/> to a binding which has 
/// source set (via <see cref="StaticResourceExtension"/>) to <see cref="BindingBridge"/> 
/// and path set to the <see cref="BindingBridge.SourceElement"/> (which will be the control 
/// on which you set the attached property on step 2) plus the property of interest 
/// (e.g. <see cref="FrameworkElement.DataContext"/>): 
/// <code> 
/// <CollectionViewSource 
///  Source="{Binding SourceElement.DataContext.Images, Source={StaticResource ImagesBindingBridge}}"/> 
/// </code>. 
/// 
/// So the result is that when assigning the attached property on a control, the assigned 
/// <see cref="BindingBridge"/> stores the reference to the control. And that reference can be 
/// retrieved from the <see cref="BindingBridge.SourceElement"/>. 
/// </remarks> 
public sealed class BindingBridge : DependencyObject 
{ 
    #region BridgeInstance property 

    public static BindingBridge GetBridgeInstance(DependencyObject obj) 
    { 
     Contract.Requires(obj != null); 
     return (BindingBridge)obj.GetValue(BridgeInstanceProperty); 
    } 

    public static void SetBridgeInstance(DependencyObject obj, BindingBridge value) 
    { 
     Contract.Requires(obj != null); 
     obj.SetValue(BridgeInstanceProperty, value); 
    } 

    // Using a DependencyProperty as the backing store for BridgeInstance. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty BridgeInstanceProperty = 
     DependencyProperty.RegisterAttached("BridgeInstance", typeof(BindingBridge), typeof(BindingBridge), 
     new PropertyMetadata(OnBridgeInstancePropertyChanged)); 

    #endregion BridgeInstance property 

    #region SourceElement property 

    public FrameworkElement SourceElement 
    { 
     get { return (FrameworkElement)GetValue(SourceElementProperty); } 
     private set { SetValue(SourceElementPropertyKey, value); } 
    } 

    // Using a DependencyProperty as the backing store for SourceElement. This enables animation, styling, binding, etc... 
    private static readonly DependencyPropertyKey SourceElementPropertyKey = 
     DependencyProperty.RegisterReadOnly("SourceElement", typeof(FrameworkElement), typeof(BindingBridge), new PropertyMetadata(null)); 

    public static readonly DependencyProperty SourceElementProperty; 

    #endregion SourceElement property 

    /// <summary> 
    /// Initializes the <see cref="BindingBridge"/> class. 
    /// </summary> 
    static BindingBridge() 
    { 
     SourceElementProperty = SourceElementPropertyKey.DependencyProperty; 
    } 

    private static void OnBridgeInstancePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var sourceElement = (FrameworkElement)d; 
     var bridge = (BindingBridge)e.NewValue; 
     bridge.SourceElement = sourceElement; 
    } 
} 

は、(リソース辞書が図示されていない)の使用例である:

DEPENDS結合
<ItemsControl 
     infrastructure:BindingBridge.BridgeInstance="{StaticResource ImagesBindingBridge}"> 
     <ItemsControl.ItemsSource> 
      <Binding> 
       <Binding.Source> 
        <CollectionViewSource 
           Source="{Binding SourceElement.DataContext.Images, Source={StaticResource ImagesBindingBridge}, Mode=OneWay}"> 
         <CollectionViewSource.SortDescriptions> 
          <componentModel:SortDescription PropertyName="Timestamp" Direction="Descending"/> 
         </CollectionViewSource.SortDescriptions> 
        </CollectionViewSource> 
       </Binding.Source> 
      </Binding> 
     </ItemsControl.ItemsSource> 
    </ItemsControl> 
0

Cvsはビジュアルツリーではないので、バインディングは機能しません。

代わりにx:Referenceを使用できます。

<Border x:Name="border" /> 
<ComboBox> 
    <ComboBox.ItemsSource> 
     <Binding> 
      <Binding.Source> 
       <CollectionViewSource Source="{Binding Path=DataContext.Configurations, Source={x:Reference border}}"> 
        <CollectionViewSource.SortDescriptions> 
         <scm:SortDescription PropertyName="AgencyName" /> 
        </CollectionViewSource.SortDescriptions> 
       </CollectionViewSource> 
      </Binding.Source> 
     </Binding> 
    </ComboBox.ItemsSource> 
</ComboBox> 
関連する問題