切换" CanExecute"基于网格选择的按钮

时间:2015-08-26 13:17:56

标签: c# wpf mvvm relaycommand canexecute

我非常喜欢现代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为空,CanKontoEditExecute属性是否变为false?

非常感谢你的帮助!

2 个答案:

答案 0 :(得分:1)

带来以下更正

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


cursor = pexpect.spawn(<some_command>)
cursor.expect(XXX)
cursor.sendline(<some_command>)
output = cursors.after

答案 1 :(得分:1)

您应该在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();
    }
}