gridview data binding itemptemplate field - asp.net

I have a data gridview which gathers data from database. The grid has 4 columns. one of the columns is the city name. In the sql code, I select the city code rather than city name.
I have converted this column into template field. In the edit mode, i was able to place drop down list and provide data binding in order for the user to be able to select the city.
however in itemtemplate mode i have label field. how can i provide data binding in which can pick up the data from database?

You can achieve it in some sort of following way(s)
First approach
Declare your datasource such as SQL Data Source / Object Data Source including the required value fields using sub queries or joins and assign it to the label as other values are being assigned.
Second approach
Declare the ItemTemplate as
<ItemTemplate>
<asp:Label ID="lblCity" runat="server" Text='<%# LookupCity(DataBinder.Eval(Container.DataItem, "CityCode")) %>'></asp:Label>
</ItemTemplate>
In the code-behind declare the LookupCity function as
protected string LookupCity(object idObj)
{
string CityCode = idObj.ToString();
if (string.IsNullOrEmpty(CityCode))
// return if CityCode is not valid value
return null;
// find the corresponding name from SQL Data Source named SQLDS_City
IEnumerator CityEnum = SQLDS_City.Select(new DataSourceSelectArguments()).GetEnumerator();
// loop through enum until required value is not found
while (CityEnum.MoveNext())
{
DataRowView row = CityEnum.Current as DataRowView;
if ((string)row["CityCode"].ToString() == CityCode)
return string.Concat(row["CityName"].ToString());
}
// return code if it is not found in the enum
return CityCode;
}
Third approach
You may use the DropDownList control for ItemTemplate also. An example can be found here Bind-DropDownList-in-ItemTemplate-of-TemplateField-in-ASPNet-GridView. To restrict the user from changing the value in ItemTemplate you may keep it disabled for display purpose only.

Related

GridView control in ASP.NET is displaying data from DataSet, but Columns collection is EMPTY, so can't access/change any properties

I'm teaching myself C# in VS2012 on 4.5 framework and loving it, but this is (continuing to) baffle me, so I apologize if I'm missing something obvious. I have done some new testing (since my original post 3/23) and am now more confused.
I added a DataSet item to my project called reviews.xsd.
I programmatically fill the DataSet with all data from Review table, then add two new fields to the Columns collection, then use EntityFramework to join to the Book table to add the data for those two new fields. I programmatically link the GridView control (dgvReviews) to this populated DataSet and everything displays great when I open the page, so all the data population into the DataSet and the linked GridView control is working great.
HOWEVER, the Columns collection of the GridView control is strangely EMPTY, so I can't change the styles of the columns or hide or show them using the Visible property. The Columns collection of the DataSet that populates the GridView is complete those values are accessible normally.
I have set numerous Watches to look at other properties of the GridView control and they seem to be populating normally: the Rows collection, for example, displays the values through the Watch window, but all access to the Columns collection displays "Enumeration yielded no results," even though the data is all displaying correctly (when I don't try to access the Columns collection explicitly in code).
I'm a beginning programmer so any advice would be much appreciated.
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
// create reviews dataset, populate with standard data from Review table
reviews reviewDataSet = new reviews();
reviewsTableAdapters.reviewTableAdapter reviewDataAdapter = new reviewsTableAdapters.reviewTableAdapter();
reviewDataAdapter.Fill(reviewDataSet.review);
reviewDataSet.review.Columns.Add("bookName", typeof(string));
reviewDataSet.review.Columns.Add("bookDescription", typeof(string));
reviewDataSet.review.Columns["bookName"].SetOrdinal(3);
reviewDataSet.review.Columns["bookDescription"].SetOrdinal(4);
// use EF to populate data from Book table into new bookName and bookDescription fields
bookReviewsEntities bookConnection = new bookReviewsEntities();
foreach (reviews.reviewRow reviewEntry in reviewDataSet.review)
{
int bookNumber = reviewEntry.bookID;
var bookLookup = (from book in bookConnection.books
where book.bookID == bookNumber
select book).ToList();
reviewEntry.BeginEdit();
reviewEntry["bookName"] = bookLookup[0].title;
reviewEntry["bookDescription"] = bookLookup[0].description;
reviewEntry.EndEdit();
}
bookConnection.Dispose();
// next 2 lines verify the Columns collection of the DataSet is working fine
string test1 = reviewDataSet.review.Columns[0].ToString();
string test2 = reviewDataSet.review.Columns[1].ToString();
dgvReviews.DataSource = reviewDataSet.review;
dgvReviews.DataBind();
// everything runs and displays normally if next line is commented out
dgvReviews.Columns[0].Visible = false; // crashes with "index out of range" since "Columns" collection is empty
}
}
For the Columns property to be accessible you need to list your columns in your GridView declaration like below and disable the auto generation of columns with AutoGenerateColumns="false"
<Columns>
<asp:BoundField DataField ="Id" />
<asp:BoundField DataField ="First" />
<asp:BoundField DataField ="LastName" />
</Columns>
When Columns are auto generated you can't access the Columns property.

Binding alias-named column to gridview in ASP.Net

I am using .Net 3.5. I have a site that I have been using gridview controls on. Basically, it is a standard gridview, but with AutoGenerateColumns turned off in favor of creating our own columns via ItemTemplate. Here is an example of one of our custom columns:
<asp:TemplateField HeaderText="Physician" ItemStyle-Width="70px" HeaderStyle-Width="70">
<ItemTemplate>
<asp:Label ID="lblPhysician" runat="server" Text='<%# Bind("LastName") %>' ></asp:Label>
</ItemTemplate>
</asp:TemplateField>
In code behind, I fill a datatable based on an SQL query, and set it as the gridview datasource, and the label is normally populated based on the Bind function seen above during Postback. However, I have a SQL query that utilizes Alias names now. The query is rather large but here is an example:
SELECT LastName, COUNT(Case WHEN <condition> THEN 1 END) AS ABC
FROM tablename WHERE <condition> Group By LastName
The problem is that I cannot use the Bind command on ABC as I use it for LastName. Nothing shows up in the gridview except LastName, even though data is returned for the alias columns. If I set AutoGenerateColumns to true, the gridview is binded with all the correct data, but this is not the way we need the page to work. What am I missing that is not allowing me to bind a column value manually to a control via it's alias name?
Thanks, and let me know if further clarification is needed!
You can grab it from the row on data bound; add an event handler, an in that handler do:
.. Grid_RowDataBound(..)
{
var abc = DataBinder.Eval(e.Item.DataItem, "ABC")
if (abc == null)
((Label)e.Item.FindControl("lblPhysician")).Visible = false;
}
There may be some syntaxes that are off but the gist is that you can extract the field from the data item, and do something with it programmably.
You could also bind it in the item template using a hidden field, or stick it in the DataKeys collection too.

Bind a users role to dropdown?

I'm trying to bind a selected user's role to a dropdown-list.
The purpose of this is to be able to change said user's role.
I'm attempting this inside a formview hooked up to a linqdatasource which contains a row from the aspnet_User table.
The dropdown list is hooked up to a linqdatasource of all the roles in the aspnet_Roles table (with DataValueField="RoleID", DataTextField="RoleName").
I figured it would be possible with something like:
SelectedValue='<%# Bind("aspnet_UsersInRole[0].aspnet_Role.RoleID") %>'
But this throws a parser exception, about the bind call not being correctly formatted.
The roles are there, they show up when I remove the SelectedValue
Can anyone point me in the right direction?
If you are binding aspnet_roles table to the drop down, then why does the code sample use aspnet_usersinrole? Instead, if you want to bind to aspnet_role object, do:
SelectedValue='<%# Bind("RoleID") %>'
Instead; that will hookup to the right property. If you want to bind aspnet_usersinrole, if possible in the LINQDataSource, from the resuling aspnet_usersinrole, do a select operation to select the aspnet_role object instead for this.
Solved - I ended up just making a method in the codebehind which returned the roleID, like so:
public Guid GetRoleID(Guid userID) {
DBDataContext db = new DBDataContext();
aspnet_User user = db.aspnet_Users.SingleOrDefault(o => o.UserId == userID);
return user.aspnet_UsersInRoles[0].aspnet_Role.RoleId;
}
and then in the markup do:
SelectedValue='<%# GetRoleID((Guid)Eval("UserID")) %>'

Sorting an asp:ListView bound to an EntityDataSource

