One
thing you get when you work with a customer base as wide as the one we have at
our company is a list of useful scripts. As no two customers want the exact
same thing, these little scripts come in handy.
Here is one that I have that changes an Integer into a Roman Numeral.
Let's show some code first:
private string
ConvertToRoman(int Value)
{
System.Text.StringBuilder sbRN = new
System.Text.StringBuilder();
//Start
high, and just replace the huge numbers with letters.
// 1111
-> M111 -> MC11 ->MCX1 -> MCXI
sbRN.Append(GenerateNumber(ref Value, 1000, 'M'));
sbRN.Append(GenerateNumber(ref Value, 500, 'D'));
sbRN.Append(GenerateNumber(ref Value, 100, 'C'));
sbRN.Append(GenerateNumber(ref Value, 50, 'L'));
sbRN.Append(GenerateNumber(ref Value, 10, 'X'));
sbRN.Append(GenerateNumber(ref Value, 5, 'V'));
sbRN.Append(GenerateNumber(ref Value, 1, 'I'));
//let's replace the some substrings like:
//IIII to
IV, VIV to IX, etc.
sbRN.Replace("IIII", "IV");
sbRN.Replace("VIV", "IX");
sbRN.Replace("XXXX", "XL");
sbRN.Replace("LXL", "XC");
sbRN.Replace("CCCC", "CD");
sbRN.Replace("DCD", "CM");
return (sbRN.ToString());
}
private string
GenerateNumber(ref int
value, int magnitude, char
letter)
{
System.Text.StringBuilder sbNumberString = new System.Text.StringBuilder();
while (value >= magnitude)
{
value -= magnitude;
sbNumberString.Append(letter);
}
return (sbNumberString.ToString());
}
Roman Numerals are pretty
straight forward once you get used to it. When you start with a number, say
1234, you will want the roman numeral: MCCXXXIV.
What this above script will
do is take in the 1000, set M to the letter to be returned, and take 1000
off of the Value (Passed by Reference). It will then take the 200 and return
CC, the 30 return XXX and the 4 which will return IIII. The IIII is then turned
into IV.
Pretty easy script to use,
and helpful if you ever need to produce Roman Numerals.
After browsing some of the posts on the asp.net forums a few people asked how to manipulate data in a Repeater Control. Here is a quick sample on how to do this.
A repeater is very powerful tool when you need to well... repeat something many times. If you are going to be repeating tabular data, use a DataGrid, for anything else use a Repeater.
First, A few notes on the Repeater:
The Repeater control allows you to create templates to define the layout of its content. The templates are:
- ItemTemplate - Use this template for elements that are rendered once per row of data.
- AlternatingItemTemplate- Use this template for elements that are rendered every other row of data. This allows you to alternate background colors, for example.
- HeaderTemplate- Use this template for elements that you want to render once before your ItemTemplate section.
- FooterTemplate- Use this template for elements that you want to render once after your ItemTemplate section.
- SeperatorTemplate- Use this template for elements to render between each row, such as line breaks.
After a repeater has been created, you might end up with something like this:
<asp:Repeater ID="rptApprovesr" runat="server" OnItemCommand="rptApprovesr_ItemCommand">
<HeaderTemplate>
<table border="0" cellpadding="0" cellspacing="0">
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<asp:ImageButton ID="imbDelete" CommandName="Delete" runat="server" ImageUrl="~/Images/button_delete.gif" /><td>
<asp:Literal ID="litStaffID" runat="server" Text='<%#DataBinder.Eval(Container.DataItem,"StaffID") %>' Visible="false" />
<asp:Literal ID="litApproverName" runat="server" Text='<%# DataBinder.Eval(Container.DataItem,"FullName") %>' /></td>
<td>
<asp:ImageButton ID="imbMoveDown" CommandName="MoveUp" runat="server" ImageUrl="~/Images/button_Up.gif" /><td>
<asp:ImageButton ID="imbMoveUp" CommandName="MoveDown" runat="server" ImageUrl="~/Images/button_down.gif" /><td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table></FooterTemplate>
</asp:Repeater>
Now that we have a repeater, we might want to manipulate some Data. We can use front end binding like you see above: Text='<%# DataBinder.Eval(Container.DataItem,"FullName") %>' or we can use the ItemDataBound event:
protected void rptApprovesr_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if(e.Item.DataItem != null)
{
//Change a the staff ID to 1.
((Literal)e.Item.FindControl("litStaffID")).Text = "1";
//Add the Approver Name
((Literal)e.Item.FindControl("litApproverName")).Text = ((((System.Data.DataRow)e.Item.DataItem)["ApproverName"]).ToString());
}
}
The ItemDataBound event is called for each "row" you are adding to the repeater. If your DataSource has 10 rows, this function will be called 11 times (the first time doesn't have a valid DataItem that's why I do the check at the front). You can see above that I can use the FindControl method with the actual control ID passed in to access that control.
I can also declare a control and manipulate it that way If I needed to do more than just change the text:
ImageButton imgDelete = (ImageButton)e.Item.FindControl("imbDelete");
imgDelete.CssClass = "Some Style Class";
imgDelete.AlternateText = "Delete something";
imgDelete.CommandName = "Delete";
When you do the above, you are creating a pointer reference to the actual object in the repeater. In other words you don't need to "Re-Add" the control to the repeater. Any changes you do to it will automatically be reflected to the current item (row) of the repeater.
An issue I had today stumped me for awhile. I had a repeater, and inside it I had a checkbox. When the checkbox was updated (checked / unchecked) I needed it to postback to the server. I found a solution. Here's my Repeater layout:
<asp:Repeater ID="rptApprovers" runat="server">
<HeaderTemplate><table></HeaderTemplate>
<ItemTemplate>
<tr>
<td style="width:180px;">
<asp:Literal ID="litStaffID" Text='<%#DataBinder.Eval(Container.DataItem,"StaffID") %>' runat="server" />
<asp:Literal ID="litStaffName" Text='<%#DataBinder.Eval(Container.DataItem,"FullName") %>' runat="server" />
</td>
<td style="width:100px;">
<asp:CheckBox ID="chkApproved" Checked='<%# Boolean.Parse(DataBinder.Eval(Container.DataItem,"Approved").ToString()) %>' OnCheckedChanged="chkApproved_CheckChanged" Text="Approved" runat="server" AutoPostBack="true" />
</td>
</tr>
</ItemTemplate>
<FooterTemplate></table></FooterTemplate>
</asp:Repeater>
What I needed was when clicking a checkbox, was for it to postback and update my Database.
Seeing the repeater does not have a way of tracking autopostbacks that happen from controls within the repeater, I had to do this within the checkboxes OnCheckChanged event:
To accomplish this I needed to do the following code:
CheckBox chkBox = (CheckBox)sender;
RepeaterItem riContainer = (RepeaterItem)chkBox.NamingContainer;
int intStaffID;
//Get the StaffID to update
intStaffID = Int32.Parse(((Literal)riContainer.FindControl("litStaffID")).Text);//Update the DataBase
I've never used the NamingContainer property before, and in this case it has turned out to be quite helpful.