asp.net 转发器动态合并列
asp.net repeater merge columns dynamically
我的 ASP.net 页面中有一个转发器。我想合并具有相同文本的列。这应该在我绑定数据表时动态发生。我为此进行了很多搜索。但是,没有成功。我怀疑中继器是否可行。我还想提一下,每行还有图像按钮和复选框。
这是我的转发器来源:-
<asp:Repeater ID="rpt1" runat="server" onitemcommand="rpt1_ItemCommand">
<HeaderTemplate>
<table border="1" cellpadding="10" width="50%">
<tr>
<th>Item Name</th>
<th>As On</th>
<th>Price</th>
<th></th>
<th></th>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<asp:Label ID="lblRelayName" runat="server" Text='<%# Eval("ItemName") %>'></asp:Label>
</td>
<td>
<asp:Label ID="lblTimeFrom" runat="server" Text='<%# Eval("Date") %>'></asp:Label>
</td>
<td>
<asp:Label ID="lblPrice" runat="server" Text='<%# Eval("Price") %>'></asp:Label>
</td>
<td>
<asp:ImageButton ID="imgBtnStatus" runat="server"
ImageUrl="~/img/btnGet.jpg"
CommandName="Change" style="width: 36px; border-width: 0px; margin-top: -4px; vertical-align: middle;" />
</td>
<td>
<asp:CheckBox ID="chkStatus" runat="server" Checked="true" />
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
我是这样填中继器的:-
protected void Page_Load(object sender, EventArgs e)
{
rpt1.DataSource = GetData();
rpt1.DataBind();
}
private DataTable GetData()
{
DataTable dt = new DataTable();
dt.Columns.Add("ItemName");
dt.Columns.Add("Date");
dt.Columns.Add("Price");
DataRow dr = dt.NewRow();
dr["ItemName"] = "Orange";
dr["Date"] = "01/01/2015";
dr["Price"] = "50";
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["ItemName"] = "Orange";
dr["Date"] = "02/01/2015";
dr["Price"] = "51";
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["ItemName"] = "Orange";
dr["Date"] = "03/01/2015";
dr["Price"] = "55";
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["ItemName"] = "Apple";
dr["Date"] = "01/01/2015";
dr["Price"] = "95";
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["ItemName"] = "Apple";
dr["Date"] = "03/01/2015";
dr["Price"] = "98";
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["ItemName"] = "Banana";
dr["Date"] = "01/01/2015";
dr["Price"] = "48";
dt.Rows.Add(dr);
return dt;
}
好的,我让它看起来像这样。我想这就是你想要的:
但我必须对您的代码进行重大更改才能使它正常工作。首先,DataTable 和 DataRow 已经过时 类 ...它们不支持 Linq 等。所以我转而使用普通对象。其次,您将需要在代码隐藏中进行合并。从某种意义上说,它仍然是 "dynamic",您不必更改从服务器返回的原始数据。但是在绑定到 Repeater 控件之前,您将拥有 "process" 数据。这是我最终得到的结果:
.ASPX:
<asp:Repeater ID="rpt1" runat="server">
<HeaderTemplate>
<table border="1" cellpadding="10" width="50%">
<tr>
<th>Item Name</th>
<th>As On</th>
<th>Price</th>
<th></th>
<th></th>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td style='vertical-align: top; display: <%# ((bool) Eval("IsFirstRowWithThisItemName")) ? "" : "none" %>;'
rowspan="<%# Eval("CountOfProductsWithThisItemName") %>">
<asp:Label ID="lblRelayName" runat="server" Text='<%# Eval("ItemName") %>'></asp:Label>
</td>
<td>
<asp:Label ID="lblTimeFrom" runat="server" Text='<%# Eval("ShortDate") %>'></asp:Label>
</td>
<td>
<asp:Label ID="lblPrice" runat="server" Text='<%# Eval("PriceDisplay") %>'></asp:Label>
</td>
<td>
<asp:ImageButton ID="imgBtnStatus" runat="server"
ImageUrl="~/img/btnGet.jpg"
CommandName="Change" Style="width: 36px; border-width: 0px; margin-top: -4px; vertical-align: middle;" />
</td>
<td>
<asp:CheckBox ID="chkStatus" runat="server" Checked="true" />
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
.ASPX.CS
public partial class About : Page
{
protected void Page_Load(object sender, EventArgs e)
{
rpt1.DataSource = this.GetMergedData(this.GetData());
rpt1.DataBind();
}
private List<Product> GetMergedData(List<Product> allProducts)
{
List<Product> mergedProducts = new List<Product>();
var groupingsByName =
allProducts
.GroupBy(product => product.ItemName);
foreach (var groupingByName in groupingsByName)
{
Product firstProduct = groupingByName.First();
firstProduct.CountOfProductsWithThisItemName = groupingByName.Count();
firstProduct.IsFirstRowWithThisItemName = true;
mergedProducts.Add(firstProduct);
mergedProducts.AddRange(groupingByName.Skip(1));
}
return mergedProducts;
}
private List<Product> GetData()
{
return new List<Product>()
{
new Product("Orange", DateTime.Parse("01/01/2015"), 50),
new Product("Orange", DateTime.Parse("02/01/2015"), 51),
new Product("Orange", DateTime.Parse("03/01/2015"), 55),
new Product("Apple", DateTime.Parse("01/01/2015"), 95),
new Product("Apple", DateTime.Parse("03/01/2015"), 98),
new Product("Banana", DateTime.Parse("01/01/2015"), 48),
};
}
}
public class Product
{
public string ItemName { get; set; }
public DateTime Date { get; set; }
public decimal Price { get; set; }
public string ShortDate { get { return this.Date.ToShortDateString(); } }
public string PriceDisplay { get { return this.Price.ToString("C"); } }
public int CountOfProductsWithThisItemName { get; set; }
public bool IsFirstRowWithThisItemName { get; set; }
public Product(string itemName, DateTime date, decimal price)
{
this.ItemName = itemName;
this.Date = date;
this.Price = price;
}
}
我的 ASP.net 页面中有一个转发器。我想合并具有相同文本的列。这应该在我绑定数据表时动态发生。我为此进行了很多搜索。但是,没有成功。我怀疑中继器是否可行。我还想提一下,每行还有图像按钮和复选框。
这是我的转发器来源:-
<asp:Repeater ID="rpt1" runat="server" onitemcommand="rpt1_ItemCommand">
<HeaderTemplate>
<table border="1" cellpadding="10" width="50%">
<tr>
<th>Item Name</th>
<th>As On</th>
<th>Price</th>
<th></th>
<th></th>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<asp:Label ID="lblRelayName" runat="server" Text='<%# Eval("ItemName") %>'></asp:Label>
</td>
<td>
<asp:Label ID="lblTimeFrom" runat="server" Text='<%# Eval("Date") %>'></asp:Label>
</td>
<td>
<asp:Label ID="lblPrice" runat="server" Text='<%# Eval("Price") %>'></asp:Label>
</td>
<td>
<asp:ImageButton ID="imgBtnStatus" runat="server"
ImageUrl="~/img/btnGet.jpg"
CommandName="Change" style="width: 36px; border-width: 0px; margin-top: -4px; vertical-align: middle;" />
</td>
<td>
<asp:CheckBox ID="chkStatus" runat="server" Checked="true" />
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
我是这样填中继器的:-
protected void Page_Load(object sender, EventArgs e)
{
rpt1.DataSource = GetData();
rpt1.DataBind();
}
private DataTable GetData()
{
DataTable dt = new DataTable();
dt.Columns.Add("ItemName");
dt.Columns.Add("Date");
dt.Columns.Add("Price");
DataRow dr = dt.NewRow();
dr["ItemName"] = "Orange";
dr["Date"] = "01/01/2015";
dr["Price"] = "50";
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["ItemName"] = "Orange";
dr["Date"] = "02/01/2015";
dr["Price"] = "51";
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["ItemName"] = "Orange";
dr["Date"] = "03/01/2015";
dr["Price"] = "55";
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["ItemName"] = "Apple";
dr["Date"] = "01/01/2015";
dr["Price"] = "95";
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["ItemName"] = "Apple";
dr["Date"] = "03/01/2015";
dr["Price"] = "98";
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["ItemName"] = "Banana";
dr["Date"] = "01/01/2015";
dr["Price"] = "48";
dt.Rows.Add(dr);
return dt;
}
好的,我让它看起来像这样。我想这就是你想要的:
但我必须对您的代码进行重大更改才能使它正常工作。首先,DataTable 和 DataRow 已经过时 类 ...它们不支持 Linq 等。所以我转而使用普通对象。其次,您将需要在代码隐藏中进行合并。从某种意义上说,它仍然是 "dynamic",您不必更改从服务器返回的原始数据。但是在绑定到 Repeater 控件之前,您将拥有 "process" 数据。这是我最终得到的结果:
.ASPX:
<asp:Repeater ID="rpt1" runat="server">
<HeaderTemplate>
<table border="1" cellpadding="10" width="50%">
<tr>
<th>Item Name</th>
<th>As On</th>
<th>Price</th>
<th></th>
<th></th>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td style='vertical-align: top; display: <%# ((bool) Eval("IsFirstRowWithThisItemName")) ? "" : "none" %>;'
rowspan="<%# Eval("CountOfProductsWithThisItemName") %>">
<asp:Label ID="lblRelayName" runat="server" Text='<%# Eval("ItemName") %>'></asp:Label>
</td>
<td>
<asp:Label ID="lblTimeFrom" runat="server" Text='<%# Eval("ShortDate") %>'></asp:Label>
</td>
<td>
<asp:Label ID="lblPrice" runat="server" Text='<%# Eval("PriceDisplay") %>'></asp:Label>
</td>
<td>
<asp:ImageButton ID="imgBtnStatus" runat="server"
ImageUrl="~/img/btnGet.jpg"
CommandName="Change" Style="width: 36px; border-width: 0px; margin-top: -4px; vertical-align: middle;" />
</td>
<td>
<asp:CheckBox ID="chkStatus" runat="server" Checked="true" />
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
.ASPX.CS
public partial class About : Page
{
protected void Page_Load(object sender, EventArgs e)
{
rpt1.DataSource = this.GetMergedData(this.GetData());
rpt1.DataBind();
}
private List<Product> GetMergedData(List<Product> allProducts)
{
List<Product> mergedProducts = new List<Product>();
var groupingsByName =
allProducts
.GroupBy(product => product.ItemName);
foreach (var groupingByName in groupingsByName)
{
Product firstProduct = groupingByName.First();
firstProduct.CountOfProductsWithThisItemName = groupingByName.Count();
firstProduct.IsFirstRowWithThisItemName = true;
mergedProducts.Add(firstProduct);
mergedProducts.AddRange(groupingByName.Skip(1));
}
return mergedProducts;
}
private List<Product> GetData()
{
return new List<Product>()
{
new Product("Orange", DateTime.Parse("01/01/2015"), 50),
new Product("Orange", DateTime.Parse("02/01/2015"), 51),
new Product("Orange", DateTime.Parse("03/01/2015"), 55),
new Product("Apple", DateTime.Parse("01/01/2015"), 95),
new Product("Apple", DateTime.Parse("03/01/2015"), 98),
new Product("Banana", DateTime.Parse("01/01/2015"), 48),
};
}
}
public class Product
{
public string ItemName { get; set; }
public DateTime Date { get; set; }
public decimal Price { get; set; }
public string ShortDate { get { return this.Date.ToShortDateString(); } }
public string PriceDisplay { get { return this.Price.ToString("C"); } }
public int CountOfProductsWithThisItemName { get; set; }
public bool IsFirstRowWithThisItemName { get; set; }
public Product(string itemName, DateTime date, decimal price)
{
this.ItemName = itemName;
this.Date = date;
this.Price = price;
}
}