要在aspx页面上使用该控件,它需要是UserControl,因此GridView作为GenericTable中的组件包含在内:
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="GenericTable.ascx.cs" Inherits="CASH.WebApplication.Controls.GenericTable" %> <div style="width: 100%; overflow: scroll"> <asp:GridView ID="grid" runat="server"></asp:GridView> </div>
这适用于我的控件的第一次使用,它已添加到aspx页面.似乎这样做会增加某种启动控制组件的魔力.
当用户单击具有其自身属性的项时,GenericTable应在当前行下方插入一行并生成将显示所述属性的新GenericTable. table是我用来设置GridView内容的DataTable:
var data = table.NewRow(); var child = new GenericTable(); data[0] = child; table.Rows.InsertAt(data,row); grid.DataSource = table; grid.DataBind(); // The extra row is displayed now,initialize components in the aspx code? child.MakeTable(); // Throws exception because it's `grid` property is null.
当我尝试激活新制作的GenericTable时,在此代码之后,它的网格为空.
有没有办法初始化此控件位于aspx代码中时发生的相同魔术?
更新:也许问题在于如何在回发之间存储表,目前我正在使用会话,也许有更好的方法来记住用户输入?
整个GenericTable代码:
using Project.DomainModel.Models; using System; using System.Collections.Generic; using System.Data; using System.IO; using System.Linq; using System.Reflection; using System.Web.UI; using System.Web.UI.WebControls; namespace CASH.WebApplication.Controls { public partial class GenericTable : UserControl { private PropertyInfo[] properties; //private GridView gridView; private DataTable table = new DataTable(); private Dictionary<int,int> ingedrukt = new Dictionary<int,int>(); protected void Page_Init(object sender,EventArgs e) { grid.RowCommand += WeergaveDossiers_RowCommand; } protected void Page_Load(object sender,EventArgs e) { if (!IsPostBack) { for (int i = 0; i < grid.Rows.Count; i++) { grid.Rows[i].Cells[0].ColumnSpan = 0; } } else { properties = (PropertyInfo[])Session["properties"]; table = (DataTable)Session["table"]; ingedrukt = (Dictionary<int,int>)Session["ingedrukt"]; foreach (var knop in ingedrukt) { DetailRijToevoegen(knop.Key,knop.Value); } } grid.DataBind(); } protected void SaveInSession() { Session["properties"] = properties; Session["table"] = table; Session["ingedrukt"] = ingedrukt; } protected void WeergaveDossiers_RowCommand(object sender,GridViewCommandEventArgs e) { int row = int.Parse((string)e.CommandArgument) + 1; int col = GetKolomIndex(e.CommandName) + 1; if (ingedrukt.ContainsKey(row)) { if (ingedrukt[row] != col) { //DetailRijVerwijderen(row); //ingedrukt.Remove(row); //ingedrukt[row] = col; } } else { ingedrukt[row] = col; } //DetailRijToevoegen(row,col); SaveInSession(); } protected void DetailRijToevoegen(int row,int col) { var data = table.NewRow(); var child = new GenericTable(); child.grid = new GridView(); data[0] = child; table.Rows.InsertAt(data,row); grid.DataSource = table; grid.DataBind(); var cells = grid.Rows[row].Cells; // Only keep the first cell while (cells.Count > 1) { cells.RemoveAt(1); } child.MaakTable(new List<object>() { table.Rows[row][col] }); grid.Columns[0].Visible = true; grid.Rows[row].Cells[0].ColumnSpan = table.Columns.Count; } protected void DetailRijVerwijderen(int row) { } protected int GetKolomIndex(string naam) { for (int i = 0; i < properties.Length; i++) { if (properties[i].Name == naam) { return i; } } throw new InvalidDataException("Kolom naam " + naam + " niet bekend"); } public void MaakTable(IEnumerable<object> data) { properties = data.First().GetType().GetProperties().Where(p => p.CanRead).ToArray(); grid.AutoGenerateColumns = false; var details = new BoundField(); details.DataField = "Details"; grid.Columns.Add(details); table.Columns.Add(new DataColumn("Details",typeof(object))); foreach (var veld in properties) { table.Columns.Add(new DataColumn(veld.Name,(veld.Name == "Id" ? typeof(object) : veld.PropertyType))); grid.Columns.Add(MaakKolom(veld)); } foreach (var entry in data) { var row = table.NewRow(); int col = 0; foreach (var veld in properties) { row[++col] = veld.GetValue(entry); } table.Rows.Add(row); } grid.DataSource = table; SaveInSession(); } protected DataControlField MaakKolom(PropertyInfo veld) { DataControlField field; if (typeof(Entity).IsAssignableFrom(veld.PropertyType)) { field = new ButtonField(); ((ButtonField)field).DataTextField = veld.Name; ((ButtonField)field).ButtonType = ButtonType.Button; ((ButtonField)field).CommandName = veld.Name; } else if (veld.PropertyType == typeof(bool)) { field = new CheckBoxField(); ((CheckBoxField)field).DataField = veld.Name; } else if (veld.PropertyType.IsEnum) { field = new TemplateField(); //((TemplateField)field).ItemTemplate = (ITemplate)new Label() //{ // Text = "#DataBinder.Eval(\"" + veld.Name + "\")",//}; } else if (veld.PropertyType == typeof(DateTime)) { field = new TemplateField(); //field.DatePicker = true; } else { field = new BoundField(); ((BoundField)field).DataField = veld.Name; } field.HeaderText = veld.Name; return field; } protected void OnRowDataBound(object sender,GridViewRowEventArgs e) { if (e.Row.RowType == DataControlRowType.DataRow) { } } } }
解决方法
>您将控件添加到输入数据,而不是将其添加为网格的子控件.
>您没有在控件的consructor中实例化GridView控件.
> Session绝对是存储大量页面相关数据的错误位置.
我将从最后一点开始:如果这是在访问站点之间需要持续存在的数据,那么您必须将其放入数据库中.如果这是仅在某人登录时存在的数据,直到他们注销的时间,那么是,会话可能是适合它的地方.否则,如果它特定于页面并且应该在用户访问另一个页面时被丢弃,那么您应该每次从数据库重新加载它或者可以将它存储在ViewState中.
接下来,是相同类型的所有对象/它们是否具有相同的字段?如果是这样,那么默认行为(由AutoGenerateColumns显式控制将为您完成工作,无需额外的工作:
<asp:GridView runat="server" ID="grid" AutoGenerateColumns="true" />
如果没有相同的列,那么它们应该是单独的网格; GridView是一种创建HTTP< table>的方法.元件.表元素应该只包含相关数据;你不会用一张桌子来显示鱼的价格和汽车的颜色.由此得出,如果你有不同的表,有不相关的数据,那么你应该有不同的数据源…一个更简单的解决方案,这意味着你不需要实现你试图实现的控件.
最后,为了完整性,当您定义控件时,您只是创建一个类.如果您希望能够以您尝试的方式实例化控件,那么您需要确保其所有数据成员都在构造函数中实例化,或者任何引用都由空引用检查保护:
if (grid != null) { // Do stuff with grid }