I could use some help, trying to understand how the commands works in Wpf with Mvvm and how you bind a button to it. Have read a lot articles about commands and wpf, but they all seem to be different.
I have created a wpf project using mvvm pattern. Have a list view that will get filled with customers.
Now I want to make a search command, so I can change the data in the list view.
CustomerViewModel
public class CustomerViewModel : INotifyPropertyChanged, ICommand
{
private List<Customer> CustomerList;
public CustomerViewModel()
{
CustomerList = LoadCustomerData();
}
public List<Customer> LoadCustomerData()
{
List<Customer> data = new List<Customer>();
data.Add(new Customer() { Id = 1, FirstName = "Alexander", LastName = "Malkovich", PhoneNumber = "43215678", Email = "AlexanderMalkivich@gmail.com" });
data.Add(new Customer() { Id = 2, FirstName = "Mikkel", LastName = "Larsen", PhoneNumber = "87654321", Email = "MikkelLarsen@gmail.com" });
return data;
}
public List<Customer> CustomerDataLoadedOnSearch()
{
List<Customer> data = new List<Customer>();
data.Add(new Customer() { Id = 1, FirstName = "Ulrik", LastName = "Trissel", PhoneNumber = "35325235", Email = "UlrikTrissel@gmail.com" });
data.Add(new Customer() { Id = 2, FirstName = "Michael", LastName = "Mortensen", PhoneNumber = "14214124", Email = "Michael@gmail.com" });
return data;
}
public List<Customer> Customer
{
get
{
return CustomerList;
}
}
// Search Command
#region INotifyPropertyChanged members
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
Basically I run the LoadCustomerData() in the ctor, and gets the CustomerList with the get method.
I'm trying to create a search command, that will run the other method (CustomerDataLoadedOnSearch), and then trigger the get call again in the view.
XML view code:
<StackPanel Orientation="Vertical">
<Button Command="{Binding SearchCommand}" Padding="15, 5" HorizontalAlignment="Right">Search</Button>
</StackPanel>
<GroupBox Header="Customers">
<StackPanel Margin="10, 10" Orientation="Vertical">
<ListView Height="250" Width="Auto" ItemsSource="{Binding Customer}" Grid.Row="1">
<ListView.View>
<GridView >
<GridViewColumn Header="ID" Width="Auto">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Id}" TextAlignment="Right" Width="40"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding FirstName}" Header="First name" Width="100"/>
<GridViewColumn DisplayMemberBinding="{Binding LastName}" Header="Last name" Width="100"/>
<GridViewColumn DisplayMemberBinding="{Binding PhoneNumber}" Header="Phone" Width="100"/>
<GridViewColumn DisplayMemberBinding="{Binding Email}" Header="Email" Width="200"/>
</GridView>
</ListView.View>
</ListView>
</StackPanel>
</GroupBox>
Have binded a command called SearchCommand. Now I'm not so sure what to do next. Should I create a folder called Command and keep all commands in there for all my buttons I make?
Or should I keep all the ICommand code in the ViewModel? Hope someone can show me how this works.
Good day.
Update:
So far, thanks for your replys.
I managed to implement the ViewModelBase & RelayCommand class. Futhermore I have implemented the Icommand of the search button, but when i click it, it clears the list (the view loses its customers).
void SearchCommand_DoWork(object obj)
{
CustomerList.Clear();
CustomerList = CustomerDataLoadedOnSearch();
}
Have debugged the CustomerList and when I call the CustomerDataLoadedOnSearch, it have two rows with new customers inside, but the list hasen't been populated.
Let me try to answer this and I hope this will clear things a little bit for you.
As sexta13 said there is some frameworks you can use. Personally I don't like them at all.
What I instead do is to implement RelayCommand, which is the easiest solution in my opinion.
RelayCommand:
Next to that I implement ViewModelBase which looks like this:
With these two classes you are ready to go
MVVM
.And back to your example:
First of all your
private List<Customer> CustomerList;
should bepublic
and notprivate
. And then it should have getter and setter. otherwise it will not be reachable by your View.When this is said, then I will suggest that you will use
ObservableCollection<T>
instead of aList<T>
. Observable collections implementsINotifyPropertyChanged
, and every time your collection has changed, yourview
will know. If you useList<T>
then you have to tell your view manually that the collection has changed.When this is done then you can create a command in your VM:
The
()=>false
part of the assignment of the command is optional. if you leave it blank then you search button will be enabled. if you like this example use()=>false
it will always be disabled. You can use another attribute or delegate which returns a boolean.