Pull to refresh

WPF DataGrid. Борьба за Template

Reading time 4 min
Views 17K
Всем привет!

Надеюсь, своей статьей я внесу ясность в вопросе связки XML представления DataGrid с его кодовым собратом. Для этого лучше всего использовать конкретный пример. Итак, нам необходимо разместить список элементов некоторой структуры в таблице. Допустим сами элементы выглядят в коде следующим образом:

class Element
    {
       public Element (string firstName, string lastName, string phoneNumber, DateTime date)
        {
            this.firstName = firstName;
            this.lastName = lastName;
            this.phoneNumber = phoneNumber;
            this.date = date;
         }
       
        public string FirstName { get { return this.firstName; } set { this.firstName = value; } }
        public string LastName { get { return this.lastName; } set { this.lastName = value; } }
        public string PhoneNumber { get { return this.phoneNumber; } set { this.phoneNumber = value; } }
        public DateTime Date { get { return this.date; } set { this.date = value; } }
        
        private string firstName;
        private string lastName;
        private string phoneNumber;
        private DateTime date;
        
    }

Соответственно, их список будет выглядеть как:


List<Element> elements = new List<Element>();

Теперь перейдем к DataGrid. Так как это все таки WPF, то вытянуть его на форму можно и руками. Пусть IDE сама отпишет для него код.

<DataGrid x:Name="dataGrid" Margin="10,103,0,15" 
                  CellEditEnding="dataGrid_CellEditEnding" Grid.RowSpan="2" Grid.ColumnSpan="2" HorizontalAlignment="Left" Width="728"
                  AutoGenerateColumns="False"/>

Здесь вручную я задал только AutoGenerateColumns=«False», так как в дальнейшем мы будем редактировать колонки таблицы сами.

Далее нам необходимо привязать данные к таблице, при этом каждое поле элемента должно соответствовать колонке таблицы.

<DataGrid.Columns>
                <DataGridTextColumn Header="Имя" Binding="{Binding Path=FirstName}"/>
                <DataGridTextColumn Header="Фамилия" Binding="{Binding Path=LastName}"/>
                <DataGridTemplateColumn Header="Телефон" SortMemberPath="PhoneNumber">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBox Text="{Binding Path=PhoneNumber}"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                    <DataGridTemplateColumn.CellEditingTemplate>
                        <DataTemplate>
                            <TextBox Text="{Binding Path=PhoneNumber}" />
                        </DataTemplate>
                    </DataGridTemplateColumn.CellEditingTemplate>
                </DataGridTemplateColumn>
                <DataGridTemplateColumn Header="Дата" SortMemberPath="Date">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate >
                            <TextBlock Text="{Binding Path=Date, StringFormat='dd/MM/yyyy'}"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                    <DataGridTemplateColumn.CellEditingTemplate>
                        <DataTemplate>
                            <DatePicker SelectedDate="{Binding Date}"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellEditingTemplate>
                </DataGridTemplateColumn>
                
            </DataGrid.Columns>

Здесь использовано два вида колонок DataGridTextColumn и DataGridTemplateColumn. Про их виды можно почитать везде. Главное здесь понимать, что с помощью DataGridTemplateColumn можно задать любой шаблон. То есть, в ячейки этой колонки можно будет помещать любые элементы управления (кнопки, календари и т.д.). К примеру в третьей колонке это TextBox:

<DataGridTemplateColumn Header="Телефон" SortMemberPath="PhoneNumber">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBox Text="{Binding Path=PhoneNumber}"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>

ВАЖНО: Не забывайте прописывать Header, потому что автозаполнение у нас отключено. А также для DataGridTemplateColumn необходимо прописать SortMemberPath, чтобы он знал по какому полю сортировать данные.

Перейдем к Binding. Это непосредственно сама привязка к данным. Ее мы указываем с помощью Binding Path=PhoneNumber. Здесь главное учесть то, что это именно название метода класса, который возвращает значение поля (не phoneNumber, а PhoneNumber, см. описание класса).
И еще один момент. Есть возможность ввести разные типы шаблонов (DataTemplate) для ячеек в обычном состоянии (CellTemplate) и в состоянии редактирования (CellEditingTemplate). В четвертой колонке ячейки в обычном состоянии это TextBox, а в состоянии редактирования DatePicker:

<DataGridTemplateColumn Header="Дата" SortMemberPath="Date">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate >
                            <TextBlock Text="{Binding Path=Date, StringFormat='dd/MM/yyyy'}"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                    <DataGridTemplateColumn.CellEditingTemplate>
                        <DataTemplate>
                            <DatePicker SelectedDate="{Binding Date}"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellEditingTemplate>
                </DataGridTemplateColumn>

Также стоит отметить, что при работе с датами у поля Text есть свойство StringFormat, которое можно форматировать. Важно, что для корректного отображения месяца «ММ» должны быть большими.

Теперь, чтобы привязать конкретные данные к таблице вернемся к коду на C#.
После заполнения массива элементами, его надо указать в качестве источника данных:

dataGrid.ItemsSource = elements;

Таким образом любые изменения в elements будут отображаться в таблице и, наоборот, любые сделанные изменения в таблице, приведут к изменениям в elements. Но при внесении изменений в elements необходимо вызывать метод
dataGrid.Items.Refresh();
.
И в качестве еще одного хорошего примера связки С# — XML, приведу пример проверки заполнения ячеек телефонного номера только цифрами. Для этого немного подредактируем кусок кода третьей колонки:

<DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBox Text="{Binding Path=PhoneNumber}" TextChanged="phN_TextChanged"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>

Видно что в теге TextBox я назначил обработчик для события изменения текста. Теперь осталось только прописать этот обработчик в коде:

 private void phN_TextChanged(object sender, TextChangedEventArgs e)
        {
            int result = 0;
            TextBox txtx = sender as TextBox;
            if (txtx !=null)
            {
                if (!int.TryParse(txtx.Text, out result)) {
                    txtx.Text = txtx.Text.Substring(0, txtx.Text.Length - 1);
                    txtx.CaretIndex = txtx.Text.Length;
                }
            }
        }

Проверку на цифры можно сделать и через регулярные выражения.

Всем удачного релиза!
Tags:
Hubs:
If this publication inspired you and you want to support the author, do not hesitate to click on the button
+2
Comments 5
Comments Comments 5

Articles