关于在combobox上更新的itemSource的Xaml Set SelecteIndex

时间:2014-09-04 07:14:31

标签: wpf xaml combobox itemssource selectedindex

我希望每次更改组合框的itemssource时,都会设置SelectedIndex。

到目前为止,我有这个:

    <Style TargetType="ComboBox">
        <Setter Property="SelectedIndex"
                Value="0"></Setter>
    </Style>

它设置selectedIndex,但仅在第一次设置itemSource时设置。当整个itemSource被更改时,它将被加载到组合框中但不再被选中。此时它应该选择第一个项目。 每个ItemSource都有一个绑定,我不想用后面的代码设置SelectedIndex。 我想要一个xaml的解决方案,可能是一个触发器。

2 个答案:

答案 0 :(得分:1)

我不同意Sheridan - 开发人员当然可以设置SelectedIndex属性。但是,仅在XAML中无法实现目标,即使用样式,控件模板和触发器。这是因为依赖属性具有一定的值优先权,例如本地设置值(通过绑定或控件本身)具有比来自WPF样式的值更高的优先级(这就是您的Setter仅工作一次的原因)。您可以在http://msdn.microsoft.com/en-us/library/ms743230(v=vs.110).aspx

了解有关详情

然而,除了从视图模型控制所选索引的可能性之外(如Sheridan所提出的),还有可能创建例如:附加的依赖项属性,在组合框中设置,并在组合框的ItemsSource属性中查找更改。你的XAML看起来会像这样:

<ComboBox x:Name="ComboBox" l:ComboBoxExtensions.InitialIndexOnItemsSourceChanged="0" />

请注意,我将附加的依赖项属性ComboBoxExtensions.InitialIndexOnItemsSourceChanged设置为0,这意味着每次ItemsSource更改时,SelectedIndex都将设置为0. { {1}}指的是我需要引用以使用我的自定义附加属性的本地XML命名空间(xmlns)。

我以这种方式实现了依赖属性:

l:

在这个类中,我定义了前面提到的附加属性。另一个重要的部分是public class ComboBoxExtensions { public static readonly DependencyProperty InitialIndexOnItemsSourceChangedProperty; private static readonly IDictionary<ComboBox, BindingSpy<ComboBox, IEnumerable>> ComboBoxToBindingSpiesMapping = new Dictionary<ComboBox, BindingSpy<ComboBox, IEnumerable>>(); static ComboBoxExtensions() { InitialIndexOnItemsSourceChangedProperty = DependencyProperty.RegisterAttached("InitialIndexOnItemsSourceChanged", typeof (int?), typeof (ComboBoxExtensions), new FrameworkPropertyMetadata(null, OnInitialIndexOnItemsSourceChanged)); } public static void SetInitialIndexOnItemsSourceChanged(ComboBox targetComboBox, int? value) { if (targetComboBox == null) throw new ArgumentNullException("targetComboBox"); targetComboBox.SetValue(InitialIndexOnItemsSourceChangedProperty, value); } public static int? GetInitialIndexOnItemsSourceChanged(ComboBox targetComboBox) { if (targetComboBox == null) throw new ArgumentNullException("targetComboBox"); return (int?) targetComboBox.GetValue(InitialIndexOnItemsSourceChangedProperty); } private static void OnInitialIndexOnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var targetComboBox = d as ComboBox; if (targetComboBox == null) return; if ((int?) e.NewValue != null) { SetInitialIndexIfPossible(targetComboBox); EstablishBindingSpy(targetComboBox); return; } ReleaseBindingSpy(targetComboBox); } private static void EstablishBindingSpy(ComboBox targetComboBox) { if (ComboBoxToBindingSpiesMapping.ContainsKey(targetComboBox)) return; var bindingSpy = new BindingSpy<ComboBox, IEnumerable>(targetComboBox, ItemsControl.ItemsSourceProperty); bindingSpy.TargetValueChanged += OnItemsSourceChanged; ComboBoxToBindingSpiesMapping.Add(targetComboBox, bindingSpy); } private static void ReleaseBindingSpy(ComboBox targetComboBox) { if (ComboBoxToBindingSpiesMapping.ContainsKey(targetComboBox) == false) return; var bindingSpy = ComboBoxToBindingSpiesMapping[targetComboBox]; bindingSpy.ReleaseBinding(); ComboBoxToBindingSpiesMapping.Remove(targetComboBox); } private static void OnItemsSourceChanged(BindingSpy<ComboBox, IEnumerable> bindingSpy) { SetInitialIndexIfPossible(bindingSpy.TargetObject); } private static void SetInitialIndexIfPossible(ComboBox targetComboBox) { var initialIndexOnItemsSourceChanged = GetInitialIndexOnItemsSourceChanged(targetComboBox); if (targetComboBox.ItemsSource != null && initialIndexOnItemsSourceChanged.HasValue) { targetComboBox.SelectedIndex = initialIndexOnItemsSourceChanged.Value; } } } 方法,当在组合框上设置附加属性时将调用该方法。在那里,我只是确定是否必须遵守组合框的OnInitialIndexOnItemsSourceChanged属性。

