我非常喜欢现代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?
非常感谢你的帮助!
答案 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();
}
}