简体   繁体   English

动态更改GridView项目模板

[英]Dynamically change GridView item template

I have a fairly big asp.net website that use GridView bound to the same object in lots of places. 我有一个相当大的asp.net网站,使用GridView绑定到很多地方的同一个对象。 I'm using an item template to customize each row. 我正在使用项目模板来自定义每一行。 However to have the same template in all the pages I have to copy & paste the item template to each page. 但是,要在所有页面中使用相同的模板,我必须将项目模板复制并粘贴到每个页面。 Obviously this is not the best solution. 显然这不是最好的解决方案。 On top of this I want to be able to change the template used by the GridView, by changing some configuration file. 除此之外,我希望能够通过更改某些配置文件来更改GridView使用的模板。 One option would be to create an user control with the DataGrid and expose the necessary properties to be used in each page. 一种选择是使用DataGrid创建用户控件,并公开要在每个页面中使用的必要属性。 However this does not fulfill the second requirement to be able do dynamically change the template. 但是,这不能满足能够动态更改模板的第二个要求。 Basically I'm looking for a way to say to the GridView to use a template and be able to do this dynamically. 基本上我正在寻找一种方法来告诉GridView使用模板并能够动态地执行此操作。 Any idea would be helpful. 任何想法都会有所帮助。

In order to accomplish what you want, you have two options as I see it: 为了达到你想要的效果,我有两个选择:

1.) Build each TemplateField dynamically in code, and switch these based on some configuration. 1.)在代码中动态构建每个TemplateField,并根据某些配置切换它们。
2.) Create user controls for your custom grids and use those instead. 2.)为您的自定义网格创建用户控件并使用它们。

I know you said you don't want to use a UserControl because that will take away your ability to dynamically change your layout, but let me challenge that presupposition with an example. 我知道你说你不想使用UserControl,因为这会夺走你动态改变你的布局的能力,但让我用一个例子来挑战这个预设。

You can make use of built-in ASP.Net features in order to dynamically switch out user controls to your liking by using a PlaceHolder Control . 您可以使用内置的ASP.Net功能,以便使用PlaceHolder控件动态切换用户控件。

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

Your custom grids can be built declaratively in .ascx files and then loaded into place dynamically at runtime like so: 您的自定义网格可以在.ascx文件中以声明方式构建,然后在运行时动态加载到位:如下所示:

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

Now, if you really want to make your life easier, then you can create an abstract base class that all your custom grid controls will inherit from. 现在,如果您真的想让自己的生活更轻松,那么您可以创建一个所有自定义网格控件都将继承的抽象基类。 In this way, your controls can be treated generically when loaded. 这样,加载时可以对控件进行一般处理。

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

A simple grid can be defined in markup: 可以在标记中定义一个简单的网格:

<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>

And your code behind for that control would look something like this: 你的控件背后的代码看起来像这样:

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

Now the page or control that utilizes this only has to cast to the base class, and you can use it generically. 现在,使用它的页面或控件只需要转换为基类,你可以使用它一般。 The following is a simple example of how you might use this, but I think it makes the point clearly: 以下是一个如何使用它的简单示例,但我认为它清楚地说明了这一点:

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

So, there you have it. 所以你有它。 Custom templated controls without all the nasty headache of trying to build them all up manually in code. 自定义模板化控件没有尝试在代码中手动构建它们的所有令人讨厌的头痛。 I am going to post the completely manual way of doing this in another answer, but once you see it, I think you will agree that this method is preferred. 我将在另一个答案中发布完全手动的方式,但是一旦你看到它,我想你会同意这种方法是首选。

Alright, so here is the 100% manually building up of templated fields example. 好吧,所以这里是100%手动建立模板化字段的例子。

The first step in creating dynamic template columns is to create a class that implements the System.Web.UI.ITemplate interface. 创建动态模板列的第一步是创建一个实现System.Web.UI.ITemplate接口的类。 For our simple example here, I am just going to use a label. 对于我们这里的简单示例,我将使用标签。

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

Notice that in order to support DataBinding, you will have to manually handle that event on whatever control(s) you choose to add. 请注意,为了支持DataBinding,您必须在您选择添加的任何控件上手动处理该事件。 Once you have developed your template, you can then use this as your ItemTemplate for any TemplateField that you want to use. 一旦开发了模板,就可以将其用作要使用的任何TemplateField的ItemTemplate。

So, suppose that we have some collection of custom business objects that we want to bind our grid to. 因此,假设我们有一些我们想要将网格绑定到的自定义业务对象的集合。

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

We are going to have to manually build up each column as a TemplateField, and then bind our collection to the GridView. 我们将不得不手动将每个列构建为TemplateField,然后将我们的集合绑定到GridView。 In order to make this cleaner and easier to do, I have encapsulated the building up of the TemplateField collection into a static helper class: 为了使这个更干净,更容易,我将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;
    }
}

Using this in your code behind would look something like this: 在后面的代码中使用它看起来像这样:

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

In the end, this will produce an output that is identical to the dynamic user controls example, but as you can see, it is much more cumbersome. 最后,这将生成一个与动态用户控件示例相同的输出,但正如您所看到的,它更加麻烦。 This is also a very simplistic example that doesn't include any CSS attributes, or multiple types of controls. 这也是一个非常简单的示例,不包含任何CSS属性或多种类型的控件。 You could do this, but it would be painful, and might make you want to quit programming all together. 你可以这样做,但这会很痛苦,并且可能会让你想要一起退出编程。 Go with the user control solution and make your life easier. 使用用户控制解决方案,让您的生活更轻松。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM