Botón en una columna, obteniendo la fila de la que proviene en el controlador de eventos Click

97

Establecí el origen de elementos de mi WPF Datagrid en una Lista de objetos devueltos desde mi DAL. También agregué una columna adicional que contiene un botón, el xaml está debajo.

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

Esto queda bien. Sin embargo, en el método Button_Click , ¿hay alguna forma de que pueda obtener la fila en la cuadrícula de datos donde reside el botón? Más específicamente, una de las propiedades de mis objetos es "Id", y me gustaría poder pasar esto al constructor de otro formulario en el controlador de eventos.

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

¿Quizás necesito algo extra en mi xaml, o quizás estoy haciendo esto de una manera indirecta? Se agradece cualquier ayuda / consejo.

RekrowYnapmoc
fuente

Respuestas:

128

Básicamente, su botón heredará el contexto de datos de un objeto de datos de fila. Lo llamo MyObject y espero que MyObject.ID sea lo que querías.

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
fuente
7
La forma ideal de hacer este tipo de cosas es utilizando comandos (básicamente patrón MVVM), puede crear un comando en su objeto de datos (ViewModel) y llamar a Button.Command, para que no haya ningún código detrás como el clic de botón.
Jobi Joy
1
@JobiJoy: ¿tiene un ejemplo de esto usando un Command / RelayCommand? Estoy intentando algunas cosas pero no puedo hacer que funcione ..
VoodooChild
El problema con los ejemplos de comandos que he visto es que debe vincular el elemento seleccionado de la cuadrícula de datos a un miembro de su modelo de vista y, por lo tanto, es difícil generar el comando lo suficiente como para ser bueno para un botón de eliminación. Quiero un recurso de columna de plantilla de botón de eliminación que pueda usar para eliminar prácticamente cualquier cosa en mi aplicación.
Eric
47

Otra forma en que me gusta hacer esto es vincular el ID a la propiedad CommandParameter del botón:

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

Entonces puede acceder a él así en el código:

private void Button_Click(object sender, RoutedEventArgs e)
{
    object ID = ((Button)sender).CommandParameter;
}
xr280xr
fuente
¿Por qué está mezclando eventos y comandos? Use un comando y use el parámetro de comando en él.
ProfK
1
3 respuestas: ¿Por qué no? Sencillez. Y el OP pregunta sobre controladores de eventos, no sobre comandos. Un comando puede ser excesivo. El uso CommandParameterpuede no ser el uso previsto de la propiedad, pero semánticamente, es más significativo que usar Tagy más simple que recuperar el ID del objeto vinculado en el controlador. Si prefiere los comandos, ese enfoque está bien, pero ¿por qué agregar la complejidad si no lo va a usar?
xr280xr
10

Otra forma que se une al parámetro de comando DataContext y respeta MVVM como Jobi Joy dice que el botón hereda la fila de formulario de contexto de datos.

Botón en XAML

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

Implementación de comandos

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

        }
    }
Petr Šebesta
fuente
Entonces, ¿RowActionCommand estaría en el modelo o restablecería el contexto de datos del botón en ViewModel?
Tom Padilla
@ PetrŠebesta "RowActionCommand se define en cada modelo de vista de fila". Esto no tiene ningún sentido. Pero de todos modos, buena solución.
Igor
4
MyObject obj= (MyObject)((Button)e.Source).DataContext;
Shiha
fuente
0

Si el DataContext de su DataGrid es un objeto DataView (la propiedad DefaultView de un DataTable), también puede hacer esto:

private void Button_Click(object sender, RoutedEventArgs e) {
   DataRowView row = (DataRowView)((Button)e.Source).DataContext;
}
SurfSanta
fuente
Debería serlo e.OriginalSource. en lugar de e.Source.
Bigeyes
En serio, Bigeyes, ¡mi respuesta es de un código de trabajo real y en vivo!
SurfingSanta