I have an asp:ListView control on an ASP.NET page. It is bound to an EntityDataSource which is setup this way:
<asp:EntityDataSource ID="EntityDataSourceOrders" runat="server"
ConnectionString="name=EntitiesContext"
DefaultContainerName="EntitiesContext" EntitySetName="SOrder"
Include="Address"
EnableDelete="True" EnableInsert="True"
EnableUpdate="True">
</asp:EntityDataSource>
In SQL Server there are two tables, SOrder and Address. SOrder has a foreign key AddressID to the Address table ("an order has one address"). The address has an alphanumeric field "Name1".
In the LayoutTemplate of the ListView is a link button to sort the orders in the list by Name1 of the order's address:
<asp:LinkButton runat="server" ID="SortButtonName" Text="Name"
CommandName="Sort" CommandArgument="Address.Name1" />
If I click this button I get an EntitySqlException telling me that "'Address.Name1' could not be resolved in the current context".
Sorting by a "flat" field of the order table - for instance "OrderCode" - works:
<asp:LinkButton runat="server" ID="SortButtonOrderCode" Text="Order number"
CommandName="Sort" CommandArgument="OrderCode" />
So the exception occurs only when I try to sort by an related field in another table. I was expecting that with the Include="Address" property of the EntityDataSource sorting by fields of the related address should be possible, but it seems not.
I've made a test hack to check the query I expect the EntityDataSource to create internally:
With Linq to Entities:
using (EntitiesContext ctx = new EntitiesContext())
{
var result = from order in ctx.SOrder.Include("Address")
orderby order.Address.Name1
select order;
foreach (SOrder x in result)
{
string test=x.Address.Name1;
}
}
Or with Entity SQL:
string queryString = #"SELECT VALUE x FROM SOrder AS x
Order By x.Address.Name1";
using (EntitiesContext ctx = new EntitiesContext())
{
ObjectQuery<SOrder> query =
new ObjectQuery<SOrder>(queryString, ctx).Include("Address");
foreach (SOrder x in query.Execute(MergeOption.AppendOnly))
{
string test=x.Address.Name1;
}
}
Both works! I get a sorted result.
Now I am a bit lost how I get this sort operation working in the ListView. Does somebody have an idea what I am doing wrong here?
Thank you in advance!
I found the solution myself. It's all a matter of three missing characters: In my code above, this ...
<asp:LinkButton runat="server" ID="SortButtonName" Text="Name"
CommandName="Sort" CommandArgument="Address.Name1" />
...is WRONG and has to be replaced by:
<asp:LinkButton runat="server" ID="SortButtonName" Text="Name"
CommandName="Sort" CommandArgument="it.Address.Name1" />
Using "it." for properties of related objects seems to be necessary in contrast to flat fields. Therefore in the second example above both ways are possible:
CommandArgument="it.OrderCode" // works
CommandArgument="OrderCode" // works as well
The same for "object identities" (primary key fields) of related objects:
CommandArgument="it.Address.AddressID" // works
CommandArgument="Address.AddressID" // works as well
But again for related properties which are not identities:
CommandArgument="it.Address.Name1" // works
CommandArgument="Address.Name1" // does NOT work
Crazy, the only place where I could find (accidentally) an indication to this solution, is this video:
How Do I Use the Entity Data Source?
...especially at around 9:40 min of the video.
Associated classes may wont work CommandArguments or eg DropDownList's DataTextField value. You may use Data Transfer Objects for listing and sorting
public class OrderDTO
{
public string AddressName1 {get;set;}
}
using (EntitiesContext ctx = new EntitiesContext())
{
var result = from order in ctx.SOrder
let dto = new OrderDTO
{
AddressName1 = order.Address.Name1
//bla bla
};
orderby dto.AddressName1
select dto;
}

ASP.NET AutoCompleteExtender-enabled TextBox's TextChanged-event doesn't fire when selecting certain kind of item from AutoCompleteExtender (whew...)

