动态更改GridView项目模板

Alb*_*ert 8 asp.net templates gridview dynamic

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

Jos*_*osh 9

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

1.)在代码中动态构建每个TemplateField,并根据某些配置切换它们.
2.)为您的自定义网格创建用户控件并使用它们.

我知道你说你不想使用UserControl,因为这会夺走你动态改变你的布局的能力,但让我用一个例子来挑战这个预设.

您可以使用内置的ASP.Net功能,以便使用PlaceHolder控件动态切换用户控件.

<asp:PlaceHolder ID="GridViewPlaceHolder" runat="server" />
Run Code Online (Sandbox Code Playgroud)

您的自定义网格可以在.ascx文件中以声明方式构建,然后在运行时动态加载到位:如下所示:

GridViewPlaceHolder.Controls.Add(LoadControl("~/Controls/MyCustomControl.ascx"));
Run Code Online (Sandbox Code Playgroud)

现在,如果您真的想让自己的生活更轻松,那么您可以创建一个所有自定义网格控件都将继承的抽象基类.这样,加载时可以对控件进行一般处理.

public abstract class CustomGridControl: System.Web.UI.UserControl
{
    public abstract Object DataSource { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

可以在标记中定义一个简单的网格:

<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>
Run Code Online (Sandbox Code Playgroud)

你的控件背后的代码看起来像这样:

public partial class SimpleGrid : CustomGridControl
{
    public override object DataSource
    {
        get { return myGridView.DataSource; }
        set { myGridView.DataSource = value; }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,使用它的页面或控件只需要转换为基类,你可以使用它一般.以下是一个如何使用它的简单示例,但我认为它清楚地说明了这一点:

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);
}
Run Code Online (Sandbox Code Playgroud)

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


Jos*_*osh 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,为了支持DataBinding,您必须在您选择添加的任何控件上手动处理该事件.一旦开发了模板,就可以将其用作要使用的任何TemplateField的ItemTemplate.

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

public class MyCustomClass
{
    public String Name { get; set; }
    public Int32 Age { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我们将不得不手动将每个列构建为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;
    }
}
Run Code Online (Sandbox Code Playgroud)

在后面的代码中使用它看起来像这样:

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();
}
Run Code Online (Sandbox Code Playgroud)

最后,这将生成一个与动态用户控件示例相同的输出,但正如您所看到的,它更加麻烦.这也是一个非常简单的示例,不包含任何CSS属性或多种类型的控件.你可以这样做,但这会很痛苦,并且可能会让你想要一起退出编程.使用用户控制解决方案,让您的生活更轻松.