我正在GenericTable
作为GridView
的自定义实现,它将显示已插入的任何对象列表的值。
要在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
时,在此代码之后,grid
为空。
有没有办法初始化此控件位于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)
{
}
}
}
}
答案 0 :(得分:3)
我不确定你想要实现什么,我只知道你所做的事情从根本上是错误的(好吧,就ASP.NET的世界观而言......)。
Session
绝对存放大量与网页相关的数据的错误位置。我将从最后一点开始:如果这是在访问网站之间需要保留的数据,那么必须将其放入数据库中。如果这是仅在某人登录时存在的数据,直到他们注销的时间,那么是,Session
可能是正确的位置。否则,如果它特定于页面并且应该在用户访问另一个页面时被丢弃,那么您应该每次从数据库重新加载它,或者可能将其存储在ViewState
中。
接下来,所有相同类型的对象/它们是否具有相同的字段?如果是这样,那么默认行为(由AutoGenerateColumns
明确控制将为您完成工作,无需额外工作:
<asp:GridView runat="server"
ID="grid"
AutoGenerateColumns="true" />
如果do 不具有相同的列,则它们应位于单独的网格中; GridView
是一种创建HTTP <table>
元素的方法。表元素应该只包含相关的数据;你不会用一张桌子来显示鱼的价格和汽车的颜色。由此可见,如果你有不同的表,有不相关的数据,那么你应该有不同的数据源...一个更简单的解决方案,这意味着你不需要 来实现你的控制'重新尝试实施。
最后,为了完整性,当您定义控件时,您只是创建一个类。如果您希望能够以您尝试的方式实例化控件,那么您需要确保所有数据成员都在构造函数或中实例化,任何引用都由null保护 - 参考检查:
if (grid != null)
{
// Do stuff with grid
}
答案 1 :(得分:1)
尝试使用Static datatable选项并首先更新数据表并将其重新绑定到网格而不会丢失数据。
答案 2 :(得分:1)
我相信您需要实现的目标可以通过创建从网格视图继承的类来实现。这样,您将获得Grid View和其他属性的所有功能,而无需担心自定义控件的实现细节。
如果您仍然认为需要创建自定义控件,请发布自定义控件的代码,以帮助您理解该问题。
如果您因某些原因不希望发布代码,请visit this link我回答了与自定义控件相关的问题。我想你可以在那里找到问题的解决方案。
希望这有帮助。
答案 3 :(得分:1)
我没看到你的gridview“网格”如何连接到你的“子”自定义控件。如果您没有将它们链接在一起,它将没有网格属性?
您可以在自定义控件中的某些内容中执行此操作,但肯定需要完成此操作。
我的逻辑是:你认为定义的东西是空的。你定义了吗?