Search code examples
c#wpfc#-4.0datagridwpfdatagrid

How to convert command parameter just before command is executed?


I have a DataGrid in my view and DataGrid has cells with buttons, which have commands assigned. Now I wish to pass current row object (which sits in DataGrid.CurrentItem) to command execution logic.

My initial idea was to use CommandParameter with value converter, where converter would take DataGrid as parameter and extract required information from DataGrid into my own class - in such way I would avoid reference to DataGrid from my view model.

Problem is, that CommandParameter binding/value conversion is executed when grid is shown, meaning that there is no selected item yet.

Can I somehow avoid bringing DataGrid reference into my command execution logic, like deffer CommandParameter resolution until Command is performed or something like that?

Update: I need CurrentItem and CurrentColumn, I've realized, that CurrentItem might be accessible through binding of SelectedItem, so to avoid receiving answers with proposing use SelectedItem property.


Solution

  • So my initial idea was close enough.

    When I was binding CommandParameter to DataGrid, problem was, that when binding was resolving, DataGrid didn't knew yet what is CurrentColumn or CurrentCell or CurrentItem, so it was resolving to empty values.

    So I changed binding to bind to DataGridCell instead - and problem was solved - Cell has ability to tell it's column and item it belongs to at the binding resolution time, so when command was fired, it had all the right data already.

    Style was looking something like this:

    <Button Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}},    
                              Path=DataContext[RowActionFeature].RowActionCommand}"                                                                                                      
            CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGridCell}}, 
                                       Converter={StaticResource DataGridCellToRowActionParametersConverter}}">
    ...
    </Button>
    

    And converter was something like this:

    public class DataGridCellToRowActionParametersConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var dataGridCell = value as DataGridCell;
    
            if (dataGridCell == null)
            {
                return null;
            }
    
            var dataRowView = dataGridCell.DataContext as DataRowView;
            var columnIndex = dataGridCell.Column.DisplayIndex;
    
            return new RowActionParameters
                   {
                       Item = dataGridCell.DataContext,
                       ColumnPropertyName = dataGridCell.Column.SafeAccess(x => x.SortMemberPath),
                       DataRowView = dataRowView,                      
                       ColumnIndex = columnIndex
                   };
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }