6

我正在尝试使用 CollectionViewSource 实现一些组合框排序。此组合框实际上是数据模板的一部分,并在列表视图中重复出现。我的第一种方法似乎有效(使用 CollectionViewSource),但我所有的组合框都共享相同的数据上下文。这使得每当更改其他框之一时,所有其他框都更改以反映 - 这不是所需的副作用。

我决定退后一步,尝试使用内联 xaml 来实现一个基本的组合框(不在数据模板内),以指定 CollectionViewSource(而不是将 cvs 创建为静态资源)。我无法成功显示我的数据。我可能完全错了,因为我还是 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 原则)。

4

4 回答 4

4

“每当其他框之一被更改时,所有其他框都被更改以反映”到底是什么意思?您是在谈论 SelectedItem 吗?如果是这样,那么它可能有助于IsSynchronizedWithCurrentItem = false在您的 ComboBox 中进行设置。

除此之外:我认为只要您只在后面的代码中创建和排序 ICollectionView 一次,就不会违反 DRY 原则,因为在 XAML 中不再需要您做更多的事情。但我看到可能还有其他理由说应该在视图中完成排序等功能,就模型-视图-视图模型而言。

于 2011-03-01T22:21:55.657 回答
1

没有阅读您的整个帖子,但问题是默认情况下资源是共享的。因此,每个组合框都引用相同的集合视图。集合视图包括跟踪选择,因此在一个组合框中更改选择会影响其他组合框。

与其将 CVS 移动到本地资源,不如阻止它被共享:

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

虽然可能为时已晚,但我将此答案留给可能遇到此问题的其他人。您对 CollectionViewSource.Source 的绑定不起作用,因为 CollectionViewSource 不属于可视/逻辑树,并且它既不继承数据上下文也不能够将 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,因此 Binding 不起作用。

您可以改用 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 回答