I want to add image to GridView cell with below code but doesn't show image
//aspx
<asp:TemplateField HeaderText="image">
<ItemTemplate>
<asp:Image ID="img" runat="server" Width="100px" Height="100px" />
</ItemTemplate>
//.cs -> In page_Load
for (int i = 0; i < GridView1.Rows.Count; i++)
{
Image img = (Image)GridView1.Rows[i].FindControl("img");
img.ImageUrl = path of image;
}//for
You can use RowDataBound event to change something inside a GridView Row.
protected void GridView1_RowDatabound(object sender, GridViewRowEventArgs e)
{
// check if this row is a row with Data (not Header or Footer)
if (e.Row.RowType == DataControlRowType.DataRow)
{
// find your Image control in the Row
Image image = ((Image)e.Row.FindControl("img"));
// set the path of image
img.ImageUrl = "path of image";
}
}
Or you can use a foreach statment to loop in Rows collection and change the path of image. this code could be on the Page_Load event.
foreach(GridViewRow row in GridView1.Rows)
{
// check if this row is a row with Data (not Header or Footer)
if (row.RowType == DataControlRowType.DataRow)
{
// find your Image control in the Row
Image image = ((Image)row.FindControl("img"));
// set the path of image
img.ImageUrl = "path of image";
}
}
Edits
You cannot set the image out of the solution. Do to this, you have to create an Handler (.ashx file) and pass the name of your image on C: and return the a byte[], something like this:
public void ProcessRequest(HttpContext context)
{
byte[] imageBytes = File.ReadAllBytes(#"C:\" + context.Request["image"]);
context.Response.ContentType = "image/png";
context.Response.BinaryWrite(imageBytes);
}
And on your page, set it by handler passing a image parameter in url:
Image image = ((Image)row.FindControl("img"));
img.ImageUrl = "ImageHandler.ashx?image=1.png";
The event Page_Load fires before the GridView databinds or creates itself. If they're all going to be the same image, why not just set that path to in the ItemTemplate? If it's because you don't know the path until you get into the code behind, you could bind the ImageUrl in the template to a custom property and then just set that property in the Page_Load and then populate the property. Otherwise, any changes you want to make will need to be done in the RowDataBound event.
You can directly give path to image from database
<ItemTemplate>
<asp:Image ID="img" runat="server" Width="100px" Height="100px" ImageUrl='<%# Eval("Imageurl") %>' />
</ItemTemplate>
or give url in alt tag and in rowdatabound use it.
if (e.Row.RowType == DataControlRowType.DataRow)
{
Image image1 = ((Image)e.Row.FindControl("img"));
img.ImageUrl = image1.Alt; // You can check for path here if no image found
}
Using loop through gridview is not proper way as well as it decrease the performance
Related
Using the obout grid with the following column:
<obg:Column ID="Image" DataField="" HeaderText="" Width="50" runat="server">
<TemplateSettings TemplateId="ImageTemplate" />
</obg:Column>
And the following Template:
<Templates>
<obg:GridTemplate runat="server" ID="ImageTemplate">
<Template>
<img src="images/test.png" title="test" />
</Template>
</obg:GridTemplate>
</Templates>
I am trying to hide the image on certain rows programmatically:
protected void grd_RowDataBound(object sender, GridRowEventArgs e)
{
if (testpassed())
{
e.Row.Cells[1].Text = ""; // Column 2 is the image
}
}
But it is not hiding the image. How do I hide the image programmatically using an obout grid for certain rows only? Thanks before hand.
If found the answer in case someone runs into this in the future:
protected void grd_RowDataBound(object sender, GridRowEventArgs e)
{
// Check if this is a DataRow
if (e.Row.RowType == GridRowType.DataRow)
{
// Check if we are hiding the image
if (testpassed())
{
// Retrieve Image Cell (Column 2 in my case)
GridDataControlFieldCell cell = e.Row.Cells[1] as GridDataControlFieldCell;
// Retrieve Literal Control with Image Source Html (Found at Level 5)
LiteralControl imgTag = cell.Controls[0].Controls[0].Controls[0].Controls[0].Controls[0] as LiteralControl;
// Remove Html <img src.. code from Literal Control in order to hide image
imgTag.Text = "";
}
}
}
I have to add tooltip for my gridview edit image button. I coded as Commandfield.
<asp:CommandField ButtonType="Image"
HeaderStyle-HorizontalAlign="center"
EditText="Edit" UpdateText="Edit"
ShowEditButton="True"
ItemStyle-VerticalAlign="Top"
EditImageUrl="~/Images/edit.png"
UpdateImageUrl ="~/Images/Save.png" CancelImageUrl ="~/Images/cancel.png"
ItemStyle-Width="15px" ControlStyle-Width="15px">
</asp:CommandField>
Is it possible to add a tooltip in gridview commandfield button type as image?
Following code works well:
protected void gvResourceEditor_RowDataBound(object sender, GridViewRowEventArgs e)
{
try
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
e.Row.Cells[4].ToolTip = "Edit Resource Details";
if (e.Row.RowState == DataControlRowState.Edit || e.Row.RowState.ToString() == "Alternate, Edit")
{
int i = 0;
foreach (TableCell cell in e.Row.Cells)
{
if (e.Row.Cells.GetCellIndex(cell) == 4)
{
((System.Web.UI.WebControls.ImageButton)(e.Row.Cells[4].Controls[0])).ToolTip = "Update Resource Details";
((System.Web.UI.LiteralControl)(e.Row.Cells[4].Controls[1])).Text = " ";
((System.Web.UI.WebControls.ImageButton)(e.Row.Cells[4].Controls[2])).ToolTip = "Close Resource Details";
}
i++;
}
}
}
}
catch (Exception _e)
{
}
}
or you can
define the EditText property of your gridview's commandfield (as you did), which will render as alt atribute of the <input type='image' alt='Edit' /> tag:
<asp:CommandField ButtonType="Image" EditText="Edit" etc />
then add a script tag to set the title attribute with the following code:
VB:
Protected Sub gvResourceEditor_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles gvResourceEditor.RowDataBound
Dim strScript as String = "$('#" + gvResourceEditor.ClientID + " input[type=image]').each(function(key, el) {el.title=el.alt;});"
Page.ClientScript.RegisterStartupScript(Me.GetType, "SetEditButtonTitle", strScript, True)
End Sub
CS:
protected void gvResourceEditor_RowDataBound(object sender, GridViewRowEventArgs e) {
string strScript = "$('#" + gvResourceEditor.ClientID + " input[type=image]').each(function(key, el) {el.title=el.alt;});"
Page.ClientScript.RegisterStartupScript(this.GetType(), "SetEditButtonTitle", strScript, true);
}
Of course, you may need to taylor the javascript to your grid. This script will set the title attribute of all input tag with type=image.
I didn't try solutions suggested by Sekaran and Show and took a little different approach as I was not willing to rely on JavaScript; thought it might be worth sharing.
A Show's mentioned in his solution that EditText property of Edit button will be rendered as alt attribute of image; this means it should also be stored as AlternateText of the .NET counterpart.
In my case; I have Edit, Update, Delete and Cancel buttons in my CommandField and I wanted to do same for all buttons.
So the (localized) text is in AlternateText property of buttons; I am looping through each buttons and put this value in ToolTip property.
Here is my code.
protected void myGridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
foreach (Control ctrl in e.Row.Cells[2].Controls)
{
if (ctrl.GetType().BaseType == typeof(ImageButton))
((ImageButton)ctrl).ToolTip = ((ImageButton)ctrl).AlternateText;
}
}
}
I had hardcoded Cell Id "2" in my code as it was well known.
Every Image Button control is of System.Web.UI.WebControls.DataControlImageButton type which is not accessible. Therefore I had used it's BaseType which should be ImageButton
The RegisterStartupScript part of #show's answer does not neeed to run during RowDataBound. There it will run for each row doing exactly the same thing during the grid databind process. You can drop those two lines into the OnPreRender event for the page and it will have the same effect but only happens once during code execution on the server.
I have a <asp:GridView > with a <asp:ButtonField ButtonType="Image"> as one of the columns.
Here's the problem: I have to dynamically change the image of this ButtonField during the gridView_RowDataBound(...) event based on the data found in that particular gridview row.
The real question is, is how to access that particular ButtonField inside the gridView_RowDataBound(...) event so I can change its image in C# code?
I can't use
Image imgCtrl = (Image)args.Row.FindControl("ctrlID");
because the <asp:ButtonField> won't allow an ID to be set (get a parser error when I try to run the webPage). And I can't use
args.Row.Cells[0].Controls[0];
because the zeroth index of the .Controls[0] doesn't exist (I get a boundry overflow error).
There's got to be a simple, slick, easy way to do this!
Quick Example :
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
DataRowView drv = (DataRowView)e.Row.DataItem;
if (e.Row.RowType == DataControlRowType.DataRow)
{
TableCell tableCell = e.Row.Cells[3]; // Column 3 in the grid have the Image Button
foreach (var control in tableCell.Controls)
{
if (control.GetType() == typeof(System.Web.UI.WebControls.ImageButton)) ;
{
ImageButton iButton = control as ImageButton;
iButton.ImageUrl = "/Logo.jpg";
}
}
}
}
I have a GridView bound to a DataTable that I construct. Most columns in the table contain the raw HTML for a hypelinklink, and I would like that HTML to render as a link in the browser, but the GridView is automatically encoding the HTML, so it renders as markup.
How can I avoid this without explicitly adding HyperLink, or any other, columns?
Simply set the BoundColumn.HtmlEncode property to false:
<asp:BoundField DataField="HtmlLink" HtmlEncode="false" />
I am afraid that there is no easy way to disable HTML encoding of the contents in a GridView with AutoGenerateColumns= true. However, I can think of two workarounds that might solve the problem you are facing:
Option 1: Inherit the GridView class, override the Render method, loop through all cells, decode their contents, before executing the base method:
for (int i = 0; i < Rows.Count; i++)
{
for (int j = 0; j < Rows[i].Cells.Count; j++)
{
string encoded = Rows[i].Cells[j].Text;
Rows[i].Cells[j].Text = Context.Server.HtmlDecode(encoded);
}
}
Option 2: In a class inheriting from GridView or in the Page or Control using it, make your own inspection of the DataTable and create an explicit BoundColumn for each column:
foreach (DataColumn column in dataTable.Columns)
{
GridViewColumn boundColumn = new BoundColumn
{
DataSource = column.ColumnName,
HeaderText = column.ColumnName,
HtmlEncode = false
};
gridView.Columns.Add(boundColumn);
}
I was able to achieve this by using the solution that Jørn Schou-Rode provided, I modified a little bit to make it work from the RowDataBound Event of my Gridview.
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
for (int j = 0; j < e.Row.Cells.Count; j++)
{
string encoded = e.Row.Cells[j].Text;
e.Row.Cells[j].Text = Context.Server.HtmlDecode(encoded);
}
}
}
Another way is to add something like the following to the RowDataBound event handler...
If e.Row.RowType = DataControlRowType.Header Then
For Each col As TableCell In e.Row.Cells
Dim encoded As String = col.Text
col.Text = Context.Server.HtmlDecode(encoded)
Next
End If
Use OnRowCreated
protected void gvFm_RowCreated(object sender, GridViewRowEventArgs e)
{
foreach (TableCell cell in e.Row.Cells)
{
BoundField fldRef = (BoundField)((DataControlFieldCell)cell).ContainingField;
switch (fldRef.DataField)
{
case "ColToHide":
fldRef.Visible = false;
break;
case "ColWithoutEncode":
fldRef.HtmlEncode = false;
break;
}
}
}
Well since the html for the link is in your db already, you could just output the html to a literal control.
<asp:TemplateField HeaderText="myLink" SortExpression="myLink">
<ItemTemplate>
<asp:Literal ID="litHyperLink" runat="server" Text='<%# Bind("myLink", "{0}") %>' />
</ItemTemplate>
</asp:TemplateField>
This should render your link as raw text allowing the browser to render it as the link you expect it to be.
Since all the answers seem to be in C# and the questions was not specific, I ran into this issue using ASP.Net and VB.Net and the accepted solution did not work for me in VB (though I imagine it does work in C#). Hopefully this helps anyone working with VB.Net in ASP who stumbles upon this as I have.
In VB.Net BoundColumn cannot be added to Gridview.Columns as it is not a System.Web.UI.WebControls.DataControlField so instead one must use a BoundField which is a DataControlField.
BoundColoumn also does not have an HtmlEncode property however BoundField does. Also, in VB.Net DataSource becomes DataField.
For Each dataCol As DataColumn In dv.Table.Columns
Dim boundCol As New BoundField With {
.DataField = dataCol.ColumnName,
.HeaderText = dataCol.ColumnName,
.HtmlEncode = False
}
gvResult.Columns.Add(boundCol)
Next
gvResult.DataSource = dv
gvResult.Databind()
Also note that you must explicitly set AutoGenerateColumns="False" or the GridView will still generate columns along with the columns added above.
You can use this code in RowDataBound event if you want to disable HTML encoding in all rows and columns.
protected void GV_Product_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
foreach (TableCell ObjTC in e.Row.Cells)
{
string decodedText = HttpUtility.HtmlDecode(ObjTC.Text);
ObjTC.Text = decodedText;
}
}
}
I have a page with a table of stuff and I need to allow the user to select rows to process. I've figured out how to add a column of check boxes to the table but I can't seem to figure out how to test if they are checked when the form is submitted. If they were static elements, I'd be able to just check do this.theCheckBox but they are programaticly generated.
Also I'm not very happy with how I'm attaching my data to them (by stuffing it in there ID property).
I'm not sure if it's relevant but I'm looking at a bit of a catch-22 as I need to known which of the checkboxes that were created last time around were checked before I can re-run the code that created them.
Edit:
I've found an almost solution. By setting the AutoPostBack property and the CheckedChanged event:
checkbox.AutoPostBack = false;
checkbox.CheckedChanged += new EventHandler(checkbox_CheckedChanged);
I can get code to be called on a post back for any check box that has changed. However this has two problems:
The call back is processed after (or during, I'm not sure) Page_Load where I need to use this information
The call back is not called for check boxes that were checked when the page loaded and still are.
Edit 2:
What I ended up doing was tagging all my ID's with a know prefix and stuffing this at the top of Form_Load:
foreach (string v in this.Request.Form.AllKeys)
{
if (v.StartsWith(Prefix))
{
var data = v.Substring(Prefix.Length);
}
}
everything else seems to run to late.
I'm going to assume you're using a DataList but this should work with and Control that can be templated. I'm also going to assume you're using DataBinding.
Code Front:
<asp:DataList ID="List" OnItemDataBound="List_ItemDataBound" runat="server">
<ItemTemplate>
<asp:CheckBox ID="DeleteMe" runat="server"/>
<a href="<%# DataBinder.Eval(Container, "DataItem.Url")%>" target="_blank">
<%# DataBinder.Eval(Container, "DataItem.Title")%></a>
</ItemTemplate>
</asp:DataList>
<asp:Button ID="DeleteListItem" runat="server" OnClick="DeleteListItem_Click" ></asp:Button>
Code Behind:
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadList();
}
protected void DeleteListItem_Click(object sender, EventArgs e)
{
foreach (DataListItem li in List.Items)
{
CheckBox delMe = (CheckBox)li.FindControl("DeleteMe");
if (delMe != null && delMe.Checked)
//Do Something
}
}
LoadList();
}
protected void LoadList()
{
DataTable dt = //Something...
List.DataSource = dt;
List.DataBind();
}
protected void List_ItemDataBound(object sender, DataListItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item)
{
string id = DataBinder.Eval(e.Item.DataItem, "ID").ToString();
CheckBox delMe = (CheckBox)e.Item.FindControl("DeleteMe");
if (delMe != null)
delMe.Attributes.Add("value", id);
}
}
}
First, make sure that each Checkbox has an ID and that it's got the 'runat="server"' in the tag.
then use the FindControl() function to find it.
For example, if you're looping through all rows in a GridView..
foreach(GridViewRow r in Gridview1.Rows)
{
object cb = r.FindControl("MyCheckBoxId");
if(r != null)
{
CheckBox chk = (CheckBox)cb;
bool IsChecked = chk.Checked;
}
}
Postback data is restored between the InitComplete event and the PreLoad event. If your checkboxes are not created until later then the checkboxes will play "catch up" with their events and the data will be loaded into the control shortly after it is created.
If this is to late for you then you will have to do something like what you are already doing. That is you will have to access the post data before it is given to the control.
If you can save the UniqueId of each CheckBox that you create then can directly access the post data without having to given them a special prefix. You could do this by creating a list of strings which you save the ids in as you generate them and then saving them in the view state. Of course that requires the view state to be enabled and takes up more space in the viewstate.
foreach (string uniqueId in UniqueIds)
{
bool data = Convert.ToBoolean(Request.Form[uniqueId]);
//...
}
Your post is a little vague. It would help to see how you're adding controls to the table. Is it an ASP:Table or a regular HTML table (presumably with a runat="server" attribute since you've successfully added items to it)?
If you intend to let the user make a bunch of selections, then hit a "Submit" button, whereupon you'll process each row based on which row is checked, then you should not be handling the CheckChanged event. Otherwise, as you've noticed, you'll be causing a postback each time and it won't process any of the other checkboxes. So when you create the CheckBox do not set the eventhandler so it doesn't cause a postback.
In your submit button's eventhandler you would loop through each table row, cell, then determine whether the cell's children control contained a checkbox.
I would suggest not using a table. From what you're describing perhaps a GridView or DataList is a better option.
EDIT: here's a simple example to demonstrate. You should be able to get this working in a new project to test out.
Markup
<form id="form1" runat="server">
<div>
<table id="tbl" runat="server"></table>
<asp:Button ID="btnSubmit" runat="server" Text="Submit"
onclick="btnSubmit_Click" />
</div>
</form>
Code-behind
protected void Page_Load(object sender, EventArgs e)
{
for (int i = 0; i < 10; i++)
{
var row = new HtmlTableRow();
var cell = new HtmlTableCell();
cell.InnerText = "Row: " + i.ToString();
row.Cells.Add(cell);
cell = new HtmlTableCell();
CheckBox chk = new CheckBox() { ID = "chk" + i.ToString() };
cell.Controls.Add(chk);
row.Cells.Add(cell);
tbl.Rows.Add(row);
}
}
protected void btnSubmit_Click(object sender, EventArgs e)
{
foreach (HtmlTableRow row in tbl.Rows)
{
foreach (HtmlTableCell cell in row.Cells)
{
foreach (Control c in cell.Controls)
{
if (c is CheckBox)
{
// do your processing here
CheckBox chk = c as CheckBox;
if (chk.Checked)
{
Response.Write(chk.ID + " was checked <br />");
}
}
}
}
}
}
What about using the CheckBoxList control? I have no Visual Studio open now, but as far as I remember it is a DataBound control, providing DataSource and DataBind() where you can provide a list at runtime. When the page does a postback you can traverse the list by calling something like myCheckBoxList.Items and check whether the current item is selected by calling ListItem.Selected method. This should work.
Add them in an override of the CreateChildControls method of the Page. Be sure to give them an ID! This way they get added to the control tree at the correct time.
IMHO The best way would be to use DataBound Templated Control though, i.e. something like a ListView (in .NET 3.5). then in pageload after postback traverse all items in the databound control and use item.FindControl to get at the actual checkbox.
What I ended up doing was tagging all my ID's with a know prefix and stuffing this at the top of Form_Load:
foreach (string v in this.Request.Form.AllKeys)
{
if (v.StartsWith(Prefix))
{
var data = v.Substring(Prefix.Length);
}
}
everything else seems to run to late.