我正在尝试使用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原则的恕我直言)。
答案 0 :(得分:3)
你究竟是什么意思“当其他一个盒子被改变时,所有其他盒子都改变了以反映”?你在谈论SelectedItem吗?
如果是这样,那么它可能有助于在您的ComboBox中设置IsSynchronizedWithCurrentItem = false
。
除此之外:我认为只要你在后面的代码中创建和排序你的ICollectionView一次,就不会违反DRY原则,因为你在XAML中不需要做更多的事情。但是我看到可能有其他理由说应该在视图中完成像排序这样的功能,用模型视图 - 视图模型来说。
答案 1 :(得分:1)
没有阅读您的整个帖子,但问题是默认情况下共享资源。因此,每个组合框都引用相同的集合视图。集合视图包括跟踪选择,因此在一个组合框中更改选择将影响其他组合。
不是将CVS移动到本地资源,而是可以阻止它被共享:
<CollectionViewSource x:Key="whatever" x:Shared="False" .../>
答案 2 :(得分: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>
答案 3 :(得分:-1)
绑定取决于VisualTree,cvs不是可视化的,因此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>