Динамическое изменение шаблона элемента GridView

У меня есть довольно большой веб-сайт asp.net, который использует GridView, связанный с одним и тем же объектом во многих местах. Я использую шаблон элемента для настройки каждой строки. Однако, чтобы иметь один и тот же шаблон на всех страницах, мне нужно скопировать и вставить шаблон элемента на каждую страницу. Очевидно, что это не лучшее решение. Кроме того, я хочу иметь возможность изменить шаблон, используемый GridView, изменив некоторый файл конфигурации. Один из вариантов — создать пользовательский элемент управления с помощью DataGrid и предоставить необходимые свойства для использования на каждой странице. Однако это не соответствует второму требованию для возможности динамического изменения шаблона. В основном я ищу способ сказать GridView, чтобы использовать шаблон и иметь возможность делать это динамически. Любая идея будет полезна.


person Albert    schedule 03.06.2009    source источник
comment
Вы хотите изменить шаблон, потому что у вас другой шаблон дизайна?   -  person Muhammad Akhtar    schedule 03.06.2009
comment
да, я хочу иметь разные шаблоны оформления и иметь возможность их динамически менять   -  person Albert    schedule 03.06.2009


Ответы (2)


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

1.) Динамически создавайте каждое поле TemplateField в коде и переключайте их в зависимости от конфигурации.
2.) Создайте пользовательские элементы управления для своих настраиваемых сеток и используйте их вместо них.

Я знаю, вы сказали, что не хотите использовать UserControl, потому что это лишит вас возможности динамически изменять макет, но позвольте мне опровергнуть это предположение на примере.

Вы можете использовать встроенные функции ASP.Net для динамического переключения пользовательских элементов управления по своему вкусу с помощью элемент управления PlaceHolder.

<asp:PlaceHolder ID="GridViewPlaceHolder" runat="server" />

Ваши пользовательские сетки могут быть созданы декларативно в файлах .ascx, а затем динамически загружены на место во время выполнения следующим образом:

GridViewPlaceHolder.Controls.Add(LoadControl("~/Controls/MyCustomControl.ascx"));

Теперь, если вы действительно хотите облегчить себе жизнь, вы можете создать абстрактный базовый класс, от которого будут наследоваться все ваши настраиваемые элементы управления сеткой. Таким образом, ваши элементы управления могут обрабатываться в общем случае при загрузке.

public abstract class CustomGridControl: System.Web.UI.UserControl
{
    public abstract Object DataSource { get; set; }
}

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

<asp:GridView ID="myGridView" runat="server" AutoGenerateColumns="false">
    <Columns>
        <asp:TemplateField HeaderText="Name">
            <ItemTemplate>
                <asp:Label Text='<%#Eval("Name") %>' runat="server"></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Age">
            <ItemTemplate>
                <asp:Label Text='<%#Eval("Age") %>' runat="server"></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>

И ваш код для этого элемента управления будет выглядеть примерно так:

public partial class SimpleGrid : CustomGridControl
{
    public override object DataSource
    {
        get { return myGridView.DataSource; }
        set { myGridView.DataSource = value; }
    }
}

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

protected void Page_Load(object sender, EventArgs e)
{
    var dataSource = new List<MyCustomClass>
                        {
                            new MyCustomClass{Name = "Josh", Age = 43},
                    new MyCustomClass{Name = "Bob", Age = 14},
                    new MyCustomClass{Name = "Ashley", Age = 32},
                        };

    DynamicallyLoadUserControlGrid("~/GridViewTemplates/SimpleGrid.ascx", dataSource);
}

private void DynamicallyLoadUserControlGrid(String controlLocation, List<MyCustomClass> dataSource)
{
    var ctrl = (CustomGridControl)LoadControl(controlLocation);
    ctrl.DataSource = dataSource;
    ctrl.DataBind();

    GridViewPlaceHolder.Controls.Add(ctrl);
}

Итак, вот оно. Пользовательские шаблонные элементы управления без всякой неприятной головной боли, связанной с попытками создать их все вручную в коде. Я собираюсь опубликовать полностью ручной способ сделать это в другом ответе, но как только вы его увидите, я думаю, вы согласитесь, что этот метод предпочтительнее.

person Josh    schedule 03.06.2009
comment
Танк вам очень нравится, это сработало очень хорошо после того, как я понял суть :) - person Adil Mammadov; 14.08.2012

Итак, вот пример 100% ручного создания шаблонных полей.

Первым шагом в создании столбцов динамического шаблона является создание класса, реализующего интерфейс System.Web.UI.ITemplate. В нашем простом примере я просто буду использовать метку.

public class MyCustomTemplate : ITemplate
{
    public String DataField { get; set; }

    public MyCustomTemplate(String dataField)
    {
        DataField = dataField;
    }

    public void InstantiateIn(Control container)
    {
        var label = new Label();
        label.DataBinding += label_DataBinding;

        container.Controls.Add(label);
    }

    void label_DataBinding(object sender, EventArgs e)
    {
        var label = (Label)sender;
        var context = DataBinder.GetDataItem(label.NamingContainer);
        label.Text = DataBinder.Eval(context, DataField).ToString();
    }
}

Обратите внимание, что для поддержки DataBinding вам придется вручную обрабатывать это событие для любого элемента управления, который вы решите добавить. После того, как вы разработали свой шаблон, вы можете использовать его в качестве ItemTemplate для любого TemplateField, который вы хотите использовать.

Итак, предположим, что у нас есть некоторая коллекция пользовательских бизнес-объектов, к которым мы хотим привязать нашу сетку.

public class MyCustomClass
{
    public String Name { get; set; }
    public Int32 Age { get; set; }
}

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

public static class MyCustomTemplateCollection
{
    public static DataControlFieldCollection GetTemplateCollection()
    {
        var col = new DataControlFieldCollection();

        var nameField = new TemplateField
                        {
                            HeaderText = "Name",
                            ItemTemplate = new MyCustomTemplate("Name")
                        };

        var ageField = new TemplateField
                        {
                            HeaderText = "Age",
                            ItemTemplate = new MyCustomTemplate("Age")
                        };

        col.Add(nameField);
        col.Add(ageField);

        return col;
    }
}

Использование этого в вашем коде будет выглядеть примерно так:

protected void Page_Load(object sender, EventArgs e)
{
    var dataSource = new List<MyCustomClass>
                        {
                            new MyCustomClass{Name = "Josh", Age = 43},
                    new MyCustomClass{Name = "Bob", Age = 14},
                    new MyCustomClass{Name = "Ashley", Age = 32},
                        };

    DynamicGrid(dataSource);
}

private void DynamicGrid(List<MyCustomClass> dataSource)
{
    var col = MyCustomTemplateCollection.GetTemplateCollection();

    foreach (DataControlField field in col)
    {
        myGridView.Columns.Add(field);
    }

    myGridView.DataSource = dataSource;
    myGridView.DataBind();
}

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

person Josh    schedule 03.06.2009