根据网格选择切换按钮 "CanExecute"
Toggle "CanExecute" of a button based on grid selection
我非常喜欢现代 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 class:
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?
非常感谢您的帮助!
进行以下更正
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"));
}
}
您应该在您的 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();
}
}
我非常喜欢现代 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 class:
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?
非常感谢您的帮助!
进行以下更正
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"));
}
}
您应该在您的 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();
}
}