Не так давно мне потребовалось использовать таблицу в приложении на C#. По наивности я подумал, что буду использовать всё самое свежее и выбрал для проекта WPF вместо WinForm и, конечно, взял самый свежий .net framework 4.5. Тут-то и начались проблемы. Как всегда, я решил, что в Яндексе найдётся всё, но не тут то было — в интернете (вернее в РУнете) вообще ничего о DataGrid нет. Постоянно, как бы хитро не изменял запросы, я попадал на DataGridView из WinForm. Самое интересное в том, что платформа WPF полностью переработана и многое из того, что работало в WinForm в WPF не работает вообще никак.

Интересно также и то, что WPF должен быть как бы легче в использовании, ведь в Microsoft отделили дизайнеров от программистов, добавили векторную систему визуализации, язык XAML и прочее.

После продолжительного негодования я открыл большую и толстую книгу по WPF. И вот, чудо! Там было всё, как изменить размер, переименовать и перекрасить что угодно и как угодно, но о том, как элементарно достать запись из DataGrid не было и слова.

Отчаявшись, я решил было перейти на WinForm, но вспомнив старую добрую пословицу «если программа не работает, то проблема не в коде, а в программисте», решил разобраться в проблеме и (правда не помню на каком сайте) нашёл решение (это был сайт на английском языке в самых чёрных глубинах интернета). Название сайта вспомнил, ссылка в конце документа.

Привожу пример, как положить и достать информацию из DataGrid в WPF:


Для начала создадим новое приложение и в главном окне разместим элемент DataGrid, назовём его grid.
Далее создадим класс, который будет хранить информацию для таблицы:

    class MyTable
    {
        public MyTable(int Id, string Vocalist, string Album, int Year)
        {
            this.Id = Id;
            this.Vocalist = Vocalist;
            this.Album = Album;
            this.Year = Year;
        }
        public int Id { get; set; }
        public string Vocalist { get; set; }
        public string Album { get; set; }
        public int Year { get; set; }
    }


После этого заполним таблицу с помощью события Loaded:

//Добавим информацию в таблицу
        private void grid_Loaded(object sender, RoutedEventArgs e)
        {
            List<MyTable> result = new List<MyTable>(3);
            result.Add(new MyTable(1, "Майкл Джексон", "Thriller", 1982));
            result.Add(new MyTable(2, "AC/DC", "Back in Black", 1980));
            result.Add(new MyTable(3, "Bee Gees", "Saturday Night Fever", 1977));
            result.Add(new MyTable(4, "Pink Floyd", "The Dark Side of the Moon", 1973));
            grid.ItemsSource = result;
        }


После всего получим информацию о строчке по событию MouseUp (клик мышкой):

        //Получаем данные из таблицы
        private void grid_MouseUp(object sender, MouseButtonEventArgs e)
        {
            MyTable path = grid.SelectedItem as MyTable;
            MessageBox.Show(" ID: " + path.Id + "\n Исполнитель: " + path.Vocalist + "\n Альбом: " + path.Album
                + "\n Год: " + path.Year);
        }


Заключение


Обратите внимание, что обращаться к элементам таблицы в WPF действительно легче, чем в WinForm (напомню, что в WinForm нужно обязательно указывать номер столбца и ячейки), более того, таблица сохраняет исходный тип данных и это очень удобно при их обработке.

Скриншот того, что получилось:



Полный исходный XAML код приложения (одна из вкусняшек WPF, можно посмотреть тип элемнта, его имя и подисанные на него события, а также прочую информацию):
<Window x:Class="DataGrid.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <DataGrid x:Name="grid" HorizontalAlignment="Left" Height="251" Margin="23,23,0,0" VerticalAlignment="Top" Width="455" Loaded="grid_Loaded" MouseUp="grid_MouseUp"/>
    </Grid>
</Window>


Полный исходный код на языке C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace DataGrid
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        
        public MainWindow()
        {
            InitializeComponent();          
        }

        //Загрузка содержимого таблицы
        private void grid_Loaded(object sender, RoutedEventArgs e)
        {
            List<MyTable> result = new List<MyTable>(3);
            result.Add(new MyTable(1, "Майкл Джексон", "Thriller", 1982));
            result.Add(new MyTable(2, "AC/DC", "Back in Black", 1980));
            result.Add(new MyTable(3, "Bee Gees", "Saturday Night Fever", 1977));
            result.Add(new MyTable(4, "Pink Floyd", "The Dark Side of the Moon", 1973));
            grid.ItemsSource = result;
        }

        //Получаем данные из таблицы
        private void grid_MouseUp(object sender, MouseButtonEventArgs e)
        {
            MyTable path = grid.SelectedItem as MyTable;
            MessageBox.Show(" ID: " + path.Id + "\n Исполнитель: " + path.Vocalist + "\n Альбом: " + path.Album
                + "\n Год: " + path.Year);
        }
    }

    class MyTable
    {
        public MyTable(int Id, string Vocalist, string Album, int Year)
        {
            this.Id = Id;
            this.Vocalist = Vocalist;
            this.Album = Album;
            this.Year = Year;
        }
        public int Id { get; set; }
        public string Vocalist { get; set; }
        public string Album { get; set; }
        public int Year { get; set; }
    }

}


