Обновите динамически созданный DataGrid в WPF

Я разрабатываю приложение WPF и создал две сетки данных, как показано на прикрепленном изображении. Вторая сетка данных создается динамически с помощью метода CreateCoachCompositionDataGrid(). Существует еще один метод под названием UpdateCoachCompositionDataGrid(), который используется для обновления пользовательского интерфейса сетки данных (цвет фона ячеек, включение/отключение поля со списком и т. д.) на основе события SelectionChanged dataGridTrainHome (первая сетка данных). ).

Проблема, с которой я столкнулся, заключается в том, что пользовательский интерфейс сетки данных не обновляется, когда я выбираю строку из dataGridTrainHome. Однако я уверен, что метод UpdateCoachCompositionDataGrid() вызывается, поскольку обновляются метки (номер поезда, имя поезда, номер платформы).

Я не понимаю, в чем проблема.

Обновите динамически созданный DataGrid в WPF

Метод, который я использую для создания сетки данных:

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());
}

Метод, который я использую для обновления сетки данных:

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);
                    }
                }
            }
        }
    }
}

UpdateCoachCompositionDataGrid() вызывается через:

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);
    }
}

Я попытался использовать dataGridCoachComposition.UpdateLayout(), чтобы принудительно обновить пользовательский интерфейс сетки данных. Это не работает.

Я также попытался создать DataView из DataTable, а затем обновить пользовательский интерфейс сетки данных. Но это тоже ничего не изменило.

это входит в них, если для тренеров.констианс? или в этом примере каждый раз переходит к оператору else и устанавливает для поля со списком значение false?

Kaspar 13.03.2024 13:34

хорошо, я проверяю ваш код, это потому, что если ( stackPanel != null ) этот stackPanel всегда имеет значение null, потому что вы конвертируете ContentPresenter в StackPanel. Так что ничего не изменится, потому что оно никогда не попадает внутрь, если это утверждение, пожалуйста, дайте мне знать, если это поможет

Kaspar 13.03.2024 13:55

Это выглядит немного странно. Я не думаю, что вам нужно обрабатывать какие-либо элементы пользовательского интерфейса в вашем сценарии. это только усложняет проблему. Почему бы вам не использовать DataTable? Вы можете добавить столбцы метаданных в таблицу и использовать ее, например. скройте ComboBox из шаблона ячейки, определенного в XAML. Это приведет к уменьшению враждебного кода.

BionicCode 13.03.2024 15:27

@Каспар, спасибо за вклад! Я вижу, что моя stackPanel всегда равна нулю, поэтому сетка данных не обновляется. Не могли бы вы рассказать мне, как изменить мой код, чтобы он работал? Я новичок в этом и буду очень признателен за любую помощь, которую смогу получить!

SEIL 13.03.2024 16:42
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
65
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема в том, что: StackPanel stackPanel = cellContent as StackPanel всегда имеет значение null, потому что cellContent возвращает ContentPresenter

вы можете легко изменить часть кода, чтобы просмотреть визуальное дерево:

var stackPanel =VisualTreeHelper.GetChild(cellContent, 0) as StackPanel;

Ноль означает, что ищем первого ребенка.

Это не очень стабильное решение, поскольку если вы измените StackPanel на другой макет, система выйдет из строя.

Я бы рекомендовал использовать DataTable и более поздние версии MVVM, которые легко обновляют состояние сеток.

Меня устраивает.

Другие вопросы по теме