Managing images in asp.net repeater (add class to each picture) - asp.net

This is my code:
Codebehind:
public class data
....
...
public List<dataImages> Images { get; set; }
...
var data= GarageBLL.LoadData(Convert.ToInt32(DataId), Convert.ToInt32(MemberId));
rptImages.DataSource = data.Images.Take(3);
rptImages.DataBind();
aspx:
<asp:Repeater runat="server" ID="rptImages">
<ItemTemplate>
<asp:Image runat="server" CssClass="img1" ImageUrl='<%# String.Format("/images/{0}/{1}.{2}", DataId, Eval("ImageId"), Eval("Extension")) %>' />
</ItemTemplate>
</asp:Repeater>
So, this works at the moment, but i would like to add different classes to each image.
Anyone got any idea how i can do that?

You can use repeater's ItemDataBound event to set the CssClass:
protected void rptImages_ItemDataBound(Object Sender, RepeaterItemEventArgs e) {
// This event is raised for the header, the footer, separators, and items.
// Execute the following logic for Items and Alternating Items.
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem) {
dataImages img = (dataImages) e.Item.DataItem;
Image img1 = (Image) e.Item.FindControl("img1");
// add your correct logic here according to the dataImages properties
img.CssClass = "YourCssClass";
// assuming you just want different classes for your three images, use ItemIndex with remainder:
string class = "img" + (e.Item.ItemIndex % 3 + 1).ToString() + "class";
img.CssClass = class;
}
}

Related

Setting BackColor to items in DropDownList bound to ObjectDataSource inside DetailsView

how do you properly call methods inside custom binding expressions? Are there complications because the dropdownlist is inside a detailsview?
asp.net code:
<asp:DropDownList ID="ddlExceptionEditStatus" runat="server"
DataSourceID="odsExceptionsStatus"
DataTextField="Name"
DataValueField="StatusID"
SelectedValue='<%# Bind("StatusID") %>'
BackColor="<%# SetBackColorProp(Container.DataItem) %>">
</asp:DropDownList>
code behind:
protected System.Drawing.Color SetBackColorProp(object o)
{
System.Drawing.Color statusColor = System.Drawing.Color.White;
string statusName = o as string;
if (statusName != null)
{
statusColor = System.Drawing.ColorTranslator.FromHtml(FISBLL.StatusColors.GetColor(statusName));
return statusColor;
}
else
{
return statusColor;
}
}
Doesn't change the backcolor. but doesn't throw an exception.
So, I had two mistakes:
1) I needed to cast the Container.DataItem to the class object i was using for the ObjectDataSource. After casting, the BackColor for each item in the dropdownlist matched the StatusID of the casted Container.DataItem.
2) Unfortunately this gave all the items the same color, where as I wanted each item's color to reflect the their own value attached to the dropdownlist. This is because the dropdownlist has an objectdatasource outside the DetailsView that it's inside of. Therefor the selectedValue item of the dropdownlist dictated the colors for all the other items.
I decided to go with Tim's suggestion and tie the BackColor setting for each item in the databound event:
protected string GetColor(string name)
{
return FISBLL.StatusColors.GetColor(name);
}
protected void ddlExceptionEditStatus_DataBound(object sender, EventArgs e)
{
foreach (ListItem item in ((DropDownList)sender).Items)
{
item.Attributes.Add("style", "background-color:" + GetColor(item.Text));
}
}
And the correct behavior is shown:

Add image to GridView's Cell

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

How do I change the class for a specific <li> inside a ASP.NET listview ?

The idea is for a menu. I need to highlight the menu a specific color depending on which top node is clicked.. So if I just needed to highlight it with ONE color I could say
<li <%# (Container.DataItem as FigLeafMenuItem).ItemSelected == "True" ? #" class=""MainMenuSelectedBlue""" : #" class=""""" %>>
But I need to change the color depending on some peice of server side info.. The closest I have gotten is below.. How do I access that specific LI so I can add a class to it?
protected void lvMainOuter_ItemDataBound(object sender, ListViewItemEventArgs e)
{
if (e.Item.ItemType == ListViewItemType.DataItem)
{
ListViewDataItem lvdi = (ListViewDataItem)e.Item;
FigLeafMenuItem flmi = (FigLeafMenuItem)lvdi.DataItem;
if (flmi.Name == "About Us")
{
HtmlGenericControl hgc = (HtmlGenericControl)e.Item.FindControl("xxx");
hgc.Attributes.Add("class", "MainMenuSelectedBlue");
}
}
}
You cannot access html tag from code behind without runat="server". However, you can render entire li tag using literal control.
<asp:Literal id="MenuItemLiteral" runat="server" />
if (flmi.Name == "About Us")
{
var literal = (Literal)e.Item.FindControl("MenuItemLiteral");
literal.Text = string.format("<li class=\"{0}\">{1}</li>", DATA1, DATA2);
}

Embedded code in repeater

