Пользователь
0,0
рейтинг
19 ноября 2008 в 15:42

Разработка → GridView, и с чем его едят (часть вторая, большая)

.NET*
В прошлой вводной части я немного познакомил тех, кто не был знаком, с элементом GridView, предназначенным для отображения табличной информации на форме. Я рассказал о том, что GridView (для своего удобства я буду называть этот элемент далее везде как гридвью) можно связать с источником данных. Источников может быть несколько типов. В моих примерах везде будет в качестве источника использоваться ObjectDataSource.



Итак, как я уже сказал, используем ObjectDataSource. Эта часть будет посвящена именно ему. Ниже мы определим методы, возвращающие данные, добавим штришки, которые в будущем помогут нам при разработке из визуальной среды, а также повторю все действия, но на этот раз уже через codebehind страницы.

Условимся, что для разработки у нас используется VS 2008. Открываем студию, создаем новый проект типа ASP.NET WebSite, язык разработки – C#. Открываем страницу Default.aspx в режиме Split или Design. Бросаем на форму гридвью. Кликаем на стрелочку в правом верхнем углу гридвью, выбираем датасурс – new data source. Тип источника укажем Object. Переходим дальше и видм форму, где нас просят выбрать бизнес объект. image
Так как никаких объектов пока у нас нет, то выбрать мы ничего не сможем. Поэтому приступим к созданию нашего бизнес объекта.

Чтобы в будущем ускорить разработку объектов, создадим абстрактный класс. Этот класс будет содержать как минимум два публичных метода, общих для всех предков нашего класса. Первый – назовём его Select – будет возвращать нам массив объектов, второй – назовем его SelectCount – будет возвращать количество всех элементов, удовлетворяющих запросу. Не забудем пропейджинг, поэтому в качестве обязательных параметров для метода Select укажем два входных параметра: int maximumRows, int startRowIndex. Данные имена по умолчанию используются ObjectDataSource для передачи в метод количество строк для выборки и индекс, с которого начинать выбор. Для метода SelectCount пока никаких параметров не указываем.

[System.ComponentModel.DataObject]
public abstract class BusinessObject<T>
{
    protected T[] _objs;
    private int maximumRows, startRowIndex;

    [System.ComponentModel.DataObjectMethodAttribute
        (System.ComponentModel.DataObjectMethodType.Select, true)]
    public virtual T[] Select(int maximumRows, int startRowIndex)
    {
        this.maximumRows = maximumRows;
        this.startRowIndex = startRowIndex;

        List<T> arr = new List<T>();
        int to = startRowIndex + maximumRows;
        if (to > _objs.Length)
            to = _objs.Length;
        for (int i = startRowIndex; i < to; i++)
        {
            arr.Add(_objs[i]);
        }
        return arr.ToArray();
    }

    public int SelectCount()
    {
        return _objs.Length;
    }
}

* This source code was highlighted with Source Code Highlighter.

Рассотрим класс поподробнее. Что такое после имени класса я объяснять не буду. Незнающие могут погуглить по поводу генериков. Внутри класса объявлена переменная-массив _objs типа Т. По-умолчанию получается, что внутри каждого класса наследника у нас будет переменная, содержащая тип, который мы укажем (посмотрим дальше). Пока не буду объяснять к чему нам атрибуты у заголовка класса и метода Select, скажу лишь, что они на код никак не влияют, и вполне можно обойтись без них.
Метод Select сделаем виртуальным, чтобы иметь возможность переопределить его в классах-наследниках. Метод SelectCount возвращает все количество элементов для метода Select. У себя в проекте я условился, что для каждого селекта, возвращающего массив обектов, существует свой метод, возвращающий количество записей. Название этого метода всегда состоит из имени метода селекта плюс суффикс Count. Т.е. если у нас есть метод SelectById, то для него должен быть метод SelectByIdCount. Внимательные могли бы возразить мне, что для метода SelectById не нужно возвращать количество элементов, ибо этот метод будет всегда возвращать всего один элемент. Поэтому в данном случае мы можем не определять метод SelectByIdCount.

