繁体   English   中英

WPF:具有ObservableCollection的绑定IsEnabled MenuItem <T> Items.Any()

[英]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返回falseMenuItem将自动被禁用。

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 (例如, UserControlPageWindow )设置为视图模型的实例。

要将菜单项连接到命令,请按如下所示修改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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM