I insert three template columns in my gridview. In every column I insert a user control. For example in first column there is a user control containing an image and three labels.
In my page load, I need to get list of images in a folder and create a row for each of them. Then I need to update those user controls' images in gridview columns.
Here is the sample code which gets the list of images and will be the data source of GridView:
string[] filePaths = Directory.GetFiles(Server.MapPath("~/Resources/Pictures"));
GridView1.DataSource = filePaths;
GridView1.DataBind();
In this step I can see 4 rows which have filled with RAW user controls (Empty images in image control,default text for labels etc.) Now I need to update each of them with my own properties.
Here is a picture Of my output:
As you can see in first column there are some controls (Image and Labels) which is for user control that I used them in column template of my gridview. But they are RAW and I need to update them. For example I need to update the image with the link you see in the third column.
and Here is a part of my GridView Code:
<asp:GridView ID="GridView1" runat="server" BackColor="LightGoldenrodYellow" BorderColor="Tan" BorderWidth="1px" Caption="Image List" CellPadding="2" ForeColor="Black" GridLines="None" Height="222px" Width="409px">
<AlternatingRowStyle BackColor="PaleGoldenrod" />
<Columns>
<asp:TemplateField HeaderText="Old Picture">
<ItemTemplate>
<uc1:ImageColumn ID="ImageColumn1" runat="server" />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="New Picture">
<ItemTemplate>
<uc2:ReplaceColumn ID="ReplaceColumn1" runat="server" />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Allow Access">
<ItemTemplate>
<asp:Image ID="Image1" runat="server" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
Hope it is clear enough. can any one help please?
You have to add public properties to your user controls which you then set using "normal" data-binding expressions. E.g:
user control:
public class MyUserControl : UserControl
{
public string ImageName {get; set;}
}
grid's template column:
<asp:TemplateField ...>
<ItemTemplate>
<uc1:MyUserControl runat="server" ImageName='<%# Eval("ImageUrl")%>' ... />
code-behind:
public class ImageVM { // view-model for data-binding
public string ImageUrl { get; set; }
}
...
var images = LoadImages(); // returns a list of ImageVM instances
grid.DataSource = images;
grid.DataBind();
Related
I have an ASP TemplateField inside a data populated GridView as follows:
<asp:GridView ID="gvReport" runat="server" AutoGenerateColumns="False" ShowHeaderWhenEmpty="true" OnRowDataBound="gvReport_RowDataBound" CssClass="table table-bordered">
<Columns>
<asp:BoundField DataField="Delete" HeaderText="Delete" SortExpression="Delete" />
<asp:TemplateField HeaderText="Delete">
<ItemTemplate>
<asp:HyperLink runat="server" NavigateUrl='<%# "Edit?from=Delete&ID=" + Eval("ID") %>' ImageUrl="Assets/SmallDelete.png" SortExpression="PathToFile" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
In other words, at the end of each row, there is a delete 'button'. I can tell whether a particular row/record has been deleted by checking the true/false value of the BoundField Delete in my code behind as follows:
if (e.Row.RowType == DataControlRowType.DataRow)
{
TableCell statusCell = e.Row.Cells[0];
if (statusCell.Text == "True")
{
//change ImageUrl of Hyperlink for this row
}
}
Right now, my icon is red for delete, but in the case that a record has already been deleted,
I would like to change the image to a different icon (a blue one).
How can I change this ImageUrl if statusCell evaluates to true?
ok, so we will need two parts here:
We need (want) to persist the data table that drives the grid).
The REASON for this?
We kill about 3 birds with one stone.
We use the data table store/save/know the deleted state
We use that delete information to toggle our image
(and thus don't have to store the state in the grid view).
We ALSO then case use that table state to update the database in ONE shot, and thus don't have to code out a bunch of database operations (delete rows). We just send the table back to the database.
In fact in this example, I can add about 7 lines of code, and if you tab around, edit the data? It ALSO will be sent back to the database. And this means no messy edit templates and all that jazz (which is panful anyway).
Ok, so, here is our grid - just some hotels - and our delete button with image:
markup:
<div style="width:40%;margin-left:20px">
<asp:GridView ID="GridView1" runat="server"
AutoGenerateColumns="False"
DataKeyNames="ID" CssClass="table table-hover borderhide" >
<Columns>
<asp:TemplateField HeaderText="HotelName" >
<ItemTemplate><asp:TextBox id="HotelName" runat="server" Text='<%# Eval("HotelName") %>' /></ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="FirstName" SortExpression="ORDER BY FirstName" >
<ItemTemplate><asp:TextBox id="FirstName" runat="server" Text='<%# Eval("FirstName") %>' /></ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="LastName" >
<ItemTemplate><asp:TextBox id="LastName" runat="server" Text='<%# Eval("LastName") %>' /></ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="City" >
<ItemTemplate><asp:TextBox id="City" runat="server" Text='<%# Eval("City") %>' /></ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Delete">
<ItemTemplate>
<asp:ImageButton ID="cmdDelete" runat="server" Height="20px" Style="margin-left:10px"
ImageUrl="~/Content/cknosel.png"
Width="24px" OnClick="cmdDelete_Click"></asp:ImageButton>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<br />
<asp:Button ID="cmdDeleteAll" runat="server" Text="Delete selected" Width="122px"
OnClientClick="return confirm('Delete all selected?')" />
</div>
Ok, and the code to load up the grid - NOTE WE persist the data table!!!!!
Code:
DataTable rstTable = new DataTable();
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadGrid();
else
rstTable = (DataTable)ViewState["rstTable"];
}
void LoadGrid()
{
// load up our grid
using (SqlCommand cmdSQL = new SqlCommand("SELECT * from tblHotels ORDER BY HotelName ",
new SqlConnection(Properties.Settings.Default.TEST4)))
{
cmdSQL.Connection.Open();
rstTable.Clear();
rstTable.Load(cmdSQL.ExecuteReader());
GridView1.DataSource = rstTable;
GridView1.DataBind();
}
ViewState["rstTable"] = rstTable;
}
Ok, so far, real plain jane. The result is this:
Ok, so now all we need is to add the delete button click event.
That code looks like this:
protected void cmdDelete_Click(object sender, ImageClickEventArgs e)
{
ImageButton btn = (ImageButton)sender;
GridViewRow rRow = (GridViewRow)btn.Parent.Parent;
DataRow OneRow = rstTable.Rows[rRow.DataItemIndex];
// toggle data
if (OneRow.RowState == DataRowState.Deleted)
{
// undelete
OneRow.RejectChanges();
btn.ImageUrl = "/Content/cknosel.png";
}
else
{
// delete
OneRow.Delete();
btn.ImageUrl = "/Content/ckdelete.png";
}
}
Again, really simple. But NOTE how we use the data table row state (deleted or not).
And this ALSO toggles the image for the delete button.
So, we don't have to care, worry, or store/save the sate in the grid.
So, if I click on a few rows to delete, I now get this:
So far - very little code!!!
Ok, so now the last part. the overall delete selected button. Well, since that is dangerous - note how I tossed in a OnClientClick event to "confirm the delete. if you hit cancel, then of course the server side event does not run.
But, as noted since we persisted the table? Then we can send the table deletes right back to the server without a loop. The delete code thus looks like this:
protected void cmdDeleteAll_Click(object sender, EventArgs e)
{
// send updates (deletes) back to database.
using (SqlCommand cmdSQL = new SqlCommand("SELECT * from tblHotels WHERE ID = 0",
new SqlConnection(Properties.Settings.Default.TEST4)))
{
cmdSQL.Connection.Open();
SqlDataAdapter daUpdate = new SqlDataAdapter(cmdSQL);
SqlCommandBuilder daUpdateBuild = new SqlCommandBuilder(daUpdate);
daUpdate.Update(rstTable);
}
LoadGrid(); // refesh display
}
So, note how easy it is to update (delete) from the database. If you look close, I used text boxes for that grid - not labels. The reason of course is that if the user tabs around in the grid (and edits - very much like excel), then I can with a few extra lines of code send those changes back to the database. In fact the above delete button code will be 100% identical here (it will send table changes back with the above code. So, if we add rows, edit rows then the above is NOT really a delete command, but is in fact our save edits/deletes/adds command!
I'm having problems retrieving the current row by changing the status of a DropDownList in the row. My code for the GridView is:
<asp:GridView ID="grdMappingList" runat="server" OnPageIndexChanging="grdMappingList_PageIndexChanging" AutoGenerateColumns="false" AllowPaging="true" PageSize="10" ShowHeaderWhenEmpty="true" UseAccessibleHeader="true" CssClass="table table-hover table-striped segment_list_tbl" >
<PagerStyle CssClass="grid_pagination" HorizontalAlign="Right" VerticalAlign="Middle" BackColor="#DFDFDF" />
<Columns>
<asp:BoundField HeaderText="Mapping Id" DataField="MAPPING_ID"></asp:BoundField>
<asp:BoundField HeaderText="PDM Name" DataField="PDM_NAME"></asp:BoundField>
<asp:BoundField HeaderText="PDM EntityID" DataField="PDM_ENTITY_ID" Visible="false"></asp:BoundField>
<asp:TemplateField HeaderText="Mapping Status" HeaderStyle-CssClass="width_120 aligned_center" ItemStyle-CssClass="width_120 aligned_center" Visible="true">
<ItemTemplate>
<asp:DropDownList id="ddlMappingStatus" runat="server" SelectedValue='<%# Bind("MappingCompleted") %>' OnSelectedIndexChanged="ddlMappingStatus_SelectedIndexChanged" AutoPostBack="true">
<asp:ListItem Text="Done" Value="DONE"></asp:ListItem>
<asp:ListItem Text="Not Done" Value="NOT DONE"></asp:ListItem>
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
And the code behind is:
protected void ddlMappingStatus_SelectedIndexChanged(object sender, EventArgs e)
{
int MappingID = Convert.ToInt16(grdMappingList.SelectedRow.Cells[0].Text);
DropDownList ddgvOpp = (DropDownList)grdMappingList.SelectedRow.FindControl("ddlMappingStatus");
if (ddgvOpp.Equals("DONE"))
{
}
}
I am getting an error on this line:
DropDownList ddgvOpp (DropDownList)grdMappingList.SelectedRow.FindControl("ddlMappingStatus");
and this line:
int MappingID = Convert.ToInt16(grdMappingList.SelectedRow.Cells[0].Text);
It seems that I can't retrieve the values! I dont know why. When I choose a new status from the DropDownList, I want to get all the values of the row in order to update the record.
Unfortunately, SelectedRow does not mean what you think it means. It doesn't just simply mean the current row you are working on or the current row with the controls that you are using. That property must get set somehow. This is usually done through a "Select" button on the GridView, such as an <asp:ButtonField> with the command name "Select".
You really do not need this however. You just need the row you are working with. Since you are using the SelectedIndexChanged event of your DropDownList, you already have what you need. You just need to go about it a different way.
First, get the DropDownList. Then get the row of the DropDownList. Now do whatever you need with the row.
But, from your code, it looks like you may not even need the row. You just need the value of the DropDownList. So you could skip that all together. But if you do need the row, here is how you would do that too.
protected void ddlMappingStatus_SelectedIndexChanged(object sender, EventArgs e)
{
DropDownList ddlMappingStatus = (DropDownList)sender;
if(ddlMappingStatus.SelectedItem.Text.ToUpper() == "DONE")
{
}
GridViewRow row = (GridViewRow)ddlMappingStatus.NamingContainer;
}
Now when you use <asp:BoundField> controls in your GridView, getting their values isn't very clean. You are forced to hardcode the column index like you were doing:
GridViewRow row = (GridViewRow)ddlMappingStatus.NamingContainer;
String mappingID = row.Cells[0].Text;
I tend to prefer using <asp:TemplateField> controls so I can use FindControl() to get what I am after. This prevents any reordering of the columns from breaking the code, as you'd have to hardcode different indexes. So for example, to find that DropDownList (since it already is a <asp:TemplateField>), you'd do something like this:
DropDownList ddlMappingStatus = (DropDownList)row.FindControl("ddlMappingStatus");
I'm trying to set the first column elements as hyperlinks redirecting to another page..but somehow it doesn't seem to work no matter what I try.
reportTable.Rows[i].Cells[1].Text = report.reportId.ToString();
TableCell tCell = new TableCell();
tCell.Controls.Add(new LiteralControl(" report.reportId.ToString ()"));
// Create Hyperlink Web Server control and add to cell
System.Web.UI.WebControls.HyperLink h = new HyperLink();
h.Text = reportTable.Rows[i].Cells[1].Text = report.reportId.ToString();
h.NavigateUrl = "~/manage.aspx";
tCell.Controls.Add(h);
reportTable.Rows[i].Cells[2].Text = bench.mechId;
reportTable.Rows[i].Cells[3].Text = bench.elecId;
reportTable.Rows[i].Cells[4].Text = bench.name;
asp.net Grid and data controls are very good for data binding.
Also they provide Item templates that can be customized to include links, drop down lists, etc.
Do not populate your grid by manually creating all the controls. That totally defeats the purpose of using a grid.
e.g:
<asp:GridView ID="ReportsGridView"
DataSourceID="ReportsDataSource"
AllowPaging="true"
AutoGenerateColumns="false"
runat="server">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:LinkButton runat="server"
ID="RedirectButton"
CommandName="Manage"
PostBackUrl="~/manage.aspx"
Text="Manage" />
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Name"
HeaderText="Report Name"/>
</Columns>
</asp:GridView>
How Can I Retrieve SelectedID of Telerik RadGrid On Client-Side Without Using OnRowSelected event?
so lets to see my scenarion:
my grid properties are like this :
<telerik:RadGrid ID="RadGrid1" runat="server" GridLines="None" DataSourceID="SqlDataSource1" AllowPaging="True" AutoGenerateColumns="False" CellSpacing="0"
Width="660px" onitemdatabound="RadGrid1_ItemDataBound">
<ClientSettings Selecting-AllowRowSelect="true">
<Selecting AllowRowSelect="True"></Selecting>
<ClientEvents OnRowSelected="OnRowSelected" />
</ClientSettings>
...
and goal Column :
<telerik:GridTemplateColumn FilterControlAltText="Filter TemplateColumn_Q column"
HeaderText="Q" UniqueName="TemplateColumn_Q">
<ItemTemplate>
<asp:Label ID="lblQInsideGrd" runat="server" Font-Size="11px" Text='<%# GetQ(Eval("Q")) %>'></asp:Label>
</ItemTemplate>
</telerik:GridTemplateColumn>
i fill this column in code behind like this :
protected string GetQ(object Q)
{
if (Q.ToString().Length < 10)
{
return Q.ToString();
}
else
{
string Q_str = Q.ToString();
Q_str = Q_str.Substring(0, 10) + "<span style='font-size:9px;color:red;'><a href='#' class='QClick'> (Full View...)</a></span>";
return Q_str;
}
as you see there is an anchor in every column that i want to retrieve related ID filed of that anchor in client side and show that id in an alert.
for server-side we can use CommandName property for that anchor.
also for client-side when we click on every row we can use OnRowSelected event to retrieve that id.
but in my situation, clicking on those anchors will not couse to select the entire row for firing OnRowSelected.
so what can i do about that?
thanks in advance
var radGrid = $find('<%= RadGrid1.ClientID %>');
var selectedItems = radGrid.get_masterTableView().get_selectedItems()
...
Here you are :)
How do I pass a GridView column value to the code behind with out making it visible? In the following code, I would like to capture the ContactID with out making it visible in the GridView.
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataSourceID="SqlDataSource1"
OnRowCommand="_OnRowCommand"
>
<Columns>
<asp:BoundField DataField="ContactID" HeaderText="ContactID"
SortExpression="ContactID" InsertVisible="False" ReadOnly="True" />
.....other columns in the grid....
<asp:ButtonField ButtonType=Button CommandName="Remove" Text="Remove" />
</Columns>
</asp:GridView>
I would like to capture ContactID as follows. I can not do so with out making it visible = true in the GridView.
if (e.CommandName.Equals("Remove"))
{
int index = Convert.ToInt32(e.CommandArgument);
int ContactID = Convert.ToInt32(GridView1.Rows[index].Cells[0].Text.Trim());
}
Please help.
Thanks..
What you want and what your code is doing are two different things.
I think what you are looking for is this:
String ContactID = e.Row.Cells(0).Text;
However, I propose a different way:
You can use a CommandArgument on your Button. That means that you are passing the argument through the Button itself. You won't need to get the argument from any other control. To do that, you would do this :
<asp:ButtonField ButtonType=Button CommandName="Remove" Text="Remove" CommandArgument='<%# Eval("ContactID") %>' />
And then your code looks like this:
if (e.CommandName.Equals("Remove"))
{
int ContactID = Convert.ToInt32(e.CommandArgument);
}
Here's a good example of GridView with CommandArguments.