How are DataTextField and DataValueFields evaluated - asp.net

For a data bound control it is common scenario where we provide data text field and data value field ( in simple controls like Dropdownlist) but more fields in controls like Gridview. Generally the datasource is of type IEnumerable.
How does the control internally process these values or rather how do they get the value from the data source without knowing what kind of datasource they are dealing with.
Can someone explain with code how the controls evaluate these fields from the data source.

Typically, the data-bound control (or concerned components such as
DataControlField in GridView) will handle DataBinding event.
Within event handler, the data item that is being currently bound (e.g. DataRowView or entity instance) is retrieved. This is done via DataBinder.GetDataItem passing the actual control or control's NamingContainer. For example, if you are implementing a lower level control such as DataControlField for higher level data-bound control such as GridView then it would handle data-binding of a cell control and hence it will use cell's naming container to pass to DataBinder.GetDataItem method which uses current data binding context to get the same.
Once the data item object is retrieved, one need to evaluate the given data-binding expression against it to get the actual value and apply any formatting as per different properties set to the control/component. The most simple way is to use DataBinder.Eval overload. However, one may use the more efficient ways - for example, say DataField string is going to be only property name then you may look and cache the property descriptor and then use the same against different data items.
I will suggest you to use tool such as Reflector to inspect relevant control's code to get the better idea.

I never knew i could find this information so easily and LLyod was in fact wrong on using reflection to find data from a datasource. None of the data controls use it when i inspected through Reflector ;(
link that solved the problem
http://msdn.microsoft.com/en-us/library/ms366540.aspx
how you do it is below
protected override void PerformDataBinding(IEnumerable retrievedData)
{
base.PerformDataBinding(retrievedData);
// Verify data exists.
if (retrievedData != null)
{
string dataStr = String.Empty;
foreach (object dataItem in retrievedData)
{
if (DataTextField.Length > 0)
{
dataStr = DataBinder.GetPropertyValue(dataItem,
DataTextField, null);
}
else
{
PropertyDescriptorCollection props =
TypeDescriptor.GetProperties(dataItem);
if (props.Count >= 1)
{
if (null != props[0].GetValue(dataItem))
{
dataStr = props[0].GetValue(dataItem).ToString();
}
}
}
}
}
}
If the above code seem Greek and Latin , you will have to have a course on asp.net controls development to understand what is being done.

Related

How can I use Telerik RadGrid's filter expression to filter a custom List<Document> data object?

I am using Telerik RadGrid with LINQExpressions enabled.
I am binding this grid to data that I retrieve from Cache in NeedDataSource event as in code below.
The problem is, when I step through my code after inputting a filter, then I get this as filter expression - "(iif(MemberName == null, \"\", MemberName).ToString().StartsWith(\"T\"))". How would I use this with my listFromCache object? Perhaps, some LINQ trick? MemberName is a property of Document object. It seems its impossible to use the FilterExpression that I get in code-behind from RadGrid's object model.
I am using C#.
List<Document> listFromCache = Cache[dataCacheName] as List<Document>;
if (listFromCache != null)
{
//FILTER listFromCache here
}

Get UserControl from inside ControlCollection

So i am currently adding a collection of usercontrols to a Panel Collection.
Here is that code
foreach (IssuePoll poll in issuePollList)
{
IssuePollsUC issuePoll = (IssuePollsUC)Page.LoadControl("~/UserControls/IssuePollsUC.ascx");
issuePoll.LoadPoll(poll, false, politician.PoliticianID);
pnlUnFinishedTest.Controls.Add(issuePoll);
}
I am trying to get those usercontrols so i can call a validate method and save method inside each of those controls. Here is the code i am using for that, but it is not working.
foreach (Control control in pnlUnFinishedTest.Controls)
{
IssuePollsUC issuePolls = (IssuePollsUC)control;
issuePolls.SavePollAnswer(appUser.User.PersonID);
}
I get an error message on the convert, it says
"Unable to cast object of type 'System.Web.UI.LiteralControl' to type 'UserControls.IssuePollsUC'"
EDIT: Looks like the problem lies in the fact that a Control cannot be convert into (User Control)
There are other controls in your panel other than your user control i.e. the literal that is causing the cast to fail. Try
foreach (Control control in pnlUnFinishedTest.Controls)
{
IssuePollsUC issuePolls = control as IssuePollsUC;
if(issuePolls != null)
{
issuePolls.SavePollAnswer(appUser.User.PersonID);
}
}
This will make it more type safe.
EDIT
Please note that you must add dynamic controls in the Page_Init event not Page_Load or anywhere else. I suspect your controls aren't even there - adding them not in Page_Init means that that they are not in ViewState and won't be present in any control collection.

Customizing output of datasource in repeater?

I have a Data Repeater hooked up to a datasource (datatable object). I need to change the output on the frontend for certain columns under certain conditions. What would be the most efficient way to do this?
I am currently trying to create the formatted output and assign it to another datatable and use that as the data source, but it seems overly complicated and something that would be hard to maintain.
Is there an easier way to manipulate column values for a datasource? I need the ability to check the previous and next rows for the source as that is a basis for some of the column values.
If you're talking about simple manipulation, the DataBinder.Eval method accepts a format string:
<%#Eval("SomeMoneyColumn", "{0:C}")%>
If the format string is not sufficient, you could create a method in the code-behind to handle the formatting, like this:
<%#FormatData(Eval("SomeColumn"))%>
In code-behind:
protected string FormatData(object data)
{
return String.Format("My name is {0}", data);
}
You can also use the ItemDataBound event too. Using this technique, you can still access the datasource object, in the case that your manipulation involves other data that is bound to the repeater.
protected void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
Label lblCtrl = e.Item.FindControl("SomeControl") as Label;
if (lblCtrl != null)
{
lblCtrl.Text = String.Format("My name is {0}", DataBinder.Eval(e.Item.DataItem, "SomeColumn"));
}
}
I don't think there's a way to do what you want on the client side easily w/o using special logic like you are doing now. If you are getting data from a database, you could potentially do all the data manipulation on the DB side and pass it along transparently to the front end.