为了实现对ItemsSource的观察,我使用另一个名为ItemsSource的自定义类,它在BindingSpy和绑定间谍的自定义依赖属性之间建立数据绑定,因为这是唯一的方法我可以识别ItemsSource属性是否已更改。遗憾的是,ItemsSource(分别为ComboBox)未提供指示源集合已更改的事件。 ItemsControl的实施方式如下:

BindingSpy

正如我之前所说,这个类建立了一个绑定,并通过public class BindingSpy<TSource, TValue> : DependencyObject where TSource : DependencyObject { private readonly TSource _targetObject; private readonly DependencyProperty _targetProperty; public static readonly DependencyProperty TargetValueProperty = DependencyProperty.Register("TargetValue", typeof (TValue), typeof (BindingSpy<TSource, TValue>), new FrameworkPropertyMetadata(null, OnTargetValueChanged)); public BindingSpy(TSource targetObject, DependencyProperty targetProperty) { if (targetObject == null) throw new ArgumentNullException("targetObject"); if (targetProperty == null) throw new ArgumentNullException("targetProperty"); _targetObject = targetObject; _targetProperty = targetProperty; var binding = new Binding { Source = targetObject, Path = new PropertyPath(targetProperty), Mode = BindingMode.OneWay }; BindingOperations.SetBinding(this, TargetValueProperty, binding); } public TValue TargetValue { get { return (TValue) GetValue(TargetValueProperty); } set { SetValue(TargetValueProperty, value); } } public TSource TargetObject { get { return _targetObject; } } public DependencyProperty TargetProperty { get { return _targetProperty; } } public void ReleaseBinding() { BindingOperations.ClearBinding(this, TargetValueProperty); } private static void OnTargetValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var bindingSpy = d as BindingSpy<TSource, TValue>; if (bindingSpy == null) return; if (bindingSpy.TargetValueChanged != null) bindingSpy.TargetValueChanged(bindingSpy); } public event Action<BindingSpy<TSource, TValue>> TargetValueChanged; } 事件通知客户。

实现此目的的另一种方法是创建属于Blend SDK的WPF行为。您可以在此处找到相关教程:http://wpftutorial.net/Behaviors.html。基本上它与附加属性的模式相同。

如果您使用MVVM,我肯定会建议您使用Sheridan的解决方案 - 但如果没有,我的解决方案可能更合适。

如果您有任何疑问,请随时提出。

答案 1 :(得分:0)

ComboBox.SelectedIndexComboBox本身设置,不应由开发人员设置。您应该将数据绑定到int属性,以便您可以确定选择了哪个项目和/或从代码中选择项目:

<ComboBox ItemsSource="{Binding YourItems}" SelectedIndex="{Binding YourIndex}" />

然后在代码中:

int selectedIndex = YourIndex;

或者选择第一项例如:

YourIndex = 0;

要了解有关数据绑定的更多信息,请参阅MSDN上的Data Binding Overview‎页面。