I'm developing a WPF application and have created two data-grids as shown in the attached image. The second data-grid is being created dynamically using a CreateCoachCompositionDataGrid() method. There is another method named UpdateCoachCompositionDataGrid() method which is used to update the UI of the data-grid (cells' background colour, combo-box enable/disable, etc.) based on the SelectionChanged event of the dataGridTrainHome (first data-grid).
The issue that I have been facing is that the UI of the data-grid is not being updated when I select a row from the dataGridTrainHome. However, I'm sure that the UpdateCoachCompositionDataGrid() method is being called since the labels (Train Number, Train Name, Platform Number) are being updated.
I'm blocked on what the issue is.
The method that I'm using to create the data-grid:
private void CreateCoachCompositionDataGrid()
{
// Clear the existing columns in the data grid
dataGridCoachComposition.Columns.Clear();
// Set the margin for the data grid
dataGridCoachComposition.Margin = new Thickness(16, 468, 230, 18);
// Hide the column headers
dataGridCoachComposition.HeadersVisibility = DataGridHeadersVisibility.None;
// Set the row height
dataGridCoachComposition.RowHeight = 50; // Set this to your desired row height
// Set the vertical alignment to top to remove empty space at the bottom
dataGridCoachComposition.VerticalAlignment = VerticalAlignment.Top;
// Create 14 columns
for (int i = 1; i <= 14; i++)
{
// Create a new DataGridTemplateColumn
DataGridTemplateColumn column = new DataGridTemplateColumn();
column.Width = new DataGridLength(1, DataGridLengthUnitType.Star); // Set the column width to fill the available space
// Create a DataTemplate for the cell template
DataTemplate cellTemplate = new DataTemplate();
// Create a StackPanel to hold the TextBlock and ComboBox
FrameworkElementFactory stackPanel = new FrameworkElementFactory(typeof(StackPanel));
stackPanel.SetValue(StackPanel.OrientationProperty, Orientation.Vertical);
// Create a TextBlock for the coach number
FrameworkElementFactory textBlock = new FrameworkElementFactory(typeof(TextBlock));
textBlock.SetValue(TextBlock.TextProperty, "C" + i.ToString("00"));
textBlock.SetValue(TextBlock.HorizontalAlignmentProperty, HorizontalAlignment.Center); // Center the text block horizontally
stackPanel.AppendChild(textBlock);
// Create a ComboBox for the coach type
FrameworkElementFactory comboBox = new FrameworkElementFactory(typeof(ComboBox));
comboBox.SetValue(ComboBox.ItemsSourceProperty, new string[] { "ENG", "HIN" });
comboBox.SetValue(FrameworkElement.MarginProperty, new Thickness(5)); // Set a margin around the ComboBox
stackPanel.AppendChild(comboBox);
// Set the cell template's visual tree to the StackPanel
cellTemplate.VisualTree = stackPanel;
// Set the column's cell template
column.CellTemplate = cellTemplate;
// Add the column to the data grid
dataGridCoachComposition.Columns.Add(column);
}
// Add two empty rows to the data grid
dataGridCoachComposition.Items.Add(new object());
dataGridCoachComposition.Items.Add(new object());
}
The method I'm using to update the data-grid:
private void UpdateCoachCompositionDataGrid(DataRow selectedRow)
{
// Get the TrainNumber, TrainName, and PlatformNumber from the selected row
string trainNumber = selectedRow["TrainNumber"].ToString();
string trainName = selectedRow["TrainName"].ToString();
string platformNumber = selectedRow["PlatformNumber"].ToString();
// Display train information in the labels
lblTrainNo.Content = "Train Number: " + trainNumber;
lblTrainName.Content = "Train Name: " + trainName;
lblPlatformNo.Content = "Platform Number: " + platformNumber;
// Get the coach numbers from the database
List<string> coachNumbers = GetCoachNumbersFromDatabase(trainNumber);
// Iterate over each cell in the data grid
for (int i = 0; i < dataGridCoachComposition.Columns.Count; i++)
{
for (int j = 0; j < dataGridCoachComposition.Items.Count; j++)
{
// Get the cell content
var cellContent = dataGridCoachComposition.Columns[i].GetCellContent(dataGridCoachComposition.Items[j]);
// Get the StackPanel in the cell
StackPanel stackPanel = cellContent as StackPanel;
if (stackPanel != null)
{
// Get the ComboBox in the StackPanel
ComboBox comboBox = stackPanel.Children.OfType<ComboBox>().FirstOrDefault();
if (comboBox != null)
{
// Check if the coach number is present
if (coachNumbers.Contains("C" + (i + 1 + j * 14).ToString("00")))
{
// Auto-populate the ComboBox with 'ENG'
comboBox.SelectedIndex = 0;
// Enable the ComboBox
comboBox.IsEnabled = true;
// Set the cell background to white
((DataGridCell)cellContent.Parent).Background = new SolidColorBrush(Colors.White);
}
else
{
// Clear the ComboBox selection
comboBox.SelectedIndex = -1;
// Disable the ComboBox
comboBox.IsEnabled = false;
// Set the cell background to grey
((DataGridCell)cellContent.Parent).Background = new SolidColorBrush(Colors.Gray);
}
}
}
}
}
}
The UpdateCoachCompositionDataGrid() is being called through:
private void dataGridTrainHome_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// Get the currently selected items in the DataGrid
var selectedRows = dataGridTrainHome.SelectedItems;
// If any rows are selected
if (selectedRows != null && selectedRows.Count > 0)
{
// Get the last selected row
DataRowView lastSelectedRow = (DataRowView)selectedRows[selectedRows.Count - 1];
// Use the Dispatcher to delay the call to UpdateCoachCompositionDataGrid
Dispatcher.BeginInvoke(new Action(() =>
{
// Update the coach composition DataGrid
UpdateCoachCompositionDataGrid(lastSelectedRow.Row);
}), DispatcherPriority.Render);
}
}
I tried using dataGridCoachComposition.UpdateLayout() to forcefully update the UI of the data-grid. It did not work.
I also tried creating a DataView from the DataTable and then updating the UI of the data-grid. But, that did not change anything either.
The problem is that:
StackPanel stackPanel = cellContent as StackPanel
is always null cause cellContent returns ContentPresenter
you can easily change the part of the code to look into the visual tree:
var stackPanel =VisualTreeHelper.GetChild(cellContent, 0) as StackPanel;
Zero means that looking for the first child.
It is not the very stable solution cause if you change the StackPanel to other layout the system will break.
I would recommend to use DataTable and later MVVM that easily update state of the grids.
It works for me.