1

I'm trying to retrieve the datagrid because I want to focus on a specific cell in a row. I have a DataGridRow based on the LoadingRow event that I use by doing this:

<i:EventTrigger EventName="LoadingRow">
   <utils:InteractiveCommand Command="{Binding RelativeSource = {RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.MainWindowViewModel.SDataGrid_LoadingRow}"/>
</i:EventTrigger>

But in the function receiving this, I only am able to get the DataGridRow.

    public void SDataGridLoadingRow(object param)
    {
        DataGridRowEventArgs e = param as DataGridRowEventArgs;
        e.Row.Tag = e.Row.GetIndex().ToString();
    }

I want to get a specific cell from the row and focus on it so the user can type. Is this possible?

I'm using MVVM

Also have this now

    public void SDataGridLoadingRow(object sender, DataGridRowEventArgs e)
    {
        e.Row.Tag = e.Row.GetIndex().ToString();

        DataGrid dataGrid = sender as DataGrid;
        dataGrid.Focus();

        // Cancel our focus from the current cell of the datagrid
        // if there is a current cell
        if (dataGrid.CurrentCell != null)
        {
            var cancelEdit = new System.Action(() =>
            {
                dataGrid.CancelEdit();
            });
            Application.Current.Dispatcher.BeginInvoke(cancelEdit,
                System.Windows.Threading.DispatcherPriority.ApplicationIdle, null);
        }

        dataGrid.CurrentCell = new DataGridCellInfo(
            dataGrid.Items[e.Row.GetIndex()], dataGrid.Columns[1]);

        var startEdit = new System.Action(() =>
        {
            dataGrid.BeginEdit();
        });
        Application.Current.Dispatcher.BeginInvoke(startEdit, 
            System.Windows.Threading.DispatcherPriority.ApplicationIdle, null);
    }

And the previous row is still in edit mode... can't quite figure out how to get it out of edit mode...

bobsyauncle
  • 152
  • 8
  • Does this answer your question? [WPF - How to get a cell from a DataGridRow?](https://stackoverflow.com/questions/3671003/wpf-how-to-get-a-cell-from-a-datagridrow) – Keith Stein May 01 '20 at 21:15

1 Answers1

0

I am not sure why your LoadingRow event handler is in your ViewModel. If you are using MVVM your viewModels shouldn't be manipulating visual element such as DataGrid and DataGridCell but only the underlying business data.

In your case you could subscribe to the LoadingRow event like this:

<DataGrid ItemsSource="{Binding BusinessObjectExemples}" LoadingRow="DataGrid_LoadingRow" />

and then in your code behind (xaml.cs file):

private void DataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
    {
        if (sender is DataGrid dataGrid && e.Row is DataGridRow row)
        {
            //You can now access your dataGrid and the row
            row.Tag = row.GetIndex().ToString();
            //The grid is still loading row so it is too early to set the current cell.
        }
    }

What you can do is subscribe to the loaded event of your grid and set the selectedCell there:

private void Grid_Loaded(object sender, RoutedEventArgs e)
    {
        //Adapt the logic for the cell you want to select
        var dataGridCellInfo = new DataGridCellInfo(this.Grid.Items[11], this.Grid.Columns[1]);
        //The grid must be focused in order to be directly editable once a cell is selected
        this.Grid.Focus();
        //Setting the SelectedCell might be neccessary to show the "Selected" visual
        this.Grid.SelectedCells.Clear();
        this.Grid.SelectedCells.Add(dataGridCellInfo);

        this.Grid.CurrentCell = dataGridCellInfo;
    }

You could also execute the same logic with a button.

Xaml:

<DataGrid x:Name="Grid" ItemsSource="{Binding BusinessObjectExemples}" 
                  Loaded="Grid_Loaded" SelectionUnit="Cell" AutoGenerateColumns="False" 
                  LoadingRow="DataGrid_LoadingRow">

And if some of the treatment is related to the business and needs to be in your viewModel. You can then invoke a command or run public methods from DataGrid_LoadingRow in your code behind.

Ostas
  • 839
  • 7
  • 11
  • Hey Ostas, thanks for the answer. I'm using Caliburn Micro. If i put it in the code-behind it would go into ShellView.xaml.cs instead of the MainWindowViewModel.cs class. Would this be ok? – bobsyauncle May 01 '20 at 23:21
  • Also Ostas, I notice, the focus does indeed change, but I have to press "enter" on the keyboard in order to start typing. Do you know why? – bobsyauncle May 01 '20 at 23:24
  • I am not familiar with Caliburn micro but https://caliburnmicro.com/ mention the deccoupling of ViewModel so I don't think it changes to much. I suppose your View is called ShellView.xaml so that would be the right place for this kind of operation. Check https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel if you are not sure what belongs to the viewModel and what belongs to the view . Regarding the fact that you have to press enter, I suppose that you have a TextBox inside your cell and you should put the focus on the TextBox rather than the cell. – Ostas May 01 '20 at 23:37
  • Hi Oslas, thank you. I don't have a textbox inside the cell... I do the following: – bobsyauncle May 02 '20 at 00:13
  • I notice when the loading row function gets triggered for the next row, the previous row's text is still in focus (i solved the focus issue by doing BeginEdit and invoking it with the dispatcher), however I don't understand why the previous row is still in edit mode. I even tried doing currentcell cancelEdit before setting the next row to BeginEdit but the previous row is still editing :\ – bobsyauncle May 02 '20 at 00:20
  • I edited my answer. You shouldn't have to use the dispatcher and have to run beginEdit/ cancelEdit just to set a selection. – Ostas May 02 '20 at 00:59
  • It would be nice to set the answer as accepted answer if it was helpful :) – Ostas May 02 '20 at 12:36