C# WPF简单命令示例
我尽量不发表这样的问题,但我一直在努力寻找答案或类似的例子。我有一个我认为非常简单的例子,我想设置。 基本上,我想使用命令将一个项目从文本框添加到列表框。我想通过CanExecute确保文本框中有一些内容,并且我想确保它不在列表中 我知道这看起来太复杂了,但它击中了我一直在努力解决的一些问题C# WPF简单命令示例,c#,wpf,mvvm,C#,Wpf,Mvvm,我尽量不发表这样的问题,但我一直在努力寻找答案或类似的例子。我有一个我认为非常简单的例子,我想设置。 基本上,我想使用命令将一个项目从文本框添加到列表框。我想通过CanExecute确保文本框中有一些内容,并且我想确保它不在列表中 我知道这看起来太复杂了,但它击中了我一直在努力解决的一些问题 <Window x:Class="Commanding_Example.MainWindow" xmlns="http://schemas.microsoft.com/winfx/20
<Window x:Class="Commanding_Example.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local ="clr-namespace:Commanding_Example"
Title="MainWindow" Width="200" Height="300">
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<StackPanel>
<TextBlock>Name</TextBlock>
<TextBox></TextBox>
<Button>Add</Button>
<Button>Remove</Button>
<ListBox ItemsSource="{Binding People}" DisplayMemberPath="Name"></ListBox>
</StackPanel>
</Window>
我这样做的唯一原因是Add需要创建一个新对象,比简单字符串稍微复杂一些
然后是一个基本的视图模型
class MainViewModel : INotifyPropertyChanged
{
public MainViewModel()
{
People = new ObservableCollection<Person>();
People.Add( new Person {Name = "jimmy"});
}
public ObservableCollection<Person> People { get; set; }
#region Default INotifyPropertyChanged implimentation
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
class MainViewModel:INotifyPropertyChanged
{
公共主视图模型()
{
人员=新的可观察集合();
添加(新人物{Name=“jimmy”});
}
公共可观察集合人员{get;set;}
#区域默认INotifyPropertyChanged实现
公共事件属性更改事件处理程序属性更改;
受保护的虚拟void OnPropertyChanged([CallerMemberName]字符串propertyName=null)
{
PropertyChangedEventHandler处理程序=PropertyChanged;
if(handler!=null)handler(这是新的PropertyChangedEventArgs(propertyName));
}
#端区
}
所以问题是,如果名称已经存在或名称字段为空,我将如何实现命令,以便它使用CanExecute禁用Add按钮
然后删除相同的交易,只有在列表中选择名称时才启用
我想尽可能将此作为对MVVM的赞美
我已经看到,您可以使用Button.CommandBindings attached属性来注入您希望用于每个方法的方法,但这似乎并不完全符合MVVM的要求
另外,我希望避免使用框架(Prism/Caliburn.Micro),因为这主要是出于教育原因
此外,如有任何参考资料,将不胜感激。我读过很多博客等,但我总觉得它们在实现一个完整、简单的示例之前就偏离了方向。好吧,MVVM只是一种模式或理念,所以我认为您希望避免使用框架可能有点误导。即使您没有使用这些框架中的任何一个,您也需要编写自己的框架来实现MVVM模式 话虽如此,您可能希望使用的是
DelegateCommand
或类似的实现之一。请参阅:。我认为您正在寻找的重要部分是,WPF按钮绑定到的命令必须在视图模型中发生影响命令是否可以执行的更改时引发CanExecuteChanged
事件
因此,在您的情况下,例如,您可能希望将对AddPersonDelegateCommand
的CanExecuteChanged
的调用添加到OnPropertyChanged
方法中(可能通过更改的属性名称进行过滤)。这会告诉绑定到命令的任何东西调用该命令上的CanExecute
,然后您将在该CanExecute
中使用您的逻辑,该逻辑实际确定具有输入名称的人是否已经存在
因此,要添加一些示例代码,它可能如下所示:
class MainViewModel : INotifyPropertyChanged
{
public MainViewModel()
{
People = new ObservableCollection<Person>();
People.Add( new Person {Name = "jimmy"});
AddPersonDelegateCommand = new DelegateCommand(AddPerson, CanAddPerson);
}
// Your existing code here
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
if(propertyName == "NewNameTextBox") AddPersonDelegateCommand.RaiseCanExecuteChanged();
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
public DelegateCommand AddPersonDelegateCommand { get; set; }
public void AddPerson()
{
// Code to add a person to the collection
}
public bool CanAddPerson()
{
return !People.Any(p=>p.Name == NewNameTextBox);
}
public string NewNameTextBox
{
get { return _newNameTextBox; }
set
{
_newNameTextBox = value;
OnPropertyChanged();
}
}
}
class MainViewModel:INotifyPropertyChanged
{
公共主视图模型()
{
人员=新的可观察集合();
添加(新人物{Name=“jimmy”});
AddPersonDelegateCommand=新的DelegateCommand(AddPerson,CanAddPerson);
}
//您的现有代码在这里
受保护的虚拟void OnPropertyChanged([CallerMemberName]字符串propertyName=null)
{
如果(propertyName==“NewNameTextBox”)AddPersonDelegateCommand.RaiseCanceTechChanged();
PropertyChangedEventHandler处理程序=PropertyChanged;
if(handler!=null)handler(这是新的PropertyChangedEventArgs(propertyName));
}
public DelegateCommand AddPersonDelegateCommand{get;set;}
公众人士()
{
//将人员添加到集合的代码
}
公共图书馆
{
return!People.Any(p=>p.Name==NewNameTextBox);
}
公共字符串NewNameTextBox
{
获取{return\u newNameTextBox;}
设置
{
_newNameTextBox=值;
OnPropertyChanged();
}
}
}
*注意:在此示例中,您的
需要绑定到视图模型上的NewNameTextBox
属性
我如何执行命令,以便它使用CanExecute
如果名称或名称字段已存在,请禁用“添加”按钮
是空的
我将展示如何进行添加,删除是类似的,我留给你去弄清楚。首先,我将使用AddPerson
命令通过按钮显示xaml更改:
<TextBox Text="{Binding CurrentPerson,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged
}"/>
<Button Command="{Binding AddPerson}">Add</Button>
最后,这里是根据我的博客文章使用的命令类:
公共类操作命令:ICommand
{
#区域变量
Func canExecute;
行动执行;
公共事件处理程序CanExecuteChanged;
#端区
#区域属性
#端区
#区域构造/初始化
公共操作命令(操作执行)
:this(executeAction,null)
{
}
公共操作命令(Action executeAction,Func canExecute)
{
if(executeAction==null)
{
抛出新ArgumentNullException(“ICommanding操作的执行操作为null”);
}
this.executeAction=executeAction;
this.canExecute=canExecute;
}
#端区
#区域方法
公共布尔CanExecute(对象参数)
{
布尔结果=真;
Func canExecuteHandler=this.canExecute;
如果(canExecuteHandler!=null)
{
结果=canExecuteHandler(参数);
}
返回结果;
}
public void raisecancecutechanged()
{
EventHandler=this.CanExecuteChanged;
if(处理程序!=null)
{
处理程序(这是新的EventArgs());
}
}
P
<TextBox Text="{Binding CurrentPerson,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged
}"/>
<Button Command="{Binding AddPerson}">Add</Button>
public OperationCommand AddPerson { get; set; }
public string _currentPerson;
public MainViewModel()
{
People = new ObservableCollection<Person>();
People.Add(new Person { Name = "jimmy" });
// First Lamda is where we execute the command to add,
// The second lamda is the `Can` method to enable the button.
AddPerson = new OperationCommand((o) => People.Add(new Person { Name = CurrentPerson }),
(o) => (!string.IsNullOrWhiteSpace(CurrentPerson) &&
!People.Any(per => per.Name == CurrentPerson)));
// When the edit box text changes force a `Can` check.
this.PropertyChanged += MainViewModel_PropertyChanged ;
}
void MainViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "CurrentPerson")
AddPerson.RaiseCanExecuteChanged();
}
public class OperationCommand : ICommand
{
#region Variables
Func<object, bool> canExecute;
Action<object> executeAction;
public event EventHandler CanExecuteChanged;
#endregion
#region Properties
#endregion
#region Construction/Initialization
public OperationCommand(Action<object> executeAction)
: this(executeAction, null)
{
}
public OperationCommand(Action<object> executeAction, Func<object, bool> canExecute)
{
if (executeAction == null)
{
throw new ArgumentNullException("Execute Action was null for ICommanding Operation.");
}
this.executeAction = executeAction;
this.canExecute = canExecute;
}
#endregion
#region Methods
public bool CanExecute(object parameter)
{
bool result = true;
Func<object, bool> canExecuteHandler = this.canExecute;
if (canExecuteHandler != null)
{
result = canExecuteHandler(parameter);
}
return result;
}
public void RaiseCanExecuteChanged()
{
EventHandler handler = this.CanExecuteChanged;
if (handler != null)
{
handler(this, new EventArgs());
}
}
public void Execute(object parameter)
{
this.executeAction(parameter);
}
#endregion
}