Passing entire Container.DataItem row to code behind - c#

This question relates to ASP.Net 3.5 and C#
I'm building an RSS Feed from a database containing a lot of columns.
I need to format the data in a particular node and doing it inline is going to be very messy.
I'm aware I can pass all the parameters individually to a subroutine
<%# formatAddress(Container.DataItem["propertyName"],
Container.DataItem["propertyNumber"], ... ) %>
As there's going to be up to 20 of these columns, I'd rather pass the entire row.
<%# formatAddress(Container.DataItem) %>
This would be ideal then I can pick out the columns I want in code behind:
protected string FormattedAddress(object row)
{
DataRowView data = (DataRowView)row;
StringBuilder Address = new StringBuilder();
string Postcode = data["propertyPostcode"];
...
return Address.ToString();
}
I'm getting the error Unable to cast object of type 'System.Data.Common.DataRecordInternal' to type 'System.Data.DataRowView'.
Previously, I was using protected string FormattedAddress(DataRowView row) but that didn't work either.
Any clues?

Eventually found a couple of examples which led me to realise I should be casting to DbDataRecord.
I'm still passing <%# formattedAddress(Container.DataItem) %> but my function is now as follows:
protected string FormattedAddress(object dataItem)
{
DbDataRecord data = (DbDataRecord)dataItem;
string Postcode = data.GetValue(
data.GetOrdinal("propertyPostcode")).ToString();
...
return NicelyFormattedAddress;
}
Is this the best way to handle the data?

Related

In ASP.NET can I change the values of some fields from a DB bound to a grid in the binding process?

I have the following code behind:
List<Articles> articles = (from em in db.Articles orderby em.ReceivedDate descending select em).ToList();
gvArticles.DataSource = articles;
gvArticles.DataBind();
Where gvArticles is a GridView. The following is the asp code within that grid:
<p style='font-weight:bold;font-size:17px;color:black;'>
<asp:Label ID="lblDate" runat="server" Text='<%#Eval("datePrinted").ToString() %>'></asp:Label>
</p>
<asp:Label ID="lblBody" runat="server" Text= '<%#Eval("Content")%>'></asp:Label>
... that will clearly show from the DB the fields 'datePrinted' and 'Content'
Is there any way that I can show other value in 'datePrinted' based on a condition? For example, if 'datePrinted' is before 1/1/1990 then put "N/A" instead of the field 'datePrinted' itself?
Or a bit more complex, put "-" if the day is the same as the previous record (time can be different, just day/month/year is the same)?
Of course I could calculate all of that and store it in the DB, so I will pull other fields from the DB, but that sounds extremely inefficient, for any future condition create a new field in the DB. So are there any other ways to achieve the same results?
Ideally a condition, formula, or function that translates values from the DB before binding them to the grid is the most desirable solution.
Any idea?
Create a method in your code behind. Call that method parsing your value instead of using eval.
E.g
public static string ConvertDate(DateTime date)
{
if (date < new DateTime(1990, 1,1) )
{
return "N/A";
}
else
{
return date.ToString("dd/MM/yyyy");
}
}
Place this method where you placed your Eval("datePrinted").
<asp:Label ID="lblDate" runat="server" Text='<%# ConvertDate(Convert.ToDateTime(Eval("datePrinted")) ) %>'></asp:Label>
After days trying to figure out what to do, I found one answer just after posting this question. Basically I realized that you can process the List before assign it to the binding. So my second sample, I did this after loading the list and before assign it to the grid datasource:
string prevDate = "";
foreach(Article myArticle in articles) {
if (((DateTime)myArticle.ReceivedDate).ToShortDateString() != prevDate) {
prevDate = ((DateTime)myMail.ReceivedDate).ToShortDateString();
myArticle.ReceivedDate = prevDate;
}
else myArticle.ReceivedDate = "-";
}
Now, I am not a LINQ expert, if anyone can do the same code in the line where the DB is loaded in the List, I would appreciate it.

Dropdownlist data binding inside detailsview in asp.net

I have detailsview that will be used to edit customer records. Inside this detailsview, I have a dropdownlist that shows list of countries.
I have a table called CountryList that will populate list of countries to the above dropdownlist.
User can edit and save data without any issue.
But, assume that customer record has the country selected as "Australia" and if I delete Australia from the CountryList and try to edit the customer inside the details view, I am getting below error.
SelectedValue which is invalid because it does not exist in the list of items
I know the reason because the
SelectedValue='<%# Bind("Country") %>'
and it can't find it in the list.
So my question is, how to overcome this issue ?
After searching the web, I found that I can override the Databind but I am not sure how to do this. Have no idea how to override and can someone please give me sample code ?
Also is there any other solution for this such as validate it before set ?
Thank you.
you can call function before selecting value as follows:
SelectedValue='<%# CheckCountry(Eval("Country"))%>'
in aspx.cs file create function as follows which will check whether country is exist in list or not if it is not there then will show default value as selected
public string CheckCountry(string country)
{
// add your logic to check contry in list
// and return value as per result if it is exist
// return country name else return default value
}
Try checking the existence of the country in your list(dataTable,DataSet etc) before binding ,some thing like
DataTable dtPs=getAvailableCountries();
string countryName = "Australia";
DataRow foundRow = dtPs.Rows.Find(countryName);
if(foundRow != null) {
//You have it ...
bindTheDropdown();
}else{
//You dont have it ...
dontBindTheDropdown();
}

Loop thru a nested collection in a repeater control

I have a list object
List<Documents>
, and inside that I have another list list of accounts.
List<Accounts>
From my codebehind I connect List to a repeater control
rptDocumentListings.DataSource = List<Documents>;
rptDocumentListings.DataBind();
While the repeater loops thru each item in List I want it to also loop thru each nest list of accounts, and then render out with tags. Here is what I've tried so far:
//in the dataRepeater
<%# parseAccountNumbers(Eval("Accounts"))%>
//method in codebehind
public string parseAccountNumbers(List<Account> accounts)
{
string allAccounts = string.Empty;
foreach (var item in accounts)
{
allAccounts += string.Format("{0}<br />", item.AccountNumber);
}
return allAccounts;
}
The error I get is 'Cannot convert from from 'Object' to 'System.Collections.List'
Can someone please point me in the right direction? Thanks in advance.
Change
<%# parseAccountNumbers(Eval("Accounts"))%>
To
<%# parseAccountNumbers((List<Account>)Eval("Accounts"))%>
DataBinder.Eval returns an Object and your method expects a List<Account>.
Another idea: instead of parseAccountNumbers(...)Create a public property (if possible) inside Documents class like:
public string AccountNumbers
{
return Accounts.Aggregate("", (current, account) => current + (account.AccountNumber + "<br/>"));
}
and use it as a datafield like:
<asp:Boundfield DataField="AccountNumbers" HeaderText="Account#" />

Trying to get some byte array from a helper function in to an attribute

I am trying to get some binary data in to the "DataValue" attribute as in the below control.
<telerik:RadBinaryImage runat="server" ID="RadBinaryImage1" AutoAdjustImageControlSize="false"
DataValue='<%# getBinary(); %>' />
the DataValue field accepts a byte[] .
my code behind looks like this
public byte[] getBinary()
{
TestDBDataContext db = new TestDBDataContext();
var r = (from a in db.ImageTables where a.Id == 22 select a).FirstOrDefault();
byte[] bt = r.Thumbnail.ToArray();
return bt;
}
NOTE: The control is inside a repeater control
How could I get byte array in to the DataValue attribute on the above control ?
The error message and your markup are not consistent: in your markup you use data binding syntax <%# ... %> (with the # at the beginning) but the error message reports a code block <% ... %>.
Using a code block inside a control attribute is not valid ASP.NET, the text is interpreted literally, and thus is not recognized as a byte array. Make sure you use data binding syntax, can you double check?

Retrieve DataItem from RepeaterItem after databinding (during an event handler)

I'm trying to find a way to to do something that I think must be possible but I'm just missing the point on - so hopefully someone can give me a bit of a nudge :)
I'm utilising databinding in ASP.NET (viewstate turned off - so using controlstate for a few things here and there) to render a repeater (repeaterPriceClasses) that has a repeater within each itemtemplate (repeaterPriceBands). Basically this renders a table out of some text and a dropdownlist in each cell.
I'm trying to find a way to enumerate the repeaterOuter inside the event handler of a button to give me a list of all of the originally bound elements that have now got a dropdownlist with a value of >0, along with what that value is.
public Dictionary<Price, int> SelectedPrices
{
get
{
var sel = new Dictionary<Price, int>();
foreach(RepeaterItem itemClass in repeaterPriceClasses.Items)
{
var repeaterPriceBands = itemClass.FindControl("repeaterPriceBands") as Repeater;
foreach(RepeaterItem itemBand in repeaterPriceBands.Items)
{
var context = (Price)itemBand.DataItem;
var listQty = itemBand.FindControl("listQty") as DropDownList;
if(listQty.SelectedValue.ToInt32() > 0)
{
sel.Add(context, listQty.SelectedValue.ToInt32());
}
}
}
return sel;
}
}
Now this fails because the itemBand.DataItem is always null after databinding has finished.
What technique should I use to get around this?
Hidden field with primary keys in it
(not ideal as can be abused and adds
weight to the page)
Lookup from
original cached data based on indexes
(just seems wrong)
or something
else/better...?
EDIT: Is there any more information that I could provide to help this get answered?
You can try adding extra attributes to your HTML elements in the ItemDataBound event when DataItem is available.
ddlSomething.Attributes["Attribute1"] = dataItemObject.PropertyName;
[Edit]
Apart from using attributes, you can render some array containing JSON objects like this, for each row.
var repeaterItemAttributes = [ { Prop1: val1, Prop2: val2, ... }, { ... }, ... ]
So, by using this, you won't have to render the attributes, and your code will be XHTML compliant too (tho its not required). You can then loop through the object array and read any property you like. You can also apply the light encryption you were talking about to the property values.
[/Edit]

Categories

Resources