动态更改GridView项目模板

时间:2009-06-03 11:27:01

标签: asp.net gridview dynamic templates

我有一个相当大的asp.net网站,它使用GridView绑定到很多地方的同一个对象。我正在使用项目模板来自定义每一行。但是要在我必须复制的所有页面中使用相同的模板。将项目模板粘贴到每个页面。显然这不是最好的解决方案。除此之外,我希望能够通过更改某些配置文件来更改GridView使用的模板。 一种选择是使用DataGrid创建用户控件,并公开要在每个页面中使用的必要属性。但是,这不能满足能够动态更改模板的第二个要求。 基本上我正在寻找一种方法来告诉GridView使用模板并能够动态地执行此操作。任何想法都会有所帮助。

2 个答案:

答案 0 :(得分:9)

为了达到你想要的效果,我有两个选择:

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

所以,你有它。自定义模板化控件没有尝试在代码中手动构建它们的所有令人讨厌的头痛。我将在另一个答案中发布完全手动的方式,但是一旦你看到它,我想你会同意这种方法是首选。

答案 1 :(得分:5)

好的,所以这里是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,您必须在您选择添加的任何控件上手动处理该事件。一旦开发了模板,就可以将其用作要使用的任何TemplateField的ItemTemplate。

因此,假设我们有一些我们想要将网格绑定到的自定义业务对象的集合。

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属性或多种类型的控件。你可以这样做,但这会很痛苦,并且可能会让你想要一起退出编程。使用用户控制解决方案,让您的生活更轻松。