Идём дальше, создадим наш бизнес класс на основе абстрактного класса BusinesObject.

[System.ComponentModel.DataObject]
public class SimpleBusinesObject:BusinessObject<Person>
{
    private int cnt = 0;

    public SimpleBusinesObject()
    {
        List<Person> p = new List<Person>();
        for (int i = 0; i < 24; i++)
        {
            p.Add(new Person("John " + i.ToString(), i, "Lenina str., " + i.ToString()));
        }
        p.Add(new Person("Misha", "123-4567", "Kremlin"));
        _objs = p.ToArray();
    }

    [System.ComponentModel.DataObjectMethodAttribute
        (System.ComponentModel.DataObjectMethodType.Select, false)]
    public Person[] SelectByName(int maximumRows, int startRowIndex, String name)
    {
        List<Person> p = new List<Person>();
        for (int i = 0; i < _objs.Length; i++)
        {
            if (_objs[i].Name.IndexOf(name))
                p.Add(_objs[i]);
        }
        cnt = p.Count;
        return p.GetRange(startRowIndex, maximumRows).ToArray();
    }

    public int SelectByNameCount(String name)
    {
        return cnt;
    }
}


* This source code was highlighted with Source Code Highlighter.


Класс Person:

public class Person
{
    private String _name;
    private String _phone;
    private String _address;

    public String Name
    {
        get { return _name; }
        set { _name = value; }
    }

    public String Phone
    {
        get { return _phone; }
        set { _phone = value; }
    }

    public String Address
    {
        get { return _address; }
        set { _address = value; }
    }

    public Person()
    {
        _name = "No Name";
        _phone = "555-5555";
        _address = "без определенного места жительства";
    }

    public Person(String name, String phone, String address)
    {
        _name = name;
        _phone = phone;
        _address = address;
    }
}

* This source code was highlighted with Source Code Highlighter.

Теперь можно заняться нашей страничкой default.aspx

image.
Как видно на скриншоте, мы можем выбрать наш созданный бизнес объект SimpleBusinessObject. Справа от списка с выбором бизнес объектов стоит галочка Show only data components. Что это такое, зачем оно нужно. Я сейчас объясню. Вспомним, какой атрибут мы указывали у нашего класса: [System.ComponentModel.DataObject]. Этим атрибутом мы помечаем классы, которые у нас используются для доступа к данным. Представьте. Если бы в нашем проекте было определено сотня и больше различных классов, было бы сложновато найти нужный нам объект. А использование этого атрибута вместе с установленной галочкой отфильтровывают только те классы. Которые нам нужны. На следующей форме, после выбора нашего бизнес объекта, нас просят выбрать метод, который будет использоваться для селекта. Здесь снова нам поможет атрибут [System.ComponentModel.DataObjectMethodAttribute (System.ComponentModel.DataObjectMethodType.Select, true)]
Которым мы помечаем наши методы. Возвращающие данные. В конце можно заметить, что у нас стоит true, это говорит о том, что данный метод будет сразу выбран в списке методов. Поэтому имеет смысл выставить для одно из методов true, если он будет использоваться чаще других. Так, для метода Select стоит true, а для метода SelectByName стоит false. Итак выбираем первый метод в списке, идем дальше, видим, что у нас есть список параметров. Здесь пока ничего менять не будем, жмем пимпу, готово. Теперь посмотрим на наш сгенерированный html код:
<asp:GridView ID="GridView1"
runat="server"
AllowPaging="True"
PageSize="10"
     AutoGenerateColumns="False"
DataSourceID="ObjectDataSource1">
     <Columns>
         <asp:BoundField DataField="Name" HeaderText="Name" SortExpression="Name" />
         <asp:BoundField DataField="Phone" HeaderText="Phone" SortExpression="Phone" />
          <asp:BoundField DataField="Address" HeaderText="Address"
                    SortExpression="Address" />
      </Columns>
</asp:GridView>

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
SelectMethod="Select"
     SelectCountMethod="SelectCount"
     EnablePaging="true"
     TypeName="SimpleBusinesObject">
</asp:ObjectDataSource>

* This source code was highlighted with Source Code Highlighter.

Я уже подправил здесь всё, что нужно, организовал пейджинг. Замечу, что если мы хотим пейджинг, который создан нами вручную (выбор идет именно того, что нужно и сколько нужно, без фильтрации необходимых элементов средствами asp.net), то к чёрту выкидываем все параметры из ObjectDataSource (если точнее, то не все, а только два, maximumRows и startRowIndex)! Это очень важное замечание. Ибо тут и бывает куча всяких проблем, вынос мозга и т.п. Еще раз отмечу:

Если пейджинг организован руками:
  • Выкидываем два веселых параметра maximumRows и startRowIndex, оставляя только те, которые задают дополнительную фильтрацию
  • Эти параметры не указываем в методе SelectCount, оставляем только те, которые задают дополнительную фильтрацию
  • Добавляем в GridView атрибуты AllowPaging=true, PageSize=сколько_нужно
  • Добавляем в ObjectDataSource атрибуты SelectCountMethod=имя_метода, EnablePaging=true

Запускаем наш проект и видим, что все прекрасно работает.

Теперь отобразим только список тех персон, корые имеют определеннуюподстроку в имени

<asp:GridView ID="GridView2" runat="server"
            AllowPaging="True"
            PageSize="10"
            AutoGenerateColumns="False"
            DataSourceID="ObjectDataSource2">
            <Columns>
                <asp:BoundField DataField="Name" HeaderText="Name" SortExpression="Name" />
                <asp:BoundField DataField="Phone" HeaderText="Phone" SortExpression="Phone" />
                <asp:BoundField DataField="Address" HeaderText="Address"
                    SortExpression="Address" />
            </Columns>
        </asp:GridView>
        <asp:ObjectDataSource ID="ObjectDataSource2" runat="server"
            SelectMethod="SelectByName"
            SelectCountMethod="SelectByNameCount"
            EnablePaging="true"
            TypeName="SimpleBusinesObject">
            <SelectParameters>
                <asp:QueryStringParameter DefaultValue="John" Name="name"
                    QueryStringField="name" Type="String" />
            </SelectParameters>
        </asp:ObjectDataSource>

* This source code was highlighted with Source Code Highlighter.

Лишнее я уже все убрал, добавил необходимое. Запускаем, ура! Работает. Но заметим, что последнюю страничку мы открыть не можем, ибо «Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection.» Желающие могут исправить сие недоразумение и убедиться, что в конце списка у нас не будет персоны с именем Misha. А теперь можно сходить покурить (если Вы курите, либо попить кофейку), Представить себя мега крутым программистом на asp.net и забить на все 

Итак, мы рассмотрели простой пейджинг, отфильтровали все, что нам нужно. Сейчас лишь могу сделать несколько замечаний. Если вы используете ORM, то, вполне возможно, что Вам придется в методе Select переделать sql запрос таким образом, чтобы БД отдавала необходимую порцию данных. Также для метода SelectCount Вам снова придется переделать sql запрос, чтобы он не возвращал ничего, кроме количества элементов, удовлетворяющих запросу. Таким образом Вы значительно уменьшите объем передаваемых данных между сервером БД и веб сервером.

За сим откланяюсь, а в будущем, возможно, разберем сортировку, вставку новых элементов, удаление и обновление. Но это уже будет намного проще, ибо азы работы с GridView & ObjectDataSource мы уже имеем.

Ну и напоследок приложим созданный проект files.mail.ru/4UKA8Z

