Очень нужно разобраться с тем как работает ComboBox в таблице DataGrid на WPF. Мне важно чтобы было грамотно разъяснено и правильно реализовано. Изложу суть - Вывести коллекцию в DataGrid : 1. Есть коллекция телефонов (например) ObservableCollection collectionPones; (сразу вопрос - почему нужно использовать эту коллекцию, а не простой List или ArrayList ... ? и как "красиво"[Linq] приводить к такой коллекции уже существующие коллекции?) 2. В этой коллекции есть Param, который нужно выводить в ComboBox, так чтоб изменялась коллекция при изменении параметра в ComboBox, (типа Mode=TwoWay)
<Window x:Class="DataGrid_ComboBox.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DataGrid_ComboBox"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid AutoGenerateColumns="False"
ItemsSource="{Binding Path=collectionPones}">
<!--Не подключает - почему?-->
<DataGrid.Columns>
<DataGridTextColumn Header="id Phone" Binding="{Binding Id}" />
<DataGridTextColumn Header="Name Phone" Binding="{Binding Name}"
/>
<!-- Нужно добавить ComboBox listParams и увязать его с
collectionPones-->
<DataGridTemplateColumn Header="Param">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox/>
<!--Как разобраться с биндингами-->
<!--ItemsSource="{Binding Path=???,
RelativeSource={RelativeSource AncestorType=
{x:Type Window}}}"
IsSynchronizedWithCurrentItem="False"
SelectedItem="{Binding ???, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" />-->
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
using System.Collections.ObjectModel;
using System.Windows;
namespace DataGrid_ComboBox
{
public partial class MainWindow : Window
{
public ObservableCollection<Phone> collectionPones;
public ObservableCollection<Param> listParams;
public class Phone
{
public int Id { get; set; }
public string Name { get; set; }
public Param PhoneParam { get; set; }
}
public class Param
{
public int IdParam { get; set; }
public string NameParam { get; set; }
public bool MyProperty { get; set; }
}
public MainWindow()
{
InitializeComponent();
InitCollection();
}
private void InitCollection()
{
listParams = new ObservableCollection<Param>()
{
new Param() { IdParam = 1, MyProperty=true, NameParam="Sensor" },
new Param() { IdParam = 2, MyProperty=false, NameParam="Capacitive battery" }
};
collectionPones = new ObservableCollection<Phone>()
{
new Phone() { Id=1, Name="IPhone6", PhoneParam = listParams[0] },
new Phone() { Id=2, Name="IPhone7", PhoneParam = listParams[1] }
};
}
}
}
По поводу первого вопроса.
ObservableCollection
хороша тем, что реализует интерфейс INotifyCollectionChanged. Этот интерфейс содержит событие, которое уведомляет внешний код о изменении состава коллекции: добавлении или удалении элемента. Разметка WPF подписывается на это событие, что позволяет ей обновлять внешний вид элементов, если коллекция была изменена из кода (например, был добавлен новый элемент).
Другие коллекции приводятся к ObservableCollection
посредством вызова ее конструктора, т.е. var c = new ObservableCollection<T>(otherCollection)
.
Если рассматривать вашу ситуацию, то коллекция listParams
вполне может быть типа List<T>
, т.к. она задается один раз и не меняется (и, по идее, не должна меняться) в процессе работы программы.
По поводу второго вопроса.
Есть два важных момента, которых не доставало в вашем решении:
Более подробные разъяснения будут даны в комментариях в приведенном коде.
<Grid>
<!-- байндинг отработает, т.к. DataContext задан -->
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Phones}">
<DataGrid.Columns>
<DataGridTextColumn Header="id Phone" Binding="{Binding Id}" Width="auto" />
<DataGridTextColumn Header="Name Phone" Binding="{Binding Name}" Width="*" />
<DataGridTemplateColumn Header="Param" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<!-- Здесь привязка работает к элементу коллекции. У элемента коллекции есть свойство PhoneParam. К нему мы и привязываем выбранный элемент -->
<!-- Однако у элемента коллекции отсутствует перечень всех доступных параметров, зато он есть у контекста данных родительского элемента (окна). -->
<!-- Поэтому мы привязываемся к свойству родительского элемента с типом Window -->
<!-- DisplayMemberPath показывает значение свойства вместо строкового представления самого объекта -->
<!-- Он нужен для того, чтобы выводить понятное пользователю наименование -->
<ComboBox ItemsSource="{Binding Params, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
SelectedItem="{Binding PhoneParam}"
DisplayMemberPath="NameParam"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
.
public partial class MainWindow : Window
{
public ObservableCollection<Phone> Phones { get; private set; }
public ObservableCollection<Param> Params { get; private set; }
public MainWindow()
{
InitializeComponent();
InitCollection();
// задаем DataContext
DataContext = this;
}
...
}
Еще я бы посоветовал почитать про подход MVVM (а заодно и использовать его) и ознакомиться с интерфейсом INotifyPropertyChanged.
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Если папки нет, то создать скрытую не получается, если же папка существует, она скрывается!
Работаю с WinForm C# и возник такой вопрос: можно ли сделать что бы кнопки в программе плавно меняли цвета по порядку как радуга? Просто открываю...
Добавляю данныеДанные добавляются, но изменения не отображаются в DataGridView