Динамически изменять шаблон элемента GridView - PullRequest
8 голосов
/ 03 июня 2009

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

Ответы [ 2 ]

9 голосов
/ 03 июня 2009

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

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

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

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

<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);
}

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

5 голосов
/ 03 июня 2009

Хорошо, вот пример 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 или нескольких типов элементов управления. Вы могли бы сделать это, но это было бы болезненно и могло бы заставить вас отказаться от совместного программирования. Используйте решение для управления пользователями и сделайте свою жизнь проще.

...