Bouton dans une colonne, obtenant la ligne d'où il provient sur le gestionnaire d'événements Click

98

J'ai défini la source d'éléments de mon WPF Datagrid sur une liste d'objets renvoyés par mon DAL. J'ai également ajouté une colonne supplémentaire qui contient un bouton, le xaml est ci-dessous.

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

Cela rend bien. Cependant, sur la méthode Button_Click , y a-t-il un moyen d'obtenir la ligne sur la grille de données où réside le bouton? Plus précisément, l'une des propriétés de mes objets est "Id", et j'aimerais pouvoir la transmettre au constructeur d'une autre forme dans le gestionnaire d'événements.

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

Peut-être ai-je besoin de quelque chose de plus dans mon xaml, ou peut-être que je vais faire ça de manière détournée? Toute aide / conseil apprécié.

RekrowYnapmoc
la source

Réponses:

128

Fondamentalement, votre bouton héritera du contexte de données d'un objet de données de ligne. Je l'appelle MyObject et j'espère que MyObject.ID est ce que vous vouliez.

private void Button_Click(object sender, RoutedEventArgs e)
{
    MyObject obj = ((FrameworkElement)sender).DataContext as MyObject;
    //Do whatever you wanted to do with MyObject.ID
}
Joie Jobi
la source
7
Le moyen idéal de faire ce genre de choses est d'utiliser des commandes (essentiellement un modèle MVVM), vous pouvez créer une commande dans votre objet de données (ViewModel) et appeler Button.Command, afin qu'il n'y ait pas de code derrière comme Button click.
Jobi Joy
1
@JobiJoy: en avez-vous un exemple en utilisant un Command / RelayCommand? J'essaie peu de choses mais je n'arrive pas à le faire fonctionner ..
VoodooChild
Le problème avec les exemples de commandes que j'ai vus est que vous devez lier aux données l'élément sélectionné de la grille de données à un membre de votre modèle de vue et qu'il est donc difficile de généraliser la commande suffisamment pour être bonne pour un bouton de suppression. Je veux une ressource de colonne de modèle de bouton de suppression que je puisse utiliser pour supprimer à peu près tout dans mon application.
Eric le
47

Une autre façon de procéder consiste à lier l'ID à la propriété CommandParameter du bouton:

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

Ensuite, vous pouvez y accéder comme ceci dans le code:

private void Button_Click(object sender, RoutedEventArgs e)
{
    object ID = ((Button)sender).CommandParameter;
}
xr280xr
la source
Pourquoi mélangez-vous les événements et les commandes? Utilisez une commande et utilisez le paramètre de commande dedans.
ProfK
1
3 réponses: pourquoi pas? Simplicité. Et l'OP pose des questions sur les gestionnaires d'événements, pas sur les commandes. Une commande peut être excessive. L'utilisation CommandParametern'est peut-être pas l'utilisation prévue de la propriété, mais sémantiquement, elle est plus significative que l'utilisation Taget plus simple que de récupérer l'ID de l'objet lié dans le gestionnaire. Si vous préférez les commandes, cette approche est bonne, mais pourquoi ajouter de la complexité si vous n'allez pas l'utiliser?
xr280xr
10

Une autre manière qui se lie au paramètre de commande DataContext et respecte MVVM comme Jobi Joy dit que le bouton hérite de la ligne du formulaire datacontext.

Bouton en XAML

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

Implémentation de la commande

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

        }
    }
Petr Šebesta
la source
Ainsi, RowActionCommand serait-il dans le modèle ou réinitialiseriez-vous le contexte de données du bouton au ViewModel?
Tom Padilla
@ PetrŠebesta "RowActionCommand est défini dans chaque modèle de vue de ligne." Cela n'a aucun sens. Mais de toute façon, belle solution.
Igor
4
MyObject obj= (MyObject)((Button)e.Source).DataContext;
Shiha
la source
0

Si le DataContext de votre DataGrid est un objet DataView (la propriété DefaultView d'un DataTable), vous pouvez également le faire:

private void Button_Click(object sender, RoutedEventArgs e) {
   DataRowView row = (DataRowView)((Button)e.Source).DataContext;
}
SurfSanta
la source
Ça devrait être e.OriginalSource. au lieu de e.Source.
Bigeyes
Sérieusement Bigeyes, ma réponse vient d'un code réel, en direct et fonctionnel!
SurfingSanta