6

CollectionViewSourceを使用してコンボボックスの並べ替えを実装しようとしています。このコンボボックスは実際にはデータテンプレートの一部であり、リストビューで繰り返されます。私の最初のアプローチは(CollectionViewSourceを使用して)機能しているように見えましたが、すべてのコンボボックスが同じデータコンテキストを共有していました。これにより、他のボックスの1つが変更されるたびに、他のすべてのボックスが反映されるように変更されました。これは、望ましい副作用ではありません。

(静的リソースとして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は、ConfigurationsというObservableCollectionを持つオブジェクトにバインドされ、各構成にはAgencyNameというプロパティがあります。私はこれがcvsなしの標準バインディングを使用して正常に機能することを確認したので、その一致ですべてが正常であることがわかります。

上司への言い訳が足りなくなったので、どんな助けでも大歓迎です:)。また、コードにドロップダウンして、コードビハインドで並べ替えを行う必要はありません(これは、ObservableCollectionをビルドするときに可能でしたが、DRYの原則に違反するIMHOです)。

4

4 に答える 4

4

「他のボックスの1つが変更されたときはいつでも、他のすべてのボックスが反映するように変更された」とは、正確にはどういう意味ですか?SelectedItemについて話しているのですか?もしそうなら、それIsSynchronizedWithCurrentItem = falseはあなたのコンボボックスでの設定に役立つかもしれません。

それに加えて、コードビハインドでICollectionViewを1回だけ作成して並べ替える限り、DRYの原則に違反することはないと思います。これは、XAMLではそれ以上のことを行う必要がなくなったためです。しかし、Model-View-ViewModelの観点から言えば、並べ替えなどの機能をビューで実行する必要があると言う理由は他にもあると思います。

于 2011-03-01T22:21:55.657 に答える
1

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

CVSをローカルリソースに移動するのではなく、共有されないようにすることができます。

<CollectionViewSource x:Key="whatever" x:Shared="False" .../>
于 2011-03-01T20:36:22.910 に答える
0

おそらく手遅れですが、この問題に遭遇する可能性のある他の人にこの答えを残しておきます。CollectionViewSourceはビジュアル/論理ツリーに属していないため、CollectionViewSource.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;
    }
}

使用例を次に示します(リソース辞書は表示されていません)。

 <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>
于 2014-08-14T06:33:50.427 に答える
-1

バインディングは、cvsがビジュアルではないVisualTreeに依存しているため、バインディングは機能しません。

代わりに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>
于 2017-07-07T06:05:14.730 に答える