I try not to post questions like this, but i've really been struggling to find an answer or similar example. I have what I think is a really simple example I'd like to setup. Basically I want to use commanding to add an item from a textbox to a listbox. I want to make sure there is something in the textbox via CanExecute and i want to make sure that its not already in the list.
I know this seems over complicated for what it is, but it hits on some points I've been struggling with.
<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>
I have a Person Class
class Person
{
public string Name { get; set; }
}
The only reason I have this is that the Add needs to create a new object, so slightly more complex than a simple string.
And then a basic view model
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
}
So the question is, how would I implement commanding so that it uses the CanExecute to disable the Add button if the name is already there or the Name field is empty.
And then the same deal for Remove, only enabled if a name is selected in the list.
I'd like to make this as MVVM compliment as possible.
I've seen that you can do the Button.CommandBindings attached property to inject the methods you'd like to use for each, but that doesnt seem completely MVVM happy.
Also, i'd like to avoid the use of frameworks (Prism/Caliburn.Micro) since this is primarily for education reasons.
Also any references would be greatly appreciated. I've read many blogs etc but I always feel like they stray off before implementing a complete, simple example.
Well, MVVM is just a pattern or philosophy, so I think your desire to avoid using a framework might be a little misguided. Even if you're not using one of those frameworks, you will essentially be writing your own framework in order to implement the MVVM pattern.
That being said, probably what you want to use is a
DelegateCommand
or one of the similar implementations. See: http://www.wpftutorial.net/DelegateCommand.html. The important part that I think you are looking for is that the command that the WPF button is binding to must raise theCanExecuteChanged
event whenever there is a change made in the view model which affects whether the command can or cannot be executed.So in your case, for example, you would want to add a call to the
CanExecuteChanged
of yourAddPersonDelegateCommand
to yourOnPropertyChanged
method (possibly filtered by the name of the property that was changed). This tells anything bound to the command to callCanExecute
on the command, and then you would have your logic in thatCanExecute
that actually determines if a person with the entered name already exists.So to add some sample code, it might look something like this:
*Note: In this sample your
<TextBox></TextBox>
would need to be bound to theNewNameTextBox
property on the view model.I will show how to do the add, the remove is similar and I leave that for you to figure out. First I will show the xaml changes with the button using an
AddPerson
command:We have bound the current edited text to a new property on the View Model named
CurrentPerson
. This is done because we want to access what the person enters, but also we need the binding updated as the user types. To accomplish that updating, we specify that the binding updates by setting theUpdateSourceTrigger
attribute to bePropertyChanged
. Otherwise our theCurrentPerson
string and ultimately the commandCan
operation would only fire when the edit text box lost focus.ViewModel The viewmodel will subscribe to the
AddPerson
command. Execution of that will add the user, but also check acan
method which returns a boolean whether to enable the button or not. The can will be excecuted when theCurrentPerson
property changes where we ultimately callRaiseCanExecuteChanged
on the commanding class to have the button check thecan
method.(This VM is abbreviated for the example and based on your full VM)
Finally here is the commanding class used which is based on my blog article Xaml: ViewModel Main Page Instantiation and Loading Strategy for Easier Binding.: