Reputation: 35
I have the following situation:
Views:
ViewModels:
The EbayCategoryViewModel has a public Property, that is a List called ChildrenCategories. the TreeView is bound to the ObservableCollection and each node of the TreeView is an HyperLink. I would like that when the Hyperlink is clicked, the system opens the MaintainEbayCategoryView and load it with the EbayCategoryViewModel data.
I'm using the MVVM pattern; the EbayCategoryViewModel accept an input ICommand parameter in the Constructor. When I populate the ObservableCollection in the EbayAllCategoriesViewModel, I create a new RelayCommand for each element of the collection and pass the function that should be executed:
hierarchyList.Add(new EbayCategoryViewModel(
item.EbayCategoryName,
item.EbayCategoryID,
FillRecursive(flatList, item.EbayCategoryID, item.EbayCategoryName),
parentCategoryName,
item.EbayOrder,
new RelayCommand(cmd => this.LoadCategoryDetails())
));
My problem now is that in the LoadCategoryDetails() method of the EbayAllCategoriesViewModel I don't have any reference of the EbayCategoryViewModel tree node that has been clicked (the SelectedItem in the TreeView is not public, and also I'm not sure it contains the element being clicked...).
Even if I found some workaround, I would like to understand what is the correct approach to solve my problem, respecting the MVVM pattern. Since I already have all the category fields in the EbayCategoryViewModel, I would be able to access the current EbayCategoryViewModel object being clicked, without accessing again my source of data.
Thanks in advance for any suggestion.
Upvotes: 2
Views: 251
Reputation: 37059
@Nitin's answer is correct, but here's another way that's even simpler:
var ecvm = new EbayCategoryViewModel(
item.EbayCategoryName,
item.EbayCategoryID,
FillRecursive(flatList, item.EbayCategoryID, item.EbayCategoryName),
parentCategoryName,
item.EbayOrder,
null);
// Guessing at the name of your command property here
ecvm.LoadCategoryDetailsCommand
= new RelayCommand(cmd => this.LoadCategoryDetails(ecvm));
hierarchyList.Add(ecvm);
And elsewhere...
public void LoadCategoryDetails(EbayCategoryViewModel vm)
{
// Do stuff
}
I do personally prefer my answer to Nitin's because of the semantics of this particular command: It's telling a category to load its own details. I don't think there's a case where you would tell Category A to tell Category B to load its details, so I don't see a necessity to give the command a parameter. In every case where you're using it, you're in effect saying "Dear category, please load your details, and by the way, this is who you are". The necessity for that redundancy is due to a fairly arbitrary implementation detail in your viewmodel. It's not destructive, but it requires extra effort from the consumer of your classes, without adding anything.
If it were a command on the parent, the semantics would be "tell some particular child to load its details", and then a parameter would be the correct way to tell it which child. And that's the exact semantics of the parent's LoadCategoryDetails(ecvm)
method as Nitin and I both suggested you rewrite it.
Nitin's answer is conventional, high-quality professional WPF programming. It's correct by any standards. But my preference would be to hide the passing of that parameter when the method is called from that command on EbayCategoryViewModel
. It's not really a strong enough preference to justify the amount of prose I've just dumped on it, but I thought I'd explain why I added an unnecessary (lolseewhatididthere?) second answer to this question.
Upvotes: 2
Reputation: 18578
Why don't you pass your EbayCategoryViewModel instance as a parameter in the Command handler. In this way you will have the instance of VM.
hierarchyList.Add(new EbayCategoryViewModel(
item.EbayCategoryName,
item.EbayCategoryID,
FillRecursive(flatList, item.EbayCategoryID, item.EbayCategoryName),
parentCategoryName,
item.EbayOrder,
new RelayCommand(param=> this.LoadCategoryDetails(param))
));
and where you are binding your command you can set the CommandParameter
to return the DataContext i.e. instance of EbayCategoryViewModel CommandParameter="{Binding}"
Upvotes: 2