Botão em uma coluna, obtendo a linha de onde veio no manipulador de eventos Click

97

Eu defini a fonte de itens do meu Datagrid WPF para uma Lista de Objetos retornados do meu DAL. Também adicionei uma coluna extra que contém um botão, o xaml está abaixo.

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

Isso funciona bem. No entanto, no método Button_Click , há alguma maneira de obter a linha no datagrid onde o botão reside? Mais especificamente, uma das propriedades dos meus objetos é "Id" e gostaria de poder passar isso para o construtor de outro formulário no manipulador 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"  
    }

Talvez eu precise de algo extra no meu xaml ou talvez esteja fazendo isso de uma forma indireta? Qualquer ajuda / conselho apreciada.

RekrowYnapmoc
fonte

Respostas:

128

Basicamente, seu botão herdará o texto de dados de um objeto de dados de linha. Estou chamando-o de MyObject e espero que MyObject.ID seja o que você queria.

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
fonte
7
A maneira ideal de fazer esse tipo de coisa é usando comandos (Basicamente padrão MVVM), você pode criar um comando em seu Objeto de Dados (ViewModel) e chamar Button.Command, para que não haja nenhum código por trás como clique de Botão.
Jobi Joy
1
@JobiJoy: você tem um exemplo disso usando um Command / RelayCommand? Estou tentando algumas coisas, mas não consigo fazer funcionar.
VoodooChild
O problema com os exemplos de comando que vi é que você tem que vincular o item selecionado da grade de dados a um membro do seu modelo de visualização e, portanto, é difícil generalizar o comando o suficiente para ser bom para um botão de exclusão. Quero um recurso de coluna de modelo de botão de exclusão que possa usar para excluir praticamente qualquer coisa no meu aplicativo.
Eric,
47

Outra maneira que gosto de fazer é vincular o ID à propriedade CommandParameter do botão:

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

Então você pode acessá-lo assim no código:

private void Button_Click(object sender, RoutedEventArgs e)
{
    object ID = ((Button)sender).CommandParameter;
}
xr280xr
fonte
Por que você está misturando eventos e comandos? Use um comando e use o parâmetro de comando nele.
ProfK
1
3 respostas: Por que não? Simplicidade. E o OP está perguntando sobre manipuladores de eventos, não comandos. Um comando pode ser um exagero. Usar CommandParameterpode não ser o uso pretendido da propriedade, mas semanticamente é mais significativo do que usar Tage mais simples do que recuperar o ID do objeto vinculado no manipulador. Se você prefere comandos, essa abordagem é adequada, mas por que adicionar complexidade se você não vai usá-la?
xr280xr
10

Outra forma que se liga ao parâmetro de comando DataContext e respeita o MVVM, como Jobi Joy diz que o botão herda a linha do formulário do datacontext.

Botão em XAML

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

Implementação de comando

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

        }
    }
Petr Šebesta
fonte
Então, RowActionCommand estaria no modelo ou você redefiniria o texto de dados do botão para o ViewModel?
Tom Padilla
@ PetrŠebesta "RowActionCommand é definido em cada modelo de visualização de linha." Isso não faz sentido. Mas de qualquer maneira, boa solução.
Igor
4
MyObject obj= (MyObject)((Button)e.Source).DataContext;
Shiha
fonte
0

Se o DataContext do seu DataGrid for um objeto DataView (a propriedade DefaultView de uma DataTable), você também pode fazer isso:

private void Button_Click(object sender, RoutedEventArgs e) {
   DataRowView row = (DataRowView)((Button)e.Source).DataContext;
}
SurfingSanta
fonte
Deve ser e.OriginalSource. em vez de e.Source.
Bigeyes de
Sério, Bigeyes, minha resposta é de um código real, ativo e funcional!
SurfingSanta