Как исправить отсутствующее отображение строк в DataGrid, когда столбцы генерируются динамически? - PullRequest
1 голос
/ 27 марта 2019

В моем текущем приложении WPF требуется динамически генерировать столбцы DataGrid в моей ViewModel. Для этого я использовал подход с System.Windows.Interactivity и поведением. Поэтому я создал ColumnsBehavior точно так же, как в этом посте:

Можно ли получить динамические столбцы на сетке данных wpf в шаблоне mvvm?

Все работало нормально, когда я инициализировал ограниченный список и генерировал столбцы с привязками. Когда я переключился на ListBox для отображения DataGrid в каждом ListBoxItem, все снова работало отлично. Теперь я хочу добавить информацию (модель) в ограниченный список во время выполнения. Когда выбран ListBoxItem, должна отображаться соответствующая DataGrid. С помощью кнопки над DataGrid я могу передавать образцы данных в объекты ограниченного списка. Когда я нажимаю кнопку, генерируется нужное количество столбцов с правильными заголовками, но строки появляются только в следующий раз, когда ListBoxItem снова становится видимым. Это означает, что данные появляются, как только я обновляю сетку.

Чтобы связать свойство Botton Command с ViewModel, я использовал реализацию ActionCommand:

RelayCommand

Я использую шаблон MVVM.

Это мой ViewModel :

    public class ViewModel
    {
        public ViewModel()
        {
            ListItems = new ObservableCollection<ListItemModel>();
            ListItems.Add(new ListItemModel()
            {
                IsSelected = true
            });
            ListItems.Add(new ListItemModel()
            {
                IsSelected = false
            });

            FillCommand = new RelayCommand(FillAction);
        }

        public ObservableCollection<ListItemModel> ListItems { get; set; }

        public ListItemModel SelectedListItem { get; set; }

        public ICommand FillCommand { get; set; }

        public void FillAction(object sender)
        {
            SelectedListItem.Entries = new ObservableCollection<Entry>()
            {
                new Entry()
                {
                    Cells = new ObservableCollection<Cell>()
                    {
                        new Cell() { Cond1 = 11, Value = 99 },
                        new Cell() { Cond1 = 22, Value = 99 },
                        new Cell() { Cond1 = 33, Value = 99 }
                    }
                },
                new Entry()
                {
                    Cells = new ObservableCollection<Cell>()
                    {
                        new Cell() { Cond1 = 11, Value = 99 },
                        new Cell() { Cond1 = 22, Value = 99 },
                        new Cell() { Cond1 = 33, Value = 99 }
                    },
                },
                new Entry()
                {
                    Cells = new ObservableCollection<Cell>()
                    {
                        new Cell() { Cond1 = 11, Value = 99 },
                        new Cell() { Cond1 = 22, Value = 99 },
                        new Cell() { Cond1 = 33, Value = 99 }
                    },
                }
            };

            SelectedListItem.GenerateGrid();
        }
    }

Свойство для хранения столбцов находится в ListItemModel. Структуру объекта позади ItemsSource DataGrid и свойства столбцов вы можете увидеть в следующем коде:

public class ListItemModel
    {
        public ListItemModel()
        {
            Entries = new ObservableCollection<Entry>();
            DataColumns = new ObservableCollection<DataGridColumn>();
        }

        public ObservableCollection<Entry> Entries { get; set; }

        public ObservableCollection<DataGridColumn> DataColumns { get; set; }

        public bool IsSelected { get; set; }

        public void GenerateGrid()
        {
            if (Entries.Count != 0)
            {
                var columns = Entries[0]?.Cells;

                for (int i = 0; i < columns.Count; i++)
                {
                    Binding b = new Binding(string.Format("Cells[{0}].Value", i));
                    DataGridTextColumn text = new DataGridTextColumn();
                    text.Header = columns[i].Cond1.ToString();
                    text.Binding = b;
                    DataColumns.Add(text);
                }
            }
        }
    }

    public class Entry
    {
        public ObservableCollection<Cell> Cells { get; set; }

        public Entry() { Cells = new ObservableCollection<Cell>(); }
    }

    public class Cell
    {
        public Cell() { }

        public int Cond1 { get; set; }

        public int Value { get; set; }
    }
}

Для просмотра вам нужно пространство имен:

http://schemas.microsoft.com/expression/2010/interactivity

Следующий пример кода показывает представление.

<Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"></ColumnDefinition>
            <ColumnDefinition Width="*"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <ListBox ItemsSource="{Binding ListItems}" SelectedItem="{Binding SelectedListItem}">
            <ListBox.Resources>
                <Style TargetType="{x:Type ListBoxItem}">
                    <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
                </Style>
            </ListBox.Resources>
        </ListBox>
        <DockPanel Grid.Column="1">
            <Button DockPanel.Dock="Top" Command="{Binding FillCommand}">Fill Data</Button>
            <DataGrid x:Name="ToleranceGrid" ColumnWidth="*" ItemsSource="{Binding Path=SelectedListItem.Entries}"
                      CanUserAddRows="False" SelectionMode="Single" SelectionUnit="Cell" AutoGenerateColumns="False" local:ColumnsBindingBehaviour.BindableColumns="{Binding Path=SelectedListItem.DataColumns}">
            </DataGrid>
        </DockPanel>
    </Grid>

Для ViewModel установлено значение DataContext представления в коде позади.

Результат должен выглядеть следующим образом: Приложение WPF

Выбран первый ListItemModel, и я нажал кнопку над сеткой данных. Как видите, столбцы были сгенерированы, но строки не отображаются. Я отладил код, все правильно установлено в моей ViewModel. Когда я выберу вторую ListItemModel и вернусь к первой, содержимое будет отображаться правильно.

У вас есть идеи?

1 Ответ

0 голосов
/ 28 марта 2019

Ваш ListItemModel должен реализовать интерфейс INotifyPropertyChanged и вызвать событие PropertyChanged, когда свойство Entries установлено в новую коллекцию:

public class ListItemModel : INotifyPropertyChanged
{
    public ListItemModel()
    {
        Entries = new ObservableCollection<Entry>();
        DataColumns = new ObservableCollection<DataGridColumn>();
    }

    private ObservableCollection<Entry> _entries;
    public ObservableCollection<Entry> Entries
    {
        get { return _entries; }
        set { _entries = value; NotifyPropertyChanged(); }
    }

    public ObservableCollection<DataGridColumn> DataColumns { get; set; }

    public bool IsSelected { get; set; }

    public void GenerateGrid()
    {
        if (Entries.Count != 0)
        {
            var columns = Entries[0]?.Cells;

            for (int i = 0; i < columns.Count; i++)
            {
                Binding b = new Binding(string.Format("Cells[{0}].Value", i));
                DataGridTextColumn text = new DataGridTextColumn();
                text.Header = columns[i].Cond1.ToString();
                text.Binding = b;
                DataColumns.Add(text);
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...