views:

501

answers:

2

OK, so the situation is I'm defining an ItemTemplate for a ListBox in a ResourceDictionary (Styles.xaml). The ListBoxItem Template looks something like this:

<ControlTemplate TargetType="ListBoxItem">
    <Button Command="{Binding Path=DoSomeCommand}" Content="Test"  />
</ControlTemplate>

Now wherever this template is used, I'd like to have this button's click bind to an available ViewModel command to handle it.

However this does not work as is, I've also tried this:

<ControlTemplate TargetType="ListBoxItem">
    <Button Command="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DoSomeCommand}" Content="Test"  />
</ControlTemplate>

But still no dice.

A simple example that does work is if you define the template in the control (resources) that is using it, and just use an event handler (the same handler for all generated XAML.

Any ideas or thoughts on the best way to accomplish this? I figure this must be a common scenario: the goal is just to allow the user to interact with the items in the ListBox.

Thanks!

A: 

Long answer: http://stackoverflow.com/questions/1941773/reference-to-a-textbox-inside-a-datatemplate/1945951#1945951

Short answer: Use Prism Commands or Blend Behaviours.

JustinAngel
Thanks Justin, however I think it's pretty clear in my code example above that I am using Commands (actually Commands are now built-in to the Silverlight framework, no need to use Prism attached behaviors anymore).I think the issue is that the DataContext of each ListItem becomes the object from the databound list, not the "page" ViewModel. This is why I was hoping the new TemplatedParent RelativeSource could help..
Bobby
A: 

OK I think I answered my own question :

The solution seems to be to use 'nested' ViewModels here:

In other words, rather than have my ListBox bind directly to a collection of DTOs/business objects (as I was doing above) I instead created a simple ViewModel to wrap each DTO, and have the command on it, rather than on the original, top-level VM.

So the bound collection now looks like this:

    TestItems = new ObservableCollection<ItemVM> ()
    {
        new ItemVM(),
        new ItemVM(),
        new ItemVM()
    };

And each ItemVM just wraps the DTO, and has the command:

public class ItemVM : INotifyPropertyChanged
{
    public ItemVM ()
    {
        this.MyCommand = new DelegateCommand<string> ( TheCommand );
    }

    public ICommand MyCommand { get; private set; } 
    public MyBusinessObject BizObj;
}

And voila, no need for a RelativeSource, and we have a reusable template complete with commands.

Bobby