views:

476

answers:

2

MVVM light has been a pleasure to learn, but here I am stuck. The problem is event firing.

In the code below, one button the works and fires events. The other button doesnt. No binding errors are reported in the output. Is there anything obvious I am missing?

<Grid x:Name="LayoutRoot">...
<StackPanel>
  <Button Content="THIS BUTTON WORKS">
    <i:Interaction.Triggers>
      <i:EventTrigger EventName="Click">
        <Command:EventToCommand Command="{Binding DataContext.HandleAddQuestionActionCommand, ElementName=LayoutRoot, Mode=OneWay}" PassEventArgsToCommand="True"/>
      </i:EventTrigger>
    </i:Interaction.Triggers>
  </Button>
  <sdk1:DataGrid ItemsSource="{Binding QuestionActions}" AutoGenerateColumns="False" >
    <sdk1:DataGrid.Columns>
      <sdk1:DataGridTextColumn Binding="{Binding Answer.Name}" Header="Answer"/>
        <sdk1:DataGridTemplateColumn Header="Edit">
          <sdk1:DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
              <Button Content="THIS BUTTON DONT WORK" >
                <i:Interaction.Triggers>
                  <i:EventTrigger EventName="Click">
                    <Command:EventToCommand Command="{Binding DataContext.HandleEditQuestionActionCommand, ElementName=LayoutRoot, Mode=OneWay}" PassEventArgsToCommand="True"/>
                  </i:EventTrigger>
                </i:Interaction.Triggers>
              </Button>
            </DataTemplate>
          </sdk1:DataGridTemplateColumn.CellTemplate>
        </sdk1:DataGridTemplateColumn>
    </sdk1:DataGrid.Columns>
  </sdk1:DataGrid>
</StackPanel>

ViewModel code:

public RelayCommand<RoutedEventArgs> HandleAddQuestionActionCommand {
    get; private set;
}
public RelayCommand<RoutedEventArgs> HandleEditQuestionActionCommand {
    get; private set;
}


HandleAddQuestionActionCommand = new RelayCommand<RoutedEventArgs>(e =>{...});
HandleEditQuestionActionCommand = new RelayCommand<RoutedEventArgs>(e =>{...});
A: 

The button inside the DataGrid has a DataContext of QuestActions since the Binding is based on the the DataGrid's ItemSource Property. That being the case, you'll need to find the DataContext of the DataGrid itself (or the UserControl or whatever parent that has the Command in it's DataContext) to get to your Command:

<Command:EventToCommand 
Command="{Binding RelativeSource={RelativeSource FindAncestor, 
AncestorType={x:Type sdk1:DataGrid}}, 
Path=DataContext.ViewSchemaCommand, Mode=OneWay}" 
PassEventArgsToCommand="True" />
Metro Smurf
Correct me if I am wrong, but aren't the FindAncestor and AncestorType thingies only available in WPF?
Henrik Söderlund
The theory is correct though, you do need to bind to the DataContext of the parent DataGrid. In this thread is a workaround that you might want to look at:http://forums.silverlight.net/forums/p/163476/367975.aspx
Henrik Söderlund
Really? I didn't realize FindAncestor and AncestorType were WPF-only.
Metro Smurf
Here is the line that has the issue: <Command:EventToCommand Command="{Binding DataContext.HandleEditQuestionActionCommand, ElementName=LayoutRoot, Mode=OneWay}" PassEventArgsToCommand="True"/>Correct me if I am wrong, but isnt the ELEMENTNAME=LayoutRoot, Path=DataContext.....Sufficient to bind the event to the property in the viewmodel without the need for a RelativeSource?
pete_w
@pete - no. See @Matt Casto's answer from a few minutes ago which should help resolve this Silverlight issue.
Metro Smurf
You are right, Matt Casto's solution worked perfectly
pete_w
+1  A: 

Your data context is lost in the DataGrid DataGridTemplateColumn since the DataGrid.Columns isn't a dependency property. Because of this, you can't use element-to-element data binding from within your DataGridTemplateColumn.

However, this is easily fixed thanks to MVVM Light Toolkit's ViewModelLocator.

I don't know what your ViewModel is called, but assuming it is MainViewModel you can change your button binding to this:

<sdk1:DataGridTemplateColumn Header="Edit">
    <sdk1:DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <Button Content="THIS BUTTON WILL WORK NOW ;-)" >
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="Click">
                        <Command:EventToCommand Command="{Binding Source={StaticResource Locator},
                                                                  Path=MainViewModel.HandleEditQuestionActionCommand}"
                                                PassEventArgsToCommand="True" />
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </Button>
        </DataTemplate>
    </sdk1:DataGridTemplateColumn.CellTemplate>
</sdk1:DataGridTemplateColumn>
Matt Casto
That is precisely what I needed! Thank you, and with that, MVVM-light continues to be a simple and elegant approach to silverlight in all scenarios. Thanks again
pete_w