Insert a control before another control inside a ItemDataBound event - asp.net

I tried to Solution suggested here, but it didn't work in my case. using Page.Controls.IndexOf() for any of the elements on my page, when called in the ItemDataBound event method, returns -1.
I need to insert a linebreak based on certain conditions for stuff generated by my Data repeater. Here is the method:
private String lastCharacter = "";
public void users_ItemDataBound(Object Sender, RepeaterItemEventArgs e)
{
HyperLink link = (HyperLink)e.Item.FindControl("micrositeLink");
Tuple<String, String> user = (Tuple<String, String>)e.Item.DataItem;
link.NavigateUrl = "/" + user.Item1;
link.Text = user.Item2;
// makes a break in the data when going from one bunch of data to another.
if (user.Item1.Length >= 2)
{
if (lastCharacter == "")
lastCharacter = user.Item1[1].ToString().ToLower();
else if (lastCharacter != user.Item1[1].ToString().ToLower())
{
HtmlGenericControl lineBreak = new HtmlGenericControl("br");
if (Page.Controls.IndexOf(link) >= 0)
Page.Controls.AddAt(Page.Controls.IndexOf(link), lineBreak);
lastCharacter = user.Item1[1].ToString().ToLower();
}
}
}
The bound data is a list of users in my system with names beginning with a particular letter. My goal is to further sub-divide this data with a line break between groups of data that have the same second letter. For instance:
AaPerson Aarad AaStuff
Aathing
AbItem AbStuff
Acan Achandle
To me, inserting a line break before the elements where the second letter changes is the obvious solution, but other suggestions are also appreciated.

Try using e.Item.Controls.IndexOf instead:
if (e.Item.Controls.IndexOf(link) >= 0)
e.Item.Controls.AddAt(e.Item.Controls.IndexOf(link), lineBreak);

Related

Depending source for drop down list

I have one drop down list in my pages that its source comes of below code. Now I like to put 1 text box adjusted on my drop down list and when I type on that, source of drop down list (DocumentNo) depend on what I type in the text box and when text box is null drop downs list shows all the (DocumentNo) , please help how I have to change my code,
protected void ddlProjectDocument_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
var query = from p in _DataContext.tblDocuments
orderby p.DocumentNo
select p;
int maxs = 0;
foreach (tblDocument v in query)
{
if (v.DocumentNo.Length > maxs)
maxs = v.DocumentNo.Length;
}
foreach (tblDocument vv in query)
{
string doctitle = vv.DocumentNo;
for (int i = vv.DocumentNo.Length; i < maxs; i++)
{
doctitle += " ";
}
doctitle += " | ";
doctitle += vv.TITLE;
// Use HtmlDecode to correctly show the spaces
doctitle = HttpUtility.HtmlDecode(doctitle);
ddlProjectDocument.Items.Add(new ListItem(doctitle, vv.DocId.ToString()));
}
}
First, I would highly recommend storing the result of that query at the beginning of the method into something like a session variable so that you don't have to continually query the database every time you hit this page.
Second, you should use the OnTextChanged event in ASP.NET to solve this problem. Put in the OnTextChanged attribute to point to a method in your code behind that will grab the query result values (now found in your session variable) and will reset what is contained in ddlProjectDocument.Items to anything that matched what was being written by using String.StartsWith():
var newListOfThings = queryResults.Where(q => q.DocumentNo.StartsWith(MyTextBox.Value));
At this point all you need to do is do that same loop that you did at the end of the method above to introduce the correct formatting.

change row colors in a specific OutlookGroupBy group in UltraGrid in VB.net

I am using an ultragrid and inside i have values that i load into a datatable from a database. In my grid i group the rows into groups with OutlookGroupBy code. My rows in the grid are in two categories. The Priority 1 and 0. I want when the data are loaded the rows that are in priority 1 to get color red, and the others in priority 0 to be in normal color.
I use the ultragrid pro grammatically so i didnt use any of its features in the editor.
here is how i initialize my grid and how i load from database from another class:
Dim dt As DataTable = Nothing
Timer1.Enabled = True
UltraGrid1.DataSource = Nothing
Generic.openOrders(dt)
UltraGrid1.DataSource = dt
Dim band As Infragistics.Win.UltraWinGrid.UltraGridBand = UltraGrid1.DisplayLayout.Bands(0)
UltraGrid1.DisplayLayout.ViewStyleBand = Infragistics.Win.UltraWinGrid.ViewStyleBand.OutlookGroupBy
band.SortedColumns.Add(band.Columns("PRIORITY"), True, True)
band.SortedColumns.Add(band.Columns("ORDERID"), False, True)
band.SortedColumns.Add(band.Columns("ORDERTIME"), False, True)
anyone has any idea of how can i change the row color into the priority 1 subrows??
You can try with this approach:
First you need to subscribe the event InitializeRow, so add this by the designer or by code (eg. in Form_Load or before setting the DataSource of the grid)
grd.InitializeRow += new InitializeRowEventHandler(grd_InitializeRow);
then, in the event, write code like this
private void grd_InitializeRow(object sender, InitializeRowEventArgs e)
{
if(e.Row.Band.Index == 1)
{
if(Convert.ToInt32(e.Row.Cells["PRIORITY"].Value) == 1)
e.Row.Appearance.BackColor = Color.LightGreen;
}
}
Keep in mind that if you have set CellAppearance they will have precedence on RowAppearance and, if you have many rows it is better to initialize an Appearance object, store it in the grid.DisplayLayout.Appearances collection and reuse the same object for every row involved.
Moreover, always with the aim of improving the performance, to get the cell value it is better to use the GetCellValue method of the row. This will avoid the creation of the a full Cell object just to retrieve its value. Things are a bit more complicated because you need an UltraGridColumn and not just the name of the column, but in the InitializeRow event, fired for each row, this is little price to pay.
private void grd_InitializeRow(object sender, InitializeRowEventArgs e)
{
if(e.Row.Band.Index == 1)
{
UltraGridColumn priorityColumn = e.Row.Band.Columns["PRIORITY"];
if(Convert.ToInt32(e.Row.GetCellValue(priorityColumn)) == 1)
e.Row.Appearance.BackColor = Color.LightGreen;
}
}
EDIT: The same code in VB.NET
....
AddHandler grd.InitializeRow, AddressOf Me.grd_InitializeRow
....
Private Sub grd_InitializeRow(sender As System.Object, e As InitializeRowEventArgs)
If e.Row.Band.Index = 1 Then
Dim priorityCol As UltraGridColumn = e.Row.Band.Columns("PRIORITY")
If Convert.ToInt32(e.Row.GetCellValue(priorityCol)) = 1 Then
e.Row.Appearance.BackColor = Color.LightGreen
End If
End If
End Sub
Also, the use the UltraGridColumn class, you need to add at the start of file
Imports Infragistics.Win.UltraWinGrid

grid View footer total in asp.net [duplicate]

protected void inderGrid_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
decimal rowTotal = Convert.ToDecimal
(DataBinder.Eval(e.Row.DataItem, "DC_No_Decimal"));
//grdTotal = grdTotal + rowTotal;
grdTotal += rowTotal;
}
if (e.Row.RowType == DataControlRowType.Footer)
{
Label lbl = (Label)e.Row.FindControl("lblTotal");
e.Row.Cells[3].Text = grdTotal.ToString("c");
//lbl.Text = grdTotal.ToString("c");
}
}
from the above code i m getting total for every page in the grid view. Instead of getting total to every page i need all page total at the end of the grid view footer. Help Immediatly.
Thanks in advance
If you want the total of ALL pages, and for the footer to only appear on the last page, then you can't calculate the totals how you are doing.
At the moment your looping through every row on the gridview. If you are using paging the gridview won't be showing all the rows, so the total won't be correct.
Are you paging with a PagedDataSource or are you limiting the records returned from SQL etc? If you are using a DataSet and a PagedDataSource you'll be able to find the total from the DataSet (as this will contain all the records). Otherwise, you'll have to create a second query to calculate the total.
Then in terms of displaying the values in the footer, you'll have to add an IF statement to your ItemDataBound event to only display this if its the final page.
If you trying to display the record summery, please look this one about Displaying Summary Information in the GridView's Footer
What I do is setup the following in the code behind (This is just an example column):
int totalCallsTaken = 0;
public int CallsTaken(int value)
{
totalCallsTaken += value;
return value;
}
public int CallsTakenTotal()
{
return totalCallsTaken;
}
Then in the ASPX page I put the following template field in:
<asp:TemplateField HeaderText="Calls Taken" FooterStyle-Font-Bold="true">
<ItemTemplate>
<%#CallsTaken(Convert.ToInt32(Eval("CallsTakenCount").ToString())).ToString("N0")%>
</ItemTemplate>
<FooterTemplate>
<%#CallsTakenTotal().ToString("N0")%>
</FooterTemplate>
</asp:TemplateField>
I hope that helps, Ian.
Noddy but you can try one more check in the if condition.
if(e.Row.RowType == DataControlRowType.Footer && inderGrid.PageCount == inderGrid.PageIndex + 1)
{
//code here.
}
// Try this
if(e.Row.RowType == DataControlRowType.Footer && inderGrid.PageCount == inderGrid.PageIndex + 1)
{
for (int i=0; i< inderGrid.Rows.Count; i++)
{
var currentRowCellVal = Convert.ToDecimal(inderGrid.Rows[i].Cells[0].Text);
grdTotal += currentRowCellVal;
}
e.Row.Cells[3].Text = grdTotal.ToString("c");
}
Just to be certain I'm understanding, you're saying you have a grid with say 100 items, but only 25 are shown at any given time. Then you want the footer to only display the sum of those 25 items that are displayed on the page.
There's a couple of options that you can do here for this:
1) Use JavaScript to calculate the total after the page has been rendered.
2) use intelligent SQL to only return those particular rows that you're wanting to display on the grid--and then keep your grid the same
3) calculate the visible rows in your code, and only add them when you need them. Remember, you know in the code behind which Grid.PageIndex you're on as well as how many items each page has. With this knowledge, you should be able to determine via the row index if any given datarow will be rendered to the screen.
You need to generate all records total using the actual data.
If you are doing paging at the data-sire (database) side then you have total at the data-sore side - you may use the same SP that returns a page-full of records to return the total of all records. If you are retrieving all records and doing paging at the web server side then you may use the retrieve data-source to do the totaling.
From optimization perspective, you can compute the total once and store it in the view-state.
If you wish to show the footer on the last row then you can use ShowFooter - set it to true only on the last page.
All you need to do is check whether your row is in the current page and do the calculation.
For example, something like this:
if (e.Row.RowType == DataControlRowType.DataRow)
{
decimal rowTotal = Convert.ToDecimal
(DataBinder.Eval(e.Row.DataItem, "DC_No_Decimal"));
if (e.Row.DataItemIndex >= inderGrid.PageIndex * inderGrid.PageSize
&& e.Row.DataItemIndex < inderGrid.PageIndex * inderGrid.PageSize + inderGrid.PageSize)
grdTotal += rowTotal;
}
Try this,
using System.Linq;
dt.AsEnumerable().Select(x => x.Field<decimal>("DC_No_Decimal")).Sum().ToString();
you can use the code like this for get sum at the footer
gv.DataSource = dt;
gv.Columns[2].FooterText = dt.Rows.Count > 0 ? dt.AsEnumerable().Select(x => x.Field<decimal>("DC_No_Decimal")).Sum().ToString() : "";
gv.DataBind();

gridview with footer row total in the final page of the grid