Для примера использован Visual Studio 2012 и .net 4.0.

[ Исходный код проекта ]

Сыслка на источник: www.dotnetperls.com/datagrid

P.S. Не знаю, может, я рассказал очевидную для кого-то вещь, однако на это потратил довольно много времени, поэтому и решил поделиться.

Комментарии (24)


  1. NeoNN
    08.11.2015 15:39
    +14

    Хабрамашина времени перенесла нас на 10 лет назад.


    1. NeoNN
      08.11.2015 15:49
      +7

      А если без шуток, то успехов в изучении. Информацию по классам и подходам к программированию лучше всего искать не в яндексе, а в гугле, на msdn и stackoverflow на английском языке. В рамках WPF очень полезно прочитать про MVVM и IoC Containers, если использовать их сразу, то сберегут кучу времени и нервов.

      Сама статья, к сожалению, никакой образовательной ценности не несет.


      1. DimaFromMai
        08.11.2015 16:13

        Да так и написал: «Не знаю, может, я рассказал очевидную для кого-то вещь...»


        1. NeoNN
          08.11.2015 20:55
          +3

          Для тех, для кого она неочевидна, она будет вредна, так как поведет по неправильному пути в изучении WPF.


          1. DimaFromMai
            08.11.2015 22:00
            -3

            Согласен, но если нужно быстро написать приложение, то подобный пример будет предпочтительней прочтения двух-трёх толстых книжек.
            И Яндекс отличный поисковик, не уступающий гуглу (конечно это только моё мнение).


            1. dordzhiev
              08.11.2015 23:34
              +1

              Как всегда, я решил, что в Яндексе найдётся всё, но не тут то было — в интернете (вернее в РУнете) вообще ничего о DataGrid нет.

              Все о DataGrid, без «прочтения двух-трех толстых книжек».


              1. DimaFromMai
                09.11.2015 06:49
                +1

                Вы эту статью читали? Да, там есть информация о том, как поменять размер колонки или как перекрасить строчку, но того о чём написал здесь я, там нет. Действительно, с первого раза не заметил, но кратко свойство SelectedItem упоминается, причём без примера.


                1. HomoLuden
                  09.11.2015 14:37

                  Все правильно написали. Поисковик нужен для выдачи решения для конкретной проблемы в как можно более сжатом виде, а не энциклопедической статьи.


                1. HomoLuden
                  09.11.2015 14:45

                  PS: если собираетесь программно или автоматически менять размеры колонок, то сразу отказывайтесь от DataGrid. он больше любит фиксированные размеры колонок, отсутствие адаптивности под размеры экрана и ручной ресайз юзером.
                  А с авторесайзом и резиновым дизайном сразу убивается производительность старта приложения с DataGrid, т.к. этот контрол на старте делает ресайз несколько раз => UpdateLayout() с DataGrid ужирает процессор по-максимуму.
                  С ListView протребление значительно ниже.


            1. HomoLuden
              09.11.2015 14:35
              +1

              «Искать в гугле» не значит, что яндекс — плохой поисковик. Скорее это вопрос специализации. Для девелоперских нужд выдача гугла релевантнее, субъективное ИМХО.


  1. agranom555
    08.11.2015 15:40

    Эммм. В WPF у всех таблиц и списочных элементов есть свойства SelectedItem или SelectedItems.


  1. michael_vostrikov
    08.11.2015 15:46
    +6

    Как-то быстро у вас заключение появилось, еще даже не началось ничего…

    однако на это потратил довольно много времени
    На приложение уровня «Hello world»? Вы правда считаете, что стоит всем об этом рассказывать?


    1. DimaFromMai
      08.11.2015 16:12
      -3

      Программка, в которой использовал таблицу здесь: Программа, это музыкальный плеер с использованием WCF. А приложение написал попроще, чтобы не перегружать кодом.


  1. AlekseenkoAV
    08.11.2015 20:17
    +3

    А если серьезно, то посмотрите WPF + MVVM, это перевернет ваше мировоззрение на построение GUI. Я не являюсь ярым фанатом того, что делает Microsoft, но это блестящая разработка.


  1. DimaFromMai
    08.11.2015 21:51
    -3

    Сразу надо было написать о том, что статья ни в коем случае не описывает вообще весь WPF, а только показывает прием программирования.
    Да, конечно, я согласен с тем, что необходимо посмотреть WPF + MVVM чтобы во всём разобраться и стать профессионалом, но бывает такое, что нужно срочно сдать работу, например лабу или курсовую или ещё что, так вот для таких случаев бысторо разобраться, что к чему было бы лучше всего. Сам лично я не раз попадал в такие ситуации, когда например не зная толком языка программирования нужно было быстро написать рабочее приложение и в таких случаях я использую подобные примеры, а не пытаюсь за ночь выучить до профессионального уровня язык программирования.


    1. Seekeer
      09.11.2015 08:55
      +2

      «например лабу или курсовую или ещё что, так вот для таких случаев бысторо разобраться, что к чему было бы лучше всего. Сам лично я не раз попадал в такие ситуации, когда например не зная толком языка программирования нужно было быстро написать рабочее приложение»
      Ну если для вас цель лабораторной работы не в том, чтобы по настоящему чему-то научиться, а чтобы её сдать, то да, такой подход подойдёт.
      Да и то — если преподаватель не слишком внимательный.

      «взял самый свежий .net framework 4.5» «использован Visual Studio 2012 и .net 4.0.»
      Во-первых, вы указываете разные версии фреймворка, во-вторых, 4.5 не самая свежая версия, в третьих — зачем пользоваться 12ой студией?


      1. DimaFromMai
        09.11.2015 09:49
        -2

        На момент написания программы (не этого примера) был самый свежий .net 4.5. Использовал .net 4.0 для большей совместимости, а вдруг кто-то использует windows XP, а Visual Studio 2012 просто был под рукой (более того и 13-ая и 15-ая без проблем откроют проект из 12-ой студии).
        Вот не выполните вовремя запрос (например не напишите программу), а с вас возьмут да и стребуют денежный штраф за срыв сроков выполнения работ, будете знать.


        1. DimaFromMai
          09.11.2015 10:16

          С windows XP погорячился, там вроде ничего выше VS 2010 не устанавливается.


        1. NeoNN
          09.11.2015 10:23
          +1

          Навряд ли в мире нормальной разработки с вас потребуют денежный штраф за срыв сроков. Хуже может быть, когда напишете в срок плохую программу, а она на проде не заработает нормально и будет адом в поддержке другими программистами — это в первую очередь скажется на вашей репутации. Если продолжите изучение программирования, .net и WPF, будете со смехом вспоминать эту статью и комментарии к ней.


        1. Daniro_San
          09.11.2015 10:33

          Я как раз использую XP. Спасибо.
          Ваша статья, как и ваш пример, несомненно, пролила свет на все скрытые аспекты и подводные камни WPF.

          то подобный пример будет предпочтительней прочтения двух-трёх толстых книжек.

          Пример великолепен.
          Теперь я могу быдлокодить без, как вы правильно сказали, книжек.
          Еще раз спасибо за столь содержательную статью
          Картинка для вас
          http://cs13.imagefiles.me/p/086191075125228012204046149162246194251016097051012226/1447054334/107634773/0/da9aeb6205f2bfe402d88f18c1c88da2/d0e31a50335c5b70ebddbfc5d0cec505/0/Daniro/asdf-spaces.ru.jpg


  1. Sing
    09.11.2015 11:03

    Ещё, постарайтесь именовать классы и методы соответственно и понятно. Особенно, если кому-то показываете. Название должно быть понятным и отражающим суть того, для чего класс или метод нужен.

    Например, DimaFromMai даёт немало информации о том, кто это и откуда. А вот MyTable ничего не говорит. Более того, это вообще не таблица, а, судя по коду, даже и не класс, а структура. Пользу структур, кстати, тоже изучите.


  1. HomoLuden
    09.11.2015 14:25
    +1

    Очень не рекомендую начинать (да и продолжать на самом деле) со стокового DataGrid в WPF. У него очень тежеловесный дизайн (архитектура и графическое дерево). Если Вам не нужны его встроенные фичи, а в реальных случаях велик шанс, что специфичные сценарии не получится с DataGrid реализовать именно так как UX спец написал, то лучше использовать ListView + GridView.
    Сортировку и Фильтрацию надежнее снаружи реализовывать. При этом тормозов с ListView намного меньше будет.

    Я профилировал перформанс двух одинаковых реализаций части экрана с DataGrid и ListView. Производительность отличается в разы в случае двухуровневых списков (Master и Details).


  1. CrazyViper
    09.11.2015 14:31

    Самое интересное в том, что платформа WPF полностью переработана и многое из того, что работало в WinForm в WPF не работает вообще никак.
    Фраза в корне не корректная. WPF — это не переработанный WinForms. Это отдельная платформа, написанная с нуля. Там совершенно другой механизм рендеринга. Да, классы называются похожими словами, реализованы на том же C# с тем же синтаксисом. Но суть совершенно другая. Именно поэтому у вас в статье кроме слова WPF ничего про WPF нет.

    Ну и выше вам уже рекомендовали почитать про MVVM.


    1. DimaFromMai
      09.11.2015 17:50

      Я и не писал, что WPF — это переработанный WinForm, но спасибо за уточнение.
      DataGrid работает только в WPF, в WinForm работать не будет.

      Согласен с вами и с теми кто выше, обязательно прочитаю про MVVM.