WPF:绑定IsEnabled MenuItem与ObservableCollection <t> Items.Any()

时间:2018-01-25 14:32:23

标签: c# wpf xaml

我在课程中有一个ObservableCollection<T>,我希望将IsEnabled元素的MenuItem属性与ObservableCollection<T>

绑定
Items.Any()

XAML =&gt;

<MenuItem x:Name="MyMenu" 
        IsEnabled="{Binding ????}" 
        Header="MENU">
</MenuItem>

C#=&gt;

public class MyClass
{
    public static MyClass Current = new MyClass();

    public ObservableCollection<Object> Items { get; } = new ObservableCollection<Object>();

}

3 个答案:

答案 0 :(得分:3)

惯用解决方案:命令

执行此操作的惯用方法是将菜单项绑定到命令,并让命令的CanExecute处理程序检查您的Items集合是否为空。如果MenuItem返回CanExecute,则false会自动停用。

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),但为了完整性我会在这里包含一个:

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" />

答案 1 :(得分:1)

您可以使用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>

ObservableCollection<T>每次Count属性更改时都会引发更改通知。

答案 2 :(得分:1)

您可以绑定到SELECT * FROM "schema1"."items" UNION SELECT * FROM "schema2"."items"; 属性并创建一个值转换器,将0转换为false,将非零转换为true:

ObservableCollection<T>.Count

然后将您的转换器添加到资源并使用绑定:

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();
    }
}