Silverlight, DataTemplate, Binding to click event

2019-07-27 17:42发布

问题:

Good day,

I'm getting desperate here. Consider the following use case.

I have a listbox which item's are custom templated control. It has several buttons for which this custom control has event handlers in code behind. Whenever button is clicked I call a method of the object my custom control is bound to through the DataContext. So, when user clicks stop, I call _context.stopDownload() and object does the rest.

But, I have one button which should start the playback of the content. I am trying to somehow listen to this button's click event on the core level, not in the code behind of my custom control which represents listbox's item UI.

So, to summarize:

  1. I have a core object which loads list of items into observable collection.
  2. This core object then gets the listbox object using GetTemplateChildnren. When this is done, core sets the ItemsSource of the listbox control to observable collection I get on #1 step. The listbox gets rendered with custom template control as its item's (DataTemplate used).
  3. I need to link event handler on the core object's level to the button element of custom control inside the DataTemplate.

I can't figure out #3. Among other things, I've tried doing something like that after I set the ItemsSource to wire the event handler, but container is always null.

DownloadsListElement.ItemsSource = _downloadsList;

foreach (var item in DownloadsListElement.ItemsSource)
{
    var container = DownloadsListElement.ItemContainerGenerator.ContainerFromItem(item) as     FrameworkElement;
}

I have also tried button a grid over the listbox and trying to get button clicked using VisualTreeHelper on Grid's MouseLeftButtonDown/Up, but those are never invoked when I click on the button.

I'm thinking that only possible solution would be using some kind of commands pattern when I register event handler in some global object and then call it from the custom control inside the DataTemplate.

I'm out of the ideas and hope someone had something similar to this issue.

Thank you.

Update

Thanks to McGamagle and ChrisW I got it working. The final code I have on the button looks like this:

<i:Interaction.Triggers>
    <i:EventTrigger EventName="Click">
        <ei:CallMethodAction TargetObject="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType=local:ListBoxExt}}" MethodName="PlayButton_Click"/>
    </i:EventTrigger>
</i:Interaction.Triggers>

Thank you guys!

回答1:

My understanding is that you want to attach a handler to an item inside a ListBox item's DataTemplate, where the handler belongs to the parent's DataContext.

You can do this using a RelativeSource FindAncestor binding. You might want to consider using an ICommand instead of a handler, but if you do need a handler, then you can use the Blend SDK's CallMethodAction.

The XAML should look something like this (where "SomeCommand" is an ICommand property of the ListBox's data context):

<ListBox>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Button Command="{Binding RelativeSource={RelativeSource AncestorType=ListBox},
                                      Path=DataContext.SomeCommand}" />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Or using the "CallMethodAction" technique (here "HandleButtonClick" must be a public method of the ListBox's data context):

<ListBox>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Button>
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="Click">
                        <ei:CallMethodAction 
                            TargetObject="{Binding RelativeSource={RelativeSource AncestorType=ListBox}, Path=DataContext.SomeCommand}" 
                            MethodName="HandleButtonClick" />
                    </i:EventTrigger EventName="Click">
                </i:Interaction.Triggers>
            </Button>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>