【问题标题】:Toggle "CanExecute" of a button based on grid selection根据网格选择切换按钮的“CanExecute”
【发布时间】:2015-08-26 21:51:01
【问题描述】:

我非常喜欢现代 UI 编程,现在我陷入了一个小型 C# WPF 应用程序,它基本上是一个 MVVM 设计模式的学习项目。

我有一个 DataGrid 和一些按钮来处理数据操作(添加、编辑、删除)。

我想要实现的目标:当没有选择网格中的行时,不应启用编辑按钮。

编辑按钮:

<Button Width="126" Height="22" Content="Edit" Margin="5,5,5,5" Command="{Binding KontoEdit}" />

网格:

   <DataGrid ItemsSource="{Binding Konten}"  SelectedItem="{Binding SelectedKonto}">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Path=KtoNr}" Header="Nr" IsReadOnly="True" />
            <DataGridTextColumn Binding="{Binding Path=Name}" Header="Name" IsReadOnly="True"  />
            <DataGridTextColumn Binding="{Binding Path=KtoArt}" Header="Kontoart" IsReadOnly="True"  />
            <DataGridTextColumn Binding="{Binding Path=KtoKlasse}" Header="Kontenklasse" IsReadOnly="True"  />
        </DataGrid.Columns>
    </DataGrid>

查看模型:

public class MainViewModel : INotifyPropertyChanged
{
    KontenDB ctx = new KontenDB();

    public MainViewModel()
    {
        FillKonten();

        CanKontoEditExecute = true ;

        KontoEdit = new RelayCommand(o => { DoKontoEdit(SelectedKonto); }, param => CanKontoEditExecute);
    }


    #region //Commands
    public void DoKontoEdit(Konten k)
    {
        //Edit the Selected Item
    }

    private ICommand _kontoEdit;
    public ICommand KontoEdit
    {
        get
        {
            return _kontoEdit;
        }
        set
        {
            _kontoEdit = value;
        }
    }

    private bool _canKontoEditExecute;

    public bool CanKontoEditExecute
    {
        get
        {
            return _canKontoEditExecute;
        }
        set
        {
            _canKontoEditExecute = value;
        }
    }

    #endregion //Commands
    private void FillKonten()
    {
        var q = (from k in ctx.Konten
                 select k).ToList();
        Konten = new ObservableCollection<Konten>(q);
    }


    private ObservableCollection<Konten> _konten;
    public ObservableCollection<Konten> Konten
    {
        get
        {
            return _konten;
        }
        set
        {
            _konten = value;
            NotifyPropertyChanged();
        }
    }

    private Konten _selectedKonto;
    public Konten SelectedKonto
    {
        get
        {
            return _selectedKonto;
        }
        set
        {
            _selectedKonto = value;
            NotifyPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

模型由 EF6 生成。

编辑:RelayCommand 类:

public class RelayCommand : ICommand
    {
        private Action<object> execute;

        private Predicate<object> canExecute;

        private event EventHandler CanExecuteChangedInternal;

        public RelayCommand(Action<object> execute)
            : this(execute, DefaultCanExecute)
        {
        }

        public RelayCommand(Action<object> execute, Predicate<object> canExecute)
        {
            if (execute == null)
            {
                throw new ArgumentNullException("execute");
            }

            if (canExecute == null)
            {
                throw new ArgumentNullException("canExecute");
            }

            this.execute = execute;
            this.canExecute = canExecute;
        }

        public event EventHandler CanExecuteChanged
        {
            add
            {
                CommandManager.RequerySuggested += value;
                CanExecuteChangedInternal += value;
            }

            remove
            {
                CommandManager.RequerySuggested -= value;
                CanExecuteChangedInternal -= value;
            }
        }

        public bool CanExecute(object parameter)
        {
            return canExecute != null && canExecute(parameter);
        }

        public void Execute(object parameter)
        {
            execute(parameter);
        }

        public void OnCanExecuteChanged()
        {
            EventHandler handler = CanExecuteChangedInternal;
            if (handler != null)
            {
                handler.Invoke(this, EventArgs.Empty);
            }
        }

        public void Destroy()
        {
            canExecute = _ => false;
            execute = _ => { return; };
        }

        private static bool DefaultCanExecute(object parameter)
        {
            return true;
        }
    }

那么在以下情况下我该如何实现:未选择数据网格中的行或 SelectedKonto 为 null CanKontoEditExecute 属性更改为 false?

非常感谢您的帮助!

【问题讨论】:

  • 在 RelayCommand 构造函数中添加 Func 并将其分配给 CanExecute。
  • 对不起,我不明白你的意思..看看RelayCommand类的样子对你有用吗?
  • 肯定会的。
  • 好的,我编辑了问题

标签: c# wpf mvvm relaycommand canexecute


【解决方案1】:

进行以下更正

SelectedItem="{Binding SelectedKonto, Mode=TwoWay}"


KontoEdit = new RelayCommand(o => { DoKontoEdit(SelectedKonto); }, param => SelectedKonto != nulll);


private object _selectedItem;
public object SelectedItem
{
    get { return _selectedItem; }
    set
    {
        _selectedItem = value;
        PropertyChanged(this,new PropertyChangedEventArgs("SelectedItem"));
    }
}

【讨论】:

    【解决方案2】:

    您应该在 ViewModel 中定义 SelectedItem 属性并将其绑定到 DataGrid。

    CS:

        private object _selectedItem;
        public object SelectedItem
        {
            get { return _selectedItem; }
            set
            {
                _selectedItem = value;
                if(PropertyChanged != null)
                    PropertyChanged(this,new PropertyChangedEventArgs("SelectedItem"));
    
                DoKontoEdit.OnCanExecuteChanged();
            }
        }
    

    XAML:

        <DataGrid SelectedItem="{Binding SelectedItem}">
            ....
    

    那么你的命令应该这样初始化:

       new RelayCommand(o => { DoKontoEdit(SelectedKonto); }, _ => SelectedItem != null);
    

    这是我认为更好的 ICommand 实现。当我决定何时评估 canExecute 委托并删除已评估的 CommandManager 的 RequireySuggested 时,我更喜欢它。你不妨试试看。

             public class RelayCommand<T> : IRelayCommand
    {
        private Predicate<T> _canExecute;
        private Action<T> _execute;
    
        public RelayCommand(Action<T> execute, Predicate<T> canExecute = null)
        {
            _execute = execute;
            _canExecute = canExecute;
        }
    
        public void Execute(T parameter)
        {
            _execute(parameter);
        }
    
        private bool CanExecute(T parameter)
        {
            return _canExecute == null ? true : _canExecute(parameter);
        }
    
        public virtual bool CanExecute(object parameter)
        {
            return parameter == null ? false : CanExecute((T)parameter);
        }
    
        public void Execute(object parameter)
        {
            _execute((T)parameter);
        }
    
        public event EventHandler CanExecuteChanged;
    
        //public event EventHandler CanExecuteChanged
        //{
        //    add { CommandManager.RequerySuggested += value; }
        //    remove { CommandManager.RequerySuggested -= value; }
        //}
    
    
        public void RaiseCanExecuteChanged()
        {
            var temp = Volatile.Read(ref CanExecuteChanged);
    
            if (temp != null)
                temp(this, new EventArgs());
        }
    }
    
    public class RelayCommand : IRelayCommand
    {
        private Func<bool> _canExecute;
        private Action _execute;
    
        public RelayCommand(Action execute , Func<bool> canExecute = null)
        {
            _execute = execute;
            _canExecute = canExecute;
        }
    
        public bool CanExecute(object parameter)
        {
            return _canExecute == null ? true : _canExecute();
        }
    
        //public event EventHandler CanExecuteChanged
        //{
        //    add { CommandManager.RequerySuggested += value; }
        //    remove { CommandManager.RequerySuggested -= value; }
        //}
    
        public event EventHandler CanExecuteChanged;
    
        public void RaiseCanExecuteChanged()
        {
            var temp = Volatile.Read(ref CanExecuteChanged);
    
            if (temp != null)
                temp(this, new EventArgs());
        }
    
        public void Execute(object parameter)
        {
            _execute();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-25
      • 2012-12-09
      • 2013-09-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多