P.S. А. ну да. забыл ведь, завтра мы настроим гридвью и датасорс из codebehind.
Павел Старков @Smerig
карма
20,6
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

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

  • –1
    действительно большая. хабракат
    • 0
      угу, как всегда столько работы, что про нег забыл :) Но хабракат я всунул менее. чем через минуту. Думаю только Вам повезло увидеть всё целиком :)
  • +7
    Раз уж мы условились, что "… для разработки у нас используется VS 2008", и скорее всего .net 3x, то класс Person можно существенно сократить.

    Например, заменить:
    private String _name;
    private String _phone;
    private String _address;

    На auto property:
    public String Name {get; set;}
    public String Phone {get; set;}
    public String Address {get; set;}

    Убрать самописные проперти и удалить конструктор с параметрами. В таком случае сущность можно создавать параметрически следующим образом:
    Person p = new Person {Name = «name», Phone=«54555», Address=«spb»}

    Что касается кода, то есть небольшие придирки конечно, но наверняка вы всё это сделали для демонстрации, а не в качестве готового решения.

    Про GridView хочется добавить, что это самый тяжёлый и сложный контрол в asp.net.
    • 0
      Все это, конечно, для меня было познавательно :)
      я делал у себя на .net 2. Как там — не знаю, а за это спасибо.
      А примеры, да, для демонстрации, придумывал на ходу.
      • 0
        Пора бы уже и на .net 3x переезжать) 4й не за горами.
        • 0
          контора такая, еле на второй перетащил :)
    • +1
      если уж .Net 3.x, то вместо GridView лучше использовать ListView — более лёгкий и намного более гибкий в настройке.
    • +2
      Извините за офтоп, но для чего вообще делают такую подмену — скрытое проперти и публичное, которое управляет скрытым — результат то ведь получается тот же. Еще ладно если функция присвоения или чтения должна быть нетривиальная, но в примере ведь не так:
      get { return _phone; }
      set { _phone = value; }
      Просветите пожалуйста.
      • 0
        Ну просто есть стереотип (и весьма правильный) что паблик переменные это очень нехорошо.
        Хотя сделать паблик переменную или переменную с автопроперти по сути одно и то же.
      • 0
        Согласен с предыдущим комментарием, по-хорошему нужно делать точки доступа к приватным переменным класса, даже если всё тривиально, как вы написали. Это правило хорошего тона. В таком случае в будущем легко изменить поведение присвоения и получения значения переменной.
  • 0
    Было бы интересно если бы вы еще внятно углубились в работу DataObjects, использование БД, написание Типизированых датасетов!

    Спасибо за материал!
  • 0
    Насколько я понял, коментят только люди в теме, а жаль, хотелось бы и новичнов услышать :)
  • 0
    мне приходится использовать динамически создаваемые таблицы для показа данных.
    и всё это из-за того, что пользователь хочет видеть одну запись в двух строчках:

    поле1 поле2 поле3
    поле4

    и так по количеству записей.
    возможно ли показывать данные в GridView в таком виде?
    • 0
      А вы расскажите подробнее задачу. Можно в личку.
  • +2
    Я думаю уже поздновато писать про такие контролы. Тем более, как заметили выше, есть намного мощнее ListView, в котором тот же самый пейджинг реализован «правильно».
    • 0
      Ага, контрол появился в первой версии дотнета, а сейчас .NET 3.5 SP1.

      Если бы хотя бы писалось про аяксовый пейджинг, то куда ни шло. А так, совершенно тривиальные вещи.
      • 0
        Во второй ;) В первой был DataGrid.
        • 0
          Да, действительно. Но насколько я помню, он пришел на смену DataGrid и не содержит принципиальных отличий.
      • 0
        как там с пейлдингом, не суть важно. Эта статья больше рассказывает об objectdatasource, и организации пейджинга именно им. Видимо, и с листвью будет то же. А в будущем, дотянутся руки, посмотрим в сторону аякса. Пусть тогда обе пока существующие статьи будут справочной информацией :)
        • 0
          Я привык видеть на Хабре статьи, рассказывающие либо о новых технологиях (в контексте программирования), либо о малоизвестных возможностях старых. Эта и предыдущая статьи не относятся ни к тому, ни к другому.

          В остальном статьи вполне нормально описывают тему и если бы они появились на rsdn или gotdotnet, то у меня никаких вопросов не возникло бы.
          • 0
            я Вас понял :)
            теперь
      • 0
        А где-нибудь можно прочитать про аяксовый пейджинг?
  • 0
    Было бы интересно прочитать больше про ЛИНК в асп.нете
    • 0
      линк в asp.net? Может в C#?
    • НЛО прилетело и опубликовало эту надпись здесь

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.