В моем текущем приложении 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 и вернусь к первой, содержимое будет отображаться правильно.
У вас есть идеи?