Today i faced a pretty weird problem, made of a stored procedure, an autocompleteextender and event handling. If anyone can suggest a concise title for the following saga, please do!
First i'll try to introduce the players (some parts are a bit abridged) and then the scenarios. Environment is VS2008, C#, SQL Server 2005 and ASP.NET.
DB table:
TABLE (
SomeNbr INT,
SomeAbbr VARCHAR(10),
Name VARCHAR(30)
)
StoredProcedure:
Reads the table above and returns something like this:
DECLARE #Results TABLE
(
SomeNbr INT,
--Composite CHAR(50), -- voodoo magic starts here...
Composite VARCHAR(50)
)
Composite-field of the return table is made of SomeNbr, SomeAbbr and Name fields. They are appended together and separated by commas (f.ex. "number, abbreviation, name").
Stored Procedure is used to retrieve a set of rows from db, and these are put into a typed datatable. This datatable is then stored in a session variable. DataTable's XSD-Schema has datatype String for the "Composite"-field.
!Important! For some rows in the db, "Name"-field contains the actual value and rpadding (made of spaces) up to the maximum length. Other just contain the name with no rpadding.
User interface (ASPX-page with codebehind):
I have extended textbox-control to include an AutoCompleteExtender from AJAX Control Toolkit. Control is declared as follows:
<ajx:TextControl ID="txtControl"
runat="server"
AutoPostBack="true"
UseAutoComplete="true"
ServiceMethod="GetItems"
MinimumPrefixLength="1" />
There are some additional basic textboxes on the ui.
CodeBehind:
AutoCompleteExtender uses the following webmethod:
[System.Web.Services.WebMethod]
public static string[] GetItems(string prefixText, int count)
{
try
{
return Utility.GetMatchingStrings(_DataTableInSession, prefixText);
}
catch (Exception ex)
{
throw;
}
}
GetMatchingStrings(...)-method compares preFixText against all datarows in _DataTableInSession, and returns an array of matching strings. Comparison is done with the datarows' "Composite"-fields.
In codebehind, the event handler gets set:
extendedTextControl.Control.TextChanged += PopulateTextControls;
, and:
private void PopulateTextControls(object sender, EventArgs e)
{
// Read Text-property from extended textcontrol
string str = extendedTextControl.Text;
// Split string by commas and take parts into an array
string[] arrStr = SplitString(",", str);
// Set the values in array to Text-properties of TextBoxes
SetValuesToTextBoxes(arrStr, _TextBoxes);
}
Scenarios
Everything seems to be fine, the extended TextControl is working as it is supposed to and generates the selectable list below the textbox.
Scenario 1:
Now, when user selects an item from autocompletion list the following things happen:
Selected string is set to Text-property of the extended textcontrol
textcontrol's autopostback happens
on postback, an eventhandler is registered for textcontrol's TextChanged-event
TextChanged-event is fired and other textboxes get filled with data as expected
For this scenario to happen, the "Composite"-field in the typed datarow has to be something like this:
"10", "10, ABBR, Some Name Goes Here____..._" (<- spaces replaced with underscores)
If the datarow is more like this:
"10", "10, ABBR, Some Name Goes Here"
then we'll go to...
Scenario 2:
The above is a sort of happy day -scenario :-)
If the matching datarow is made from a row in db where "Name"-field is not padded with spaces up to the maximum length (VARCHAR(50)), then the TextChanged-event does not get fired.
I spent a good few hours trying to figure out everything above. First i was quite confused that why the **** selecting some of the items in autocompletion list do work, and some don't.
When i realized to look at the datatable's contents, i saw that some rows had the padding and others did not. After that i tried to ltrim(rtrim()) everything in the SP's return table, and none of the items worked anymore.
After that i tried to set the SP's return value to CHAR(50) instead of VARCHAR(50), and that fixed it.
Question:
What is going on in my application? Why doesn't the registered event fire? It's like TextChanged would only work for string of certain length (max length of the VARCHAR(50)), but how would that be possible?
Problem is solved, but i have no idea why. Just another day at the office, i suppose :-)
I'll be happy to provide additional data and clarifications!
Edit 1: Added note about spaces and underscores within the datarow.
After that i tried to set the SP's return value to CHAR(50) instead of VARCHAR(50), and that fixed it.
I didn't understand the whole scenario but I would look at the CHAR(50) vs. VARCHAR(50) issue. I also do not know what "WebOlkiUtility.GetMatchingStrings" does.
declare #text char(50)
select #text = 'test'
select #text
declare #text2 varchar(50)
select #text2 = 'test2'
select #text2
-- output --
CHAR(50): 'test '
VARCHAR(59): 'test2'
CHAR(50) returns always 50 Character!
BTW: Why do you attach the event this way?
if (GetPostBackingControlId() == extendedTextControl.ID)
{
extendedTextControl.Control.TextChanged += PopulateTextControls;
}
You could attach it always. In your ASPX file or in the Page_Init Method.

Resources