Переключение кнопки "CanExecute" на основе выбора сетки
Я очень люблю современное программирование пользовательского интерфейса, и теперь я застрял в небольшом WPF-приложении на C#, которое в основном представляет собой учебный проект шаблона проектирования 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?
Большое спасибо за вашу помощь!
2 ответа
Внести следующие исправления
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"));
}
}
Вы должны определить свойство SelectedItem в вашей ViewModel и связать его с вашей 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 и удалять оцениваемый RequireySuggested из CommandManager. Вы можете попробовать это.
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();
}
}