Silverlight Custom Control and Databinding doesn't work properly in WP7

I'm trying to create my calendar control with databinding.
public partial class Calendar : UserControl
{
public static readonly DependencyProperty DateProperty =
DependencyProperty.Register("Date", typeof(DateTime),
typeof(Calendar), null);
public object Date
{
get { return GetValue(DateProperty); }
set
{
SetValue(DateProperty, value);
OnPropertyChanged("Date");
}
}
public Calendar()
{
// Required to initialize variables
InitializeComponent();
DayText.Text = ((DateTime)Date).ToString("dd");
MonthText.Text = ((DateTime)Date).ToString("MMM");
this.Loaded += new RoutedEventHandler(Calendar_Loaded);
this.GotFocus += new RoutedEventHandler(Calendar_Loaded);
}
void Calendar_Loaded(object sender, RoutedEventArgs e)
{
DayText.Text = ((DateTime)Date).ToString("dd");
MonthText.Text = ((DateTime)Date).ToString("MMM");
}
}
But When I create the listbox with this control, same calndar have the wrong date. I'm sure that the Date passed thorough databinding is correct but I don't understand why same calender show a different day (I'm noticed that is the day of a previous calendar control intance)
Thank you for supporting!
Hmm ... where do we start? Here's a few things I've noticed:
If you're using a dependency property, there's no need to call OnPropertyChanged from the Date property setter.
The dependency property declares the type as DateTime, but your public exposed property is of type object, which then requires you to cast it elsewhere.
If Calendar_Loaded is to be called in more situations than in response to the Loaded event (such as the GotFocus event, then I'd recommend that you call it something else, or create a method with a relevant name (e.g. UpdateDateParts) and call it from properly named separate event handlers.
Using fixed format specifiers when processing date strings does not localize well.
In addition to that, I'd suggest that you could implement the user interface in a manner that supports databinding (and re-templating) by using bindings and exposing the date parts of the Date dependency property instead of manually updating the Text property of some text blocks/boxes in event handlers. In fact, if you derive from Control instead of UserControl then you can create and actuall lookless control that has it's user interface defined by a style in themes\generic.xaml that can be re-defined by users of your control.
As for why the date is incorrect in different instances of your calendar control, we'd need to see some of your XAML/code to see how the control is being used and initialized to be able to provide a better answer. However, I thought the above was worth putting in an Answer, instead of trying to say it in a Comment.

Why is a child property getting overwritten when a Linq object is being updated?

I'm updating one object, and trying to update any child objects along with it.
Basically I'm handling the OnUpdating event of a LinqDataSource.
In the DataContext class I have the ObjectUpdate function (where right now I've just got a breakpoint so I can see the values...)
In the LinqDataSource.OnUpdating event e.NewObject.Child is null, which makes no sense whatsoever. I set that to a new value, but by the time I get to DataContext.ObjectUpdate NewObject.Child has been overwritten with the OLD value...
So somewhere between LinqDataSource.Updating and DataContext.UpdateObject it's populating the object with the old values... but I need the new ones.
Is there a way to fix that, or am I going to have a nervous breakdown?
I think I figured out the problem. After running LinqDataSource through .NET Reflector I noticed that:
1) It's the LinkDataSourceUpdateEventArguments.OriginalObject which is actually attached to the data context
2) values are copied from the NewObject into OriginalObject after OriginalObject is attached to the data context
What I don't understand is why the association properties are not copied. Maybe for the same reasons you can't serialize them?
The workaround is/was to handle the Updating event myself and do the actual submit instead of letting LinqDataSource handle that part.
void FormDataSource_Updating(object sender, LinqDataSourceUpdateEventArgs e)
{
var newObj = e.NewObject;
var table = FormContext.GetTable(e.NewObject.GetType());
if (BuildingObject != null)
BuildingObject(sender, new HeirarchicalBuildObjectEventArgs(newObj));
table.Attach(newObj, e.OriginalObject);
FormContext.SubmitChanges();
e.Cancel = true;
}

Resources