我希望每次更改组合框的itemssource时,都会设置SelectedIndex。
到目前为止,我有这个:
<Style TargetType="ComboBox">
<Setter Property="SelectedIndex"
Value="0"></Setter>
</Style>
它设置selectedIndex,但仅在第一次设置itemSource时设置。当整个itemSource被更改时,它将被加载到组合框中但不再被选中。此时它应该选择第一个项目。 每个ItemSource都有一个绑定,我不想用后面的代码设置SelectedIndex。 我想要一个xaml的解决方案,可能是一个触发器。
答案 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.SelectedIndex
由ComboBox
本身设置,不应由开发人员设置。您应该将数据绑定到int
属性,以便您可以确定选择了哪个项目和/或从代码中选择项目:
<ComboBox ItemsSource="{Binding YourItems}" SelectedIndex="{Binding YourIndex}" />
然后在代码中:
int selectedIndex = YourIndex;
或者选择第一项例如:
YourIndex = 0;
要了解有关数据绑定的更多信息,请参阅MSDN上的Data Binding Overview页面。