WPF:将MenuItem的IsEnabled绑定到ObservableCollection<T>的Items.Any()
刚好碰到过类似的场景,WPF的绑定系统没法直接在XAML里调用LINQ的Any()方法,给你两种靠谱的实现方式,按需选择就行:
方法一:用值转换器(IValueConverter)实现
这种方式不用修改你现有的MyClass结构,通用性很强,其他地方需要判断集合是否非空也能复用:
先写一个集合转布尔值的转换器
这个转换器会把传入的集合转换成true(有元素)或false(空集合):using System; using System.Collections; using System.Globalization; using System.Windows.Data; public class CollectionHasItemsConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is IEnumerable collection) { using (var enumerator = collection.GetEnumerator()) { return enumerator.MoveNext(); } } return false; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException("反向转换不需要实现,毕竟没法从布尔值还原集合"); } }在XAML里引用这个转换器
先在你的窗口/用户控件的资源里声明它,记得替换YourProjectName为你实际的项目命名空间:<Window.Resources> <local:CollectionHasItemsConverter x:Key="HasItemsConverter"/> </Window.Resources>(需要先在XAML根节点添加命名空间声明:
xmlns:local="clr-namespace:YourProjectName")修改MenuItem的绑定代码
现在就可以把IsEnabled绑定到Items集合,通过转换器转成布尔值:<MenuItem x:Name="MyMenu" IsEnabled="{Binding Path=Items, Source={x:Static local:MyClass.Current}, Converter={StaticResource HasItemsConverter}}" Header="MENU"> </MenuItem>这里用
Source={x:Static local:MyClass.Current}指定了绑定的数据源是你的静态实例。
方法二:给MyClass加个监听集合变化的属性
如果你愿意调整MyClass的结构,这种方式的绑定更直观,可读性也更好:
让MyClass实现INotifyPropertyChanged接口
添加一个HasItems属性,并且监听ObservableCollection的CollectionChanged事件,自动更新这个属性的值:using System.Collections.ObjectModel; using System.ComponentModel; using System.Runtime.CompilerServices; public class MyClass : INotifyPropertyChanged { public static MyClass Current = new MyClass(); public ObservableCollection<object> Items { get; } = new ObservableCollection<object>(); private bool _hasItems; public bool HasItems { get => _hasItems; private set { if (_hasItems != value) { _hasItems = value; OnPropertyChanged(); } } } public MyClass() { // 监听集合的增删变化,实时更新HasItems Items.CollectionChanged += (sender, e) => { HasItems = Items.Count > 0; }; // 初始化的时候先检查一次集合状态 HasItems = Items.Count > 0; } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }修改MenuItem的绑定
现在直接绑定到新的HasItems属性就行,非常简洁:<MenuItem x:Name="MyMenu" IsEnabled="{Binding Path=HasItems, Source={x:Static local:MyClass.Current}}" Header="MENU"> </MenuItem>
两种方式怎么选?
- 如果你不想改动现有类,或者需要在多个地方判断集合是否非空,选转换器方法,复用性拉满;
- 如果你希望绑定逻辑更清晰,或者这个
HasItems状态还会用到其他地方,选新增属性方法,代码可读性更好。
内容的提问来源于stack exchange,提问作者G.Dealmeida
相关产品推荐
相关产品推荐

