英文:
Behavior for enabling/disabling a WPF ComboBox depending on number of items
问题
每当 WPF ComboBox 的 ItemsSource 更改(例如添加或删除元素,或分配新的集合),我希望它执行以下操作(伪代码):
IsEnabled = Items.Count > 1;
if (Items.Count == 1)
SelectedItem = Items.First();
我正在使用 MVVM,并且知道如何在 MVVM 中实现它。但我想避免模板代码,而且在我看来,这对于 ViewModel 来说太依赖于 UI。所以是否有办法在 Behavior<ComboBox>
中指定这个行为?
我找不到可以订阅的 ComboBox 事件。如果可能的话,它应该适用于 ObservableCollection 以及 ICollectionView 或 List 等。
英文:
Whenever the ItemsSource of a WPF ComboBox changes (i.e. adding or removing elements, or assigning a new Collection), I want it to do the following (pseudo code):
IsEnabled = Items.Count > 1;
if (Items.Count == 1)
SelectedItem = Items.First();
I'm using MVVM, and I know how to do it in MVVM. But I want to avoid the boilerplate code, and IMHO it is too UI-specific for the ViewModel to care about. So is there a way to specify this in a Behavior<ComboBox>
?
I couldn't find a ComboBox event I could subscribe to. If possible, it should work on ObservableCollection as well as ICollectionView or List etc.
答案1
得分: 2
您可以使用触发器来定义一个名为customComboBox
的样式:
<Style x:Key="customComboBox" TargetType="ComboBox">
<Style.Triggers>
<Trigger Property="HasItems" Value="False">
<Setter Property="IsEnabled" Value="False" />
</Trigger>
<DataTrigger Binding="{Binding Items.Count, RelativeSource={RelativeSource Self}}" Value="1">
<Setter Property="SelectedIndex" Value="0" />
</DataTrigger>
</Style.Triggers>
</Style>
例如,如果您将这个样式放在您的App.xaml
文件中,您可以在整个应用程序中使用它,例如:
<ComboBox ItemsSource="{Binding SomeCollection}" Style="{StaticResource customComboBox}" />
英文:
You could use a Style
with triggers:
<Style x:Key="customComboBox" TargetType="ComboBox">
<Style.Triggers>
<Trigger Property="HasItems" Value="False">
<Setter Property="IsEnabled" Value="False" />
</Trigger>
<DataTrigger Binding="{Binding Items.Count, RelativeSource={RelativeSource Self}}"
Value="1">
<Setter Property="SelectedIndex" Value="0" />
</DataTrigger>
</Style.Triggers>
</Style>
If you for example put this in your App.xaml
file, you can use it across the whole application, e.g.:
<ComboBox ItemsSource="{Binding SomeCollection}" Style="{StaticResource customComboBox}" />
答案2
得分: 1
你可以通过监视 ItemsSource
依赖属性的变化以及监视源集合实现了 INotifyCollectionChanged
的情况下,通过 CollectionChanged
事件来捕获源集合的变化。
using System;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using Microsoft.Xaml.Behaviors;
public class ItemsControlBehavior : Behavior<ItemsControl>
{
protected override void OnAttached()
{
base.OnAttached();
var dpd = DependencyPropertyDescriptor.FromProperty(ItemsControl.ItemsSourceProperty, typeof(ItemsControl));
dpd?.AddValueChanged(AssociatedObject, OnItemsSourceChanged);
AddSourceCollection();
}
protected override void OnDetaching()
{
base.OnDetaching();
var dpd = DependencyPropertyDescriptor.FromProperty(ItemsControl.ItemsSourceProperty, typeof(ItemsControl));
dpd?.RemoveValueChanged(AssociatedObject, OnItemsSourceChanged);
RemoveSourceCollection();
}
private void OnItemsSourceChanged(object? sender, EventArgs e)
{
RemoveSourceCollection();
AddSourceCollection();
}
private INotifyCollectionChanged? _collection;
private void AddSourceCollection()
{
_collection = AssociatedObject.ItemsSource as INotifyCollectionChanged;
if (_collection is not null)
{
_collection.CollectionChanged += OnItemsSourceCollectionChanged;
}
Apply();
}
private void RemoveSourceCollection()
{
if (_collection is not null)
{
_collection.CollectionChanged -= OnItemsSourceCollectionChanged;
}
_collection = null;
}
private void OnItemsSourceCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
Apply();
}
private void Apply()
{
AssociatedObject.IsEnabled = _collection is ICollection { Count: > 1 };
if (AssociatedObject is Selector selector)
{
selector.SelectedIndex = 0;
}
}
}
英文:
You can capture the change of the source collection from the change of ItemsSource
DependencyProperty and the change of the source collection items from CollectionChanged events provided that the source collection implements INotifyCollectionChanged.
using System;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using Microsoft.Xaml.Behaviors;
public class ItemsControlBehavior : Behavior<ItemsControl>
{
protected override void OnAttached()
{
base.OnAttached();
var dpd = DependencyPropertyDescriptor.FromProperty(ItemsControl.ItemsSourceProperty, typeof(ItemsControl));
dpd?.AddValueChanged(AssociatedObject, OnItemsSourceChanged);
AddSourceCollection();
}
protected override void OnDetaching()
{
base.OnDetaching();
var dpd = DependencyPropertyDescriptor.FromProperty(ItemsControl.ItemsSourceProperty, typeof(ItemsControl));
dpd?.RemoveValueChanged(AssociatedObject, OnItemsSourceChanged);
RemoveSourceCollection();
}
private void OnItemsSourceChanged(object? sender, EventArgs e)
{
RemoveSourceCollection();
AddSourceCollection();
}
private INotifyCollectionChanged? _collection;
private void AddSourceCollection()
{
_collection = AssociatedObject.ItemsSource as INotifyCollectionChanged;
if (_collection is not null)
{
_collection.CollectionChanged += OnItemsSourceCollectionChanged;
}
Apply();
}
private void RemoveSourceCollection()
{
if (_collection is not null)
{
_collection.CollectionChanged -= OnItemsSourceCollectionChanged;
}
_collection = null;
}
private void OnItemsSourceCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
Apply();
}
private void Apply()
{
AssociatedObject.IsEnabled = _collection is ICollection { Count: > 1 };
if (AssociatedObject is Selector selector)
{
selector.SelectedIndex = 0;
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论