104

I've set the itemsource of my WPF Datagrid to a List of Objects returned from my DAL. I've also added an extra column which contains a button, the xaml is below.

<toolkit:DataGridTemplateColumn  MinWidth="100" Header="View">
    <toolkit:DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <Button Click="Button_Click">View Details</Button>
        </DataTemplate>
    </toolkit:DataGridTemplateColumn.CellTemplate>
</toolkit:DataGridTemplateColumn>

This renders fine. However on the Button_Click method, is there any way I can get the row on the datagrid where the button resides? More specifically, one of the properties of my objects is "Id", and I'd like to be able to pass this into the constructor of another form in the event handler.

private void Button_Click(object sender, RoutedEventArgs e)
    {
        //I need to know which row this button is on so I can retrieve the "id"  
    }

Perhaps I need something extra in my xaml, or maybe I'm going about this in a roundabout way? Any help/advice appreciated.

BartoszKP
  • 34,786
  • 15
  • 102
  • 130
RekrowYnapmoc
  • 2,166
  • 2
  • 22
  • 23

5 Answers5

136

Basically your button will inherit the datacontext of a row data object. I am calling it as MyObject and hope MyObject.ID is what you wanted.

private void Button_Click(object sender, RoutedEventArgs e)
{
    MyObject obj = ((FrameworkElement)sender).DataContext as MyObject;
    //Do whatever you wanted to do with MyObject.ID
}
Jobi Joy
  • 49,102
  • 20
  • 108
  • 119
  • 8
    The ideal way to do this kind of stuff is using commands (Basically MVVM pattern) you can create a command in your Data Object(ViewModel) and call Button.Command , So that there wont be any code behind like Button click. – Jobi Joy Jul 23 '09 at 16:10
  • 1
    @JobiJoy: do you have an example of this using a Command / RelayCommand? I am trying few things but can't get it to work.. – VoodooChild Nov 27 '11 at 22:04
  • The problem with the command examples I've seen is that you have to databind the datagrid selected item to a member of your view model and thus it's hard to generisize the command enough to be good for a delete button. I want one delete button template column resource I can use to delete pretty much anything in my app. – Eric Sep 18 '14 at 22:36
50

Another way I like to do this is to bind the ID to the CommandParameter property of the button:

<Button Click="Button_Click" CommandParameter="{Binding Path=ID}">View Details</Button>

Then you can access it like so in code:

private void Button_Click(object sender, RoutedEventArgs e)
{
    object ID = ((Button)sender).CommandParameter;
}
xr280xr
  • 12,621
  • 7
  • 81
  • 125
  • Why are you mixing up events and commands? Use a Command and use the command parameter in it. – ProfK Nov 18 '16 at 06:02
  • 1
    3 answers: Why not? Simplicity. And the OP is asking about event handlers, not commands. A command might be overkill. Using `CommandParameter` may not be the property's intended use, but semantically, it's more meaningful than using `Tag` and simpler than retrieving the ID from the bound object in the handler. If you prefer Commands, that approach is fine, but why add the complexity if you're not going to use it? – xr280xr Nov 18 '16 at 06:27
12

Another way which binds to command parameter DataContext and respect MVVM like Jobi Joy says button inherits datacontext form row.

Button in XAML

<RadButton Content="..." Command="{Binding RowActionCommand}" 
                         CommandParameter="{Binding RelativeSource={RelativeSource Mode=Self}, Path=DataContext}"/>

Command implementation

public void Execute(object parameter)
    {
        if (parameter is MyObject)
        {

        }
    }
Petr Šebesta
  • 201
  • 2
  • 5
  • So, would RowActionCommand be in the Model or would you reset the datacontext of the button to the ViewModel? – Tom Padilla May 19 '14 at 15:38
  • @PetrŠebesta "RowActionCommand is defined in each row view model." This doesn't make any sense. But anyway, nice solution. – Igor Jun 10 '15 at 22:01
5
MyObject obj= (MyObject)((Button)e.Source).DataContext;
antyrat
  • 27,479
  • 9
  • 75
  • 76
Shiha
  • 51
  • 1
  • 1
0

If your DataGrid's DataContext is a DataView object (the DefaultView property of a DataTable), then you can also do this:

private void Button_Click(object sender, RoutedEventArgs e) {
   DataRowView row = (DataRowView)((Button)e.Source).DataContext;
}
Keith Davidson
  • 740
  • 7
  • 9