![](/img/trans.png)
[英]Accessing items in ObservableCollection bound to WPF DataGrid
[英]WPF : Bound IsEnabled MenuItem with ObservableCollection<T> Items.Any()
我在一个类中有一个ObservableCollection<T>
,并且我想用ObservableCollection<T>
绑定MenuItem
元素的IsEnabled
属性。
Items.Any()
XAML =>
<MenuItem x:Name="MyMenu"
IsEnabled="{Binding ????}"
Header="MENU">
</MenuItem>
C#=>
public class MyClass
{
public static MyClass Current = new MyClass();
public ObservableCollection<Object> Items { get; } = new ObservableCollection<Object>();
}
惯用的方法是将菜单项绑定到命令,并让命令的CanExecute
处理程序检查Items
集合是否为空。 如果CanExecute
返回false
则MenuItem
将自动被禁用。
public class MyViewModel : INotifyPropertyChanged
{
public ObservableCollection<Object> Items { get; }
public DelegateCommand MenuItemCommand { get; }
public MyViewModel()
{
Items = new ObservableCollection<object>();
MenuItemCommand = new DelegateCommand(
() => { /* Do Something */ },
() => Items.Count > 0);
Items.CollectionChanged += (s, e) => MenuItemCommand.RaiseCanExecuteChanged();
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
按照MVVM模式,应将屏幕的DataContext
(例如, UserControl
, Page
或Window
)设置为视图模型的实例。
要将菜单项连接到命令,请按如下所示修改Xaml:
<MenuItem Command="{Binding MenuItemCommand}"
Header="MENU" />
那里有无数DelegateCommand
实现的示例(有时称为RelayCommand
),但是为了完整RelayCommand
,我将在此处包括一个示例:
public class DelegateCommand : ICommand
{
private readonly Action _execute;
private readonly Func<bool> _canExecute;
public DelegateCommand(Action execute, Func<bool> canExecute = null)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute;
}
public virtual bool CanExecute() => _canExecute?.Invoke() ?? true;
public virtual void Execute() => _execute();
public void RaiseCanExecuteChanged()
{
OnCanExecuteChanged();
}
public event EventHandler CanExecuteChanged;
protected virtual void OnCanExecuteChanged()
{
this.CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
bool ICommand.CanExecute(object parameter)
{
return this.CanExecute();
}
void ICommand.Execute(object parameter)
{
this.Execute();
}
}
IsEnabled
如果您坚持不使用命令,则可以执行以下操作:
public class MyViewModel : INotifyPropertyChanged
{
public ObservableCollection<Object> Items { get; }
public bool HasItems => Items.Count > 0;
public MyViewModel()
{
Items = new ObservableCollection<object>();
Items.CollectionChanged += (s, e) => OnPropertyChanged(nameof(HasItems));
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
并如下更新您的Xaml:
<MenuItem IsEnabled="{Binding HasItems}"
Header="MENU" />
您可以使用Style
并直接绑定到Count
属性:
<MenuItem x:Name="MyMenu" Header="MENU">
<MenuItem.Style>
<Style TargetType="MenuItem">
<Style.Triggers>
<DataTrigger Binding="{Binding Items.Count}" Value="0">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</MenuItem.Style>
</MenuItem>
每次Count
属性更改时, ObservableCollection<T>
都会引发更改通知。
您可以绑定到ObservableCollection<T>.Count
属性,并创建一个值转换器,将0转换为false,将非零转换为true:
public class HasItemsConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (value as int?) > 0;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
然后将转换器添加到资源中并用于绑定:
<MenuItem x:Name="MyMenu"
IsEnabled="{Binding Items.Count, Converter={StaticResource HasItemsConverter}}"
Header="MENU">
</MenuItem>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.