#c# #wpf #xaml #datagrid #default-value
Вопрос:
Мое DataGrid
связано с ObservableCollection
моим в моем ViewModel
.
Я добавляю новые строки с помощью команды, которая выглядит следующим образом:
public void AddItem() {
MyObservableCollection.Add(new MyClass());
}
Как я могу установить значение по умолчанию для a DataGridComboBoxColumn
в моем DataGrid
, когда я создаю новые строки, потому что как есть — он оказывается пустым, что портит мои привязки. Начальное X-количество строк при загрузке имеет значения, но не новые строки, которые добавляет пользователь.
Если бы я мог, например, привязать DefaultValue
его к тому элементу , который находится в индексе 1 ComboBoxColumn
, это было бы здорово.
Возможно ли это?
XAML для сетки данных и столбца DataGridComboBoxColumn выглядит следующим образом:
<DataGrid
AutoGenerateColumns="False"
ItemsSource="{Binding MyObservableCollection}">
<DataGridComboBoxColumn
ItemsSource="{Binding Source={StaticResource MyObservableCollection}}"
SelectedValueBinding="{Binding PropertyName1}"
DisplayMemberPath="PropertyName1"
SelectedValuePath="PropertyName1" />
</DataGrid>
Что я пробовал:
Я попытался установить TargetNullValue
«и FallBackValue
«, просто чтобы появилось значение, потому что это все, что мне нужно. Но это не работает. Я также попытался установить параметр DefaultValue
при создании экземпляра новой строки, но не смог заставить его работать. Что-то подобное добавлено к моему AddItem()
методу:
MyObservableCollection.Add(new MyClass());
DataTable dt = new();
dt.Columns.Add("PropertyName1", typeof(string));
dt.Columns["PropertyName1"].DefaultValue = /* not sure what to put here */ ;
Я попытался добавить туда случайный текст, но он не отображается, значит, что-то не так…
Ответ №1:
Вы должны привязать SelectedItem
ComboBox
или DataGridComboBoxColumn.SelecetedItemBinding
, если быть точным.
Если предположить, что такое SelectedMyClass
свойство будет определено в текущем DataGrid.DataContext
, привязка может выглядеть следующим образом:
<DataGridComboBoxColumn Header="Value"
ItemsSource="{Binding Source={StaticResource MyObservableCollection}}"
DisplayMemberPath="PropertyName1"
SelectedItemBinding="{Binding RelativeSource={RelativeSource AncestorType=DataGrid}, Path=DataContext.SelectedMyClassItem}" />
Но обратите внимание, что это приведет к привязке каждой строки к одному и тому же значению. Скорее всего, это не то, чего вы хотите.
Обычно источником элементов ячейки ComboBox
является коллекция, определенная в самой модели данных — в вашем случае MyClass
. В этом сценарии SelectedItem
свойство (источник привязки ComboBox.SelectedItem
) также будет определено в модели MyClass
данных. Я переименовал MyClass
DataGridItem
, чтобы сделать назначение участвующих моделей более ясным). Это SelectedItem
важно, когда вы хотите отобразить начальное значение в ComboBox
ячейке:
// The item model defines the source collection for the cell's ComboBox
class DataGridItem
{
public ObservableCollection<DataItem> DataItems { get; }
// TODO::Property must raise INotifyPropertyChanged.PropertyChanged
public DataItem SelectedDataItem { get; set; }
public string SomeProperty { get; set; }
}
Просто инициализируйте DataGridItem.SelectedDataItem
, чтобы отобразить начальное значение в ComboBox
ячейке:
public void AddItem()
{
var newDataGridItem = new DataGridItem();
newDataGridItem.SelectedDataItem = newDataGridItem.DataItems.FirstOrDefault();
this.DataGridItems.Add(newDataGridItem);
}
Затем отрегулируйте привязку данных DataGridComboBoxColumn
. Поскольку определение DataGridComboBoxColumn
не является частью визуального дерева DataContext
, оно не является моделью данных текущей строки. Поэтому мы должны настроить привязку с ComboBox.ItemsSource
помощью Style
:
<DataGrid ItemsSource="{Binding DataGridItems}">
<DataGridComboBoxColumn Header="Value"
DisplayMemberPath="SomeProperty"
SelectedItemBinding="{Binding SelectedDataItem}">
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding DataItems}" />
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding DataItems}" />
</Style>
</DataGridComboBoxColumn.ElementStyle>
</DataGridComboBoxColumn>
</DataGrid>
Комментарии:
1. большое вам спасибо за информативный пост. Я работаю над реализацией вашего решения, но — моя наблюдаемая коллекция находится в моей модели просмотра. Как я мог обойти это? Существует автоматическая связь между моим представлением и моделью представления, и я бы предпочел не изменять это.
2. Это не проблема. В моем примере уже предполагается
MyObservableCollection
, что (или элементы DataGridItems) являются коллекцией ObservableCollection, определенной в модели представления. Вы привязываете эту коллекцию к сетке данных, как вы уже сделали в своем первоначальном сообщении. Затем каждая модель элемента в сетке данных. ItemsSource также должен иметь коллекцию и свойство SelectedItem, которые оба привязываются к фактическому столбцу DataGridComboBoxColumn (ячейка) — это вторая часть ответа..3. спасибо за уточнение. Теперь у меня есть Система. Исключение ArgumentNullException: ‘Значение не может быть нулевым. (Параметр «источник») » когда я попытался добавить новую строку. Я трижды проверил и, по-моему, все устроил так, как вы велели. Хммм.. Я получил исключение во 2-й строке в методе AddItem (). Кроме того, при загрузке формы инициализируется X строк, раньше у них была одна строка для каждого экземпляра SomeProperty, но теперь все они имеют один и тот же индекс SomeProperty, и когда я изменяю одну из них, все они меняются.
4. Прежде всего, я показал только минимальную версию кода для отображения шаблона. Вам , конечно, придется инициализировать коллекцию DataItems в конструкторе
DataGridItem
, в противном случае, когда вы ссылаетесь на нее для добавления или получения элементов, коллекция будетnull
.5. Что касается вашей проблемы с sencond:
SomeProperty
является строковым свойствомDataGridItem
. Если вы последуете моему примеру, у вас будет строка для каждогоDataGridItem
экземпляра внутриDataGridItems
коллекции, когдаDataGridItems
коллекция будет привязанаDataGrid.ItemsSource
. Если у вас включена автогенерация столбцов, то каким-то свойством будет столбец. Если вы, как вы сказали, измените значение одной ячейки, и это приведет к изменению значений всех ячеек строки, то вы использовали один и тот же экземпляр для каждой строки. Убедитесь, что вы не добавляете один и тот же экземпляр несколько раз вDataGridItems
коллекцию.