protected void inderGrid_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
decimal rowTotal = Convert.ToDecimal
(DataBinder.Eval(e.Row.DataItem, "DC_No_Decimal"));
//grdTotal = grdTotal + rowTotal;
grdTotal += rowTotal;
}
if (e.Row.RowType == DataControlRowType.Footer)
{
Label lbl = (Label)e.Row.FindControl("lblTotal");
e.Row.Cells[3].Text = grdTotal.ToString("c");
//lbl.Text = grdTotal.ToString("c");
}
}
from the above code i m getting total for every page in the grid view. Instead of getting total to every page i need all page total at the end of the grid view footer. Help Immediatly.
Thanks in advance
If you want the total of ALL pages, and for the footer to only appear on the last page, then you can't calculate the totals how you are doing.
At the moment your looping through every row on the gridview. If you are using paging the gridview won't be showing all the rows, so the total won't be correct.
Are you paging with a PagedDataSource or are you limiting the records returned from SQL etc? If you are using a DataSet and a PagedDataSource you'll be able to find the total from the DataSet (as this will contain all the records). Otherwise, you'll have to create a second query to calculate the total.
Then in terms of displaying the values in the footer, you'll have to add an IF statement to your ItemDataBound event to only display this if its the final page.
If you trying to display the record summery, please look this one about Displaying Summary Information in the GridView's Footer
What I do is setup the following in the code behind (This is just an example column):
int totalCallsTaken = 0;
public int CallsTaken(int value)
{
totalCallsTaken += value;
return value;
}
public int CallsTakenTotal()
{
return totalCallsTaken;
}
Then in the ASPX page I put the following template field in:
<asp:TemplateField HeaderText="Calls Taken" FooterStyle-Font-Bold="true">
<ItemTemplate>
<%#CallsTaken(Convert.ToInt32(Eval("CallsTakenCount").ToString())).ToString("N0")%>
</ItemTemplate>
<FooterTemplate>
<%#CallsTakenTotal().ToString("N0")%>
</FooterTemplate>
</asp:TemplateField>
I hope that helps, Ian.
Noddy but you can try one more check in the if condition.
if(e.Row.RowType == DataControlRowType.Footer && inderGrid.PageCount == inderGrid.PageIndex + 1)
{
//code here.
}
// Try this
if(e.Row.RowType == DataControlRowType.Footer && inderGrid.PageCount == inderGrid.PageIndex + 1)
{
for (int i=0; i< inderGrid.Rows.Count; i++)
{
var currentRowCellVal = Convert.ToDecimal(inderGrid.Rows[i].Cells[0].Text);
grdTotal += currentRowCellVal;
}
e.Row.Cells[3].Text = grdTotal.ToString("c");
}
Just to be certain I'm understanding, you're saying you have a grid with say 100 items, but only 25 are shown at any given time. Then you want the footer to only display the sum of those 25 items that are displayed on the page.
There's a couple of options that you can do here for this:
1) Use JavaScript to calculate the total after the page has been rendered.
2) use intelligent SQL to only return those particular rows that you're wanting to display on the grid--and then keep your grid the same
3) calculate the visible rows in your code, and only add them when you need them. Remember, you know in the code behind which Grid.PageIndex you're on as well as how many items each page has. With this knowledge, you should be able to determine via the row index if any given datarow will be rendered to the screen.
You need to generate all records total using the actual data.
If you are doing paging at the data-sire (database) side then you have total at the data-sore side - you may use the same SP that returns a page-full of records to return the total of all records. If you are retrieving all records and doing paging at the web server side then you may use the retrieve data-source to do the totaling.
From optimization perspective, you can compute the total once and store it in the view-state.
If you wish to show the footer on the last row then you can use ShowFooter - set it to true only on the last page.
All you need to do is check whether your row is in the current page and do the calculation.
For example, something like this:
if (e.Row.RowType == DataControlRowType.DataRow)
{
decimal rowTotal = Convert.ToDecimal
(DataBinder.Eval(e.Row.DataItem, "DC_No_Decimal"));
if (e.Row.DataItemIndex >= inderGrid.PageIndex * inderGrid.PageSize
&& e.Row.DataItemIndex < inderGrid.PageIndex * inderGrid.PageSize + inderGrid.PageSize)
grdTotal += rowTotal;
}
Try this,
using System.Linq;
dt.AsEnumerable().Select(x => x.Field<decimal>("DC_No_Decimal")).Sum().ToString();
you can use the code like this for get sum at the footer
gv.DataSource = dt;
gv.Columns[2].FooterText = dt.Rows.Count > 0 ? dt.AsEnumerable().Select(x => x.Field<decimal>("DC_No_Decimal")).Sum().ToString() : "";
gv.DataBind();

GridView no column present even after DataBind()

I have a DataView that was already populated with data (Verified this to be true).
I then set the DataSource of my GridView to that DataView and called the .DataBind() Function.
Right after binding, I checked the column count of my GridView (grid.Columns.Count) and it shows 0. But it is showing the right output with 15 columns.
Also, accessing a column using its index will throw an exception.
How can I access the column then?
Thanks!
EDIT -- Additional Info:
I actually need to add a "glyph" (UP/DOWN arrow) in the column header to show what column are being sorted and its direction. The code below is what I am using. Problem is, the Columns.Count is always zero.
for (int i = 0; i < dgData.Columns.Count; i++)
{
string colExpr = dgData.Columns[i].SortExpression;
if (colExpr != "" && colExpr == dgData.SortExpression)
item.Cells[i].Controls.Add(glyph);
}
Edit
Try this, it's a little fugly as it relies on testing the linkbutton text against the GridView SortExpression. The Gridview ID is "test"
protected void test_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.Header)
{
foreach (TableCell tc in e.Row.Cells)
{
if(test.SortExpression.Contains( (tc.Controls[0] as LinkButton).Text ))
tc.Controls.Add( glyph )
}
}
}
I don't think the columns collection is set if you are auto generating the columns...
You could check the Row.Cells.Count or if you need column names, grab the HeaderRow, and iterate through the Cells & grab their .Text Value.
If the GridView is sortable (e.g. has clickable links in the header, then to get the column names you'll need to check
foreach(Row r in GridView.Rows)
{
if(r.RowType == HeaderRow)
{
r.Cells[0].Controls[0]; //Link Control is here.
}
}

Resources