I tried to display table with list of items from API url by consuming it. And in addition to that i tried to add download and delete column. Which should show download and delete buttons on each row of that table.
Successfully pulled list in table format and displayed in .aspx page. But failed to show download and delete button.
Below is the output i got so far. My target is to get download and delete buttons on each row.
protected async void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BindGridView1();
}
}
private void BindGridView1()
{
string apiUrl = "http://mesappbeta/BE_API_HOME/api/SeriesBlacklist/Req_UploadedDocs?series=AE01400&series_type=RU";
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = client.GetAsync(apiUrl).Result;
if (response.IsSuccessStatusCode)
{
string json = response.Content.ReadAsStringAsync().Result;
Root data = JsonConvert.DeserializeObject<Root>(json);
DataTable dt = new DataTable();
dt.Columns.Add("File Name");
dt.Columns.Add("File Type");
dt.Columns.Add("Uploaded Date");
foreach (var item in data.data)
{
DataRow row = dt.NewRow();
row["File Name"] = item.file_name;
row["File Type"] = item.file_type;
row["Uploaded Date"] = item.created_datetime;
dt.Rows.Add(row);
}
// Add TemplateField for Download button
TemplateField downloadField = new TemplateField();
downloadField.HeaderText = "Download";
downloadField.ItemTemplate = new ButtonTemplate("Download", "<%# DownloadFile(HttpUtility.HtmlEncode(Container.DataItem[\"file_name\"].ToString())) %>");
downloadField.ItemStyle.HorizontalAlign = HorizontalAlign.Center;
GridView2.Columns.Add(downloadField);
// Add TemplateField for Delete button
TemplateField deleteField = new TemplateField();
deleteField.HeaderText = "Delete";
deleteField.ItemTemplate = new ButtonTemplate("Delete", "<%# DeleteFile(HttpUtility.HtmlEncode(Container.DataItem[\"file_name\"].ToString())) %>");
deleteField.ItemStyle.HorizontalAlign = HorizontalAlign.Center;
GridView2.Columns.Add(deleteField);
GridView2.DataSource = dt;
GridView2.DataBind();
}
}
}
protected void GridView2_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "Download")
{
DownloadFile(e.CommandArgument.ToString());
}
else if (e.CommandName == "Delete")
{
DeleteFile(e.CommandArgument.ToString());
}
}
Below code is from class file
public class ButtonTemplate : ITemplate
{
private string _buttonText;
private string _clickMethod;
public ButtonTemplate(string buttonText, string clickMethod)
{
_buttonText = buttonText;
_clickMethod = clickMethod;
}
public void InstantiateIn(Control container)
{
LinkButton btn = new LinkButton();
btn.CommandName = "CustomCommand";
btn.Text = _buttonText;
btn.CommandArgument = _clickMethod;
btn.ID = "lnkButton";
btn.CssClass = "myButtonStyle"; // Add CSS class to the button
container.Controls.Add(btn);
}
below is the code of gridview in aspx file
<asp:GridView ID="GridView2" runat="server" OnRowDeleting="GridView2_RowDeleting" AutoGenerateColumns="true" OnRowCommand="GridView2_RowCommand">
</asp:GridView>
Seems to me there is VERY little valid case for code behind to add the columns.
Since your code behind is hard coding the column names, then why not just add the two buttons to the GV?
You might get the buttons added with your code (but you have to re-inject all the time, not have automatic view state), and worse it will be even MORE difficult to add a click event to those 2 buttons.
So, why not dump all that work, and just add the 2 buttons to the gv markup, and be done with this?
eg this markup:
<asp:GridView ID="GridView1" runat="server"
CssClass="table table-hover"
AutoGenerateColumns="false"
Width="45%">
<Columns>
<asp:BoundField DataField="Date" HeaderText="Date" ItemStyle-Width="100px" />
<asp:BoundField DataField="File Name" HeaderText="File Name" />
<asp:BoundField DataField="FullFile" HeaderText="Full File" />
<asp:BoundField DataField="File Size" HeaderText="Size" ItemStyle-Width="100px" />
<asp:TemplateField HeaderText="Download" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:Button ID="cmdDownLoad" runat="server" Text="DownLoad" CssClass="btn"
OnClick="cmdDownLoad_Click" />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Delete" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:Button ID="cmdDelete" runat="server" Text="Delete" CssClass="btn"
OnClick="cmdDelete_Click" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
You have BOAT loads more flexibility here.
And thus we get + see this:
And big bonues?
Then the click event becomes REALLY easy to pick up the current row.
Say delete button code:
protected void cmdDelete_Click(object sender, EventArgs e)
{
Button cmdDel= (Button)sender;
GridViewRow gRow = (GridViewRow)cmdDel.NamingContainer;
Debug.Print($"Row index = {gRow.RowIndex.ToString()}");
Debug.Print($"File name of this row = {gRow.Cells[1].Text}");
// do whatever to delete here
}
output:
Row index = 3
File name of this row = dd.min.js
So, it not clear at this point that you made a strong case to write all that code when you don't need to write ANY code to add those 2 buttons to the columns.
The other big advantage is you can use say a image button, or even bootstrap icons if you want. (say use a link button) like this:
But, we "enjoy" a plain jane button click event for each row.
So, it not really clear why the goal exists to inject + write code for the buttons and controls you can simple drag + drop into that page.
Well, with that requirement, then we need to persist the data we "feed" to the data table. So, then the "details" of where and how the data for the data table was obtained becomes the issue.
but, to simple "remove" the current row clicked on?
Sure, then I suggest we persist the data table, and if that dt only has say 5-10 rows, then I would consider view state. If it has more rows, then I would perist the data to session().
Lets use session() here then. So, the code to load becomes this:
(it don't matter where the data came from), but only that we persist. IN my example, I using files in a folder list.
So, say this code to load same as before, but RIGHT before we bind the gv, we do this:
Session["MyTable"] = MyTable;
GridView1.DataSource = MyTable;
GridView1.DataBind();
So, now our delete button code then is this:
protected void cmdDelete_Click(object sender, EventArgs e)
{
Button cmdDel= (Button)sender;
GridViewRow gRow = (GridViewRow)cmdDel.NamingContainer;
Debug.Print($"Row index = {gRow.RowIndex.ToString()}");
Debug.Print($"File name of this row = {gRow.Cells[1].Text}");
// do whatever to delete here
// remove row from table
DataTable MyTable = (DataTable)Session["MyTable"];
MyTable.Rows[gRow.RowIndex].Delete();
MyTable.AcceptChanges();
GridView1.DataSource= MyTable;
GridView1.DataBind();
}
So, we simple remove the row from the table, and re-bind the gv.