I am using a databound repeater component with some click-sensitive panel inside.
<ItemTemplate>
<asp:Panel ID="PanelContent" runat="server">
<asp:Panel ID="PanelMenuTitle" runat="server"
ondblclick="EditMenu(<%# Eval("ID") %>)">
As you can see I want to pass the ID of the current data item to a javascript function called EditMenu().
However, this code breaks due to "The server tag is not well formed.". I also tried everything I can think of: Using <%= instead of <%#, Bind() instead of Eval(), ' instead of " without success.
Use single quotes around the ondblclick function. That should fix it. See below.
ondblclick='EditMenu(<%# Eval("ID") %>)'
My second suggestion would be to use another control, like a ListView or a DataList, so that you can assign data keys to hold the ID. Then you can assign the ondblclick event in the ItemDataBound event like this.
protected void ListView1_ItemDataBound(object sender, ListViewItemEventArgs e)
{
if (e.Item.ItemType == ListViewItemType.DataItem)
{
Panel pnlCtrl = (Panel)e.Item.FindControl("Panel1");
if (pnlCtrl != null)
{
pnlCtrl.Attributes["ondblclick"] = String.Format("EditMenu({0})", ListView1.DataKeys[((ListViewDataItem)e.Item).DisplayIndex]["ID"]);
}
}
}
Alright, I got it working. Not the original approach, but in the end it's what I wanted:
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
Panel pnlCtrl = (Panel)e.Item.FindControl("PanelMenuTitle");
if (pnlCtrl != null)
{
myMenu menu = (e.Item.DataItem as myMenu);
pnlCtrl.Attributes["ondblclick"] = String.Format("EditMenu('{0}')", menu.ID);
}
}

nested dictionary to nested repeater asp.net c#

I'm making an asp.page that will display hierarchical information about company assets.
To grab the data I used a lambda expression:
FASAssetInfoDataContext fasInfo = new FASAssetInfoDataContext();
var data = from g in fasInfo.Asset_Informations
where g.Department.Substring(0, 3) == p
select g;
Dictionary<string, Dictionary<string, List<info>>> branch = data.GroupBy(e => e.Location)
.ToDictionary(g => g.Key,
g => g.GroupBy(gl => gl.G_L_Asset_Acct_No)
.ToDictionary(gl => gl.Key,
gl => gl.Select(s => new info
{
acqDate = s.Acquisition_Date,
asstNo = s.Co_Asset_Number,
classInfo = s.Class,
description = s.Description,
mfgSerialNo = s.Mfg_Serial_No,
deprThisRun = s.Depr_This_Run__Int_,
AcqValue = s.Acquisition_Value__Int_,
currentAccDepr = s.Current_Accum_Depr__Int_,
estLife = s.Est_Life__YYMM___Int_,
inServiceDate = s.Placed_In_Service_Date__Int_,
netBookValue = s.Current_Net_Book_Value__Int_,
oldAcqValue = s.Acquisition_Value__Tax_
}).ToList()));
So I now have a nested set of dictionaries with a list of information at the end. My question is how do I best display this information on the page itself? I can get the first level but have been struggling to get the nested repeater to function properly. If there is a better control to use I'm all ears :)
Thanks,
Marco
If you do indeed need to use nested repeaters, its possible, but getting it working isn't particularly obvious. The following would work (simplified for brevity):
<asp:Repeater id="level1" OnItemDataBound="level1_ItemDataBound" ...>
<ItemTemplate>
<asp:Repeater id="level2" OnItemDataBound="level2_ItemDataBound" ...>
<ItemTemplate>
<asp:Repeater id="level3" OnItemDataBound="level3_ItemDataBound" ...>
</asp:Repeater>
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:Repeater>
Code behind:
protected void Page_Load(object sender, EventArgs e)
{
Dictionary<string, Dictionary<string, List<info>>> branch = ...;
level1.DataSource = branch;
level1.DataBind();
}
protected void level1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
Dictionary<string, List<info>> data = (Dictionary<string, List<info>>)e.Item.DataItem;
Repeater level2 = e.Item.FindControl("level2") as Repeater;
level2.DataSource = data;
level2.DataBind();
}
protected void level2_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
List<info> data = (List<info>)e.Item.DataItem;
Repeater level3 = e.Item.FindControl("level3") as Repeater;
level3.DataSource = data;
level3.DataBind();
}
protected void level3_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
// Bind properties from info elements in List<info> here
}
There's an nicer way of doing this without any ItemDataBound events. For simplicity let's assume two level of repeaters.
<asp:Repeater id="level1" >
<ItemTemplate>
<asp:Repeater id="level2"
DataSource='<%# ((System.Collections.Generic.KeyValuePair<string,System.Collections.Generic.List<string>>)Container.DataItem).Value %>' >
<ItemTemplate>
<%# Container.DataItem %>
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:Repeater>
I usually prefer this way, since for some reason I hate ItemDataBound events :)
asp:TreeView? Not sure how it will handle the nested data set but it's designed to display it.

Resources