Data Binding Error in cascading Drop downs in asp.net - asp.net

I have 2 drop down list within the edit item Template of a form view. The first drop down contains a lit of vehicle Makes and the second a list of Vehicle Models. The list of models needs to be filtered by the selection from the Makes drop down.
Here are the 2 Drop down List
<telerik:RadComboBox ID="RadComboBoxAssetMake" runat="server" DataTextField="AssetMakeName"
SelectedValue='<%# Bind("MakeId") %>' DataSourceID="odsAllAssetMakes" AutoPostBack="True" DataValueField="Id" Skin="Vista"
Width="212px" OnSelectedIndexChanged="RadComboBoxAssetMake_SelectedIndexChanged">
<telerik:Items>
<telerik:RadComboBoxItem Text="" Value="" />
</telerik:Items>
</telerik:RadComboBox>
<telerik:RadComboBox ID="RadComboBoxAssetModel" runat="server" DataTextField="AssetModelName"
SelectedValue='<%# Bind("ModelId") %>' DataSourceID="odsAssetModelByMake" DataValueField="Id" Skin="Vista" Width="212px">
<telerik:Items>
<telerik:RadComboBoxItem Text="" Value="" />
</telerik:Items>
</telerik:RadComboBox>
Initially I wanted to use a control select parameter on the object data source for the model Drop down. With the parameter getting the value from the Make drop down. However this doesn't seem to work as the select parameter on the object data source can't see the control with in the form view.
So now I am trying to use a session select parameter on the object data source.
<asp:ObjectDataSource runat="server" ID="odsAssetModelByMake" DataObjectTypeName="GPSO.Repository.AssetModel"
TypeName="GPSOnline.ATOMWebService" SelectMethod="GetAssetModelbyMake">
<SelectParameters>
<asp:SessionParameter DbType="Guid" SessionField="assetMakeId" Name="assetMakeId" />
</SelectParameters>
</asp:ObjectDataSource>
But now I get the this error "Databinding methods such as Eval(), XPath(), and Bind() can only be used in the context of a databound control." When I try to data bind the model drop down in the selected index changed method of the make drop down.
protected void RadComboBoxAssetMake_SelectedIndexChanged(object o, RadComboBoxSelectedIndexChangedEventArgs e)
{
Session["assetMakeId"] = e.Value.ToString();
((RadComboBox) fvAsset.FindControl("RadComboBoxAssetModel")).DataBind();
}
Is there a simple way to achieve this kind of thing, it would seem like such a common scenario that there must be a standard way to do it?

Initially I wanted to use a control select parameter on the object
data source for the model Drop down. With the parameter getting the
value from the Make drop down. However this doesn't seem to work as
the select parameter on the object data source can't see the control
with in the form view.
You need to move the ObjectDataSource into templates:
<EditItemTemplate>
<telerik:RadComboBox ....
<telerik:RadComboBox ....
<asp:ObjectDataSource ....
<asp:ObjectDataSource ....
</EditItemTemplate>

Related

'ddpJobType' has a SelectedValue which is invalid because it does not exist in the list of items

im trying to bind the data from database to dropdownlist and i want to set the default value as "select". but i got this error.
My Code is:
<asp:DropDownList ID="ddpJobType" runat="server" Width="226px" Height="26px"
onselectedindexchanged="ddpJobType_SelectedIndexChanged">
<asp:ListItem Selected="True" Value="0" Text="--Please Select Type--"></asp:ListItem>
</asp:DropDownList>
<asp:RequiredFieldValidator ID="RequiredFieldValidator5" runat="server"
ErrorMessage="Please Select JobType " Font-Size="Small"
ForeColor="Red" ControlToValidate="ddpJobType"
ValidationGroup="VGPJobPost"></asp:RequiredFieldValidator>
If you are banding data using DataSource, then your default item will not be available after the call of DataBind function. You need to add it manually after calling databind something like below
dropDownList.DataSource= yourdataSource;
dropDownList.DataBind();
dropDownList.Items.Insert(0, new ListItem("--Please Select Type--", "0"));
Another option is in the designer you need to specifiy
AppendDataBoundItems=true
This will make sure your designtime list items are present after databind

Dynamic Data - Selecting a table from a DropDownList to scaffold in a GridView

I have been struggling with this ASP.NET Dynamic Data problem for days now... I have a DropDownList containing the table names of all the tables in my data context (.dbml) file. When I select the DropDownList, it needs to scaffold the selected table in a GridView. My code works 100% in scaffolding the MetaTable in the GridView (it implements all the rules that I applied in my Meta Classes).
However, filtering only seems to work if I explicitly add the DynamicExpression in the declaration of the QueryExtender:
<asp:QueryExtender ID="GridQueryExtender" TargetControlID="GridDataSource" runat="server">
<asp:DynamicFilterExpression ControlID="FilterRepeater" />
</asp:QueryExtender>
This in turn requires me to specify the MetaTable explicitly in the LinqDataSource (linqdsData), either programmatically in the Page_Load or in the ASP.NET syntax.
Since the GridView gets scaffolded in the Page_Load part of the life-cycle, the above approach does not work for me, since it takes place in the Page_Init part of the life-cycle.
So my requirement is that as soon as I select another table to populate the GridView with from the DropDownList, the FilterRepeater needs to reflect the filters of the newly selected MetaTable.
Is there any way for me to programmatically update the FilterRepeater in the Page_Load so that it will contain the filters of the MetaTable that I selected in the DropDownList.
The following is some of my code:
ASP.NET Page Code-Behind:
protected void Page_Load(object sender, EventArgs e)
{
if (ddlTable.SelectedIndex > 0)
{
string tableName = ddlDataType.SelectedValue;
linqdsData.TableName = tableName;
MetaTable mt = ASP.global_asax.DefaultModel.GetTable(tableName);
GridViewData.SetMetaTable(mt, mt.GetColumnValuesFromRoute(Context));
GridViewData.EnableDynamicData(mt.EntityType);
GridViewData.DataSourceID = linqdsData.ID;
}
}
ASP.NET Page:
<asp:Panel runat="server" ID="pnlFilters" CssClass="gridFilterCon" EnableTheming="True">
<div class="filterGridHeading">
Filter the grid by:</div>
<asp:QueryableFilterRepeater runat="server" ID="FilterRepeater">
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Eval("DisplayName") %>' OnPreRender="Label_PreRender"
CssClass="gridFilterLbl" />
<asp:DynamicFilter runat="server" ID="DynamicFilter" />
<br />
</ItemTemplate>
</asp:QueryableFilterRepeater>
<asp:Button ID="btnFilter" runat="server" Text="OK"
EnableTheming="False" UseSubmitBehavior="False" OnClick="btnFilter_Click" />
</asp:Panel>
<asp:GridView ID="GridViewData" runat="server" OnSelectedIndexChanged="GridViewData_SelectedIndexChanged"
OnPreRender="GridViewData_PreRender" OnRowDataBound="GridViewData_RowDataBound"
OnPageIndexChanged="GridViewData_PageIndexChanged" AllowPaging="True" PageSize="50" OnInit="GridViewData_Init">
<Columns>
...
</Columns>
<PagerTemplate>
<asp:GridViewPager ID="GridViewPager1" runat="server" />
</PagerTemplate>
<PagerSettings Mode="NumericFirstLast" NextPageText="Next" />
</asp:GridView>
<asp:LinqDataSource ID="linqdsData" runat="server" ContextTypeName="pdcDataContext"
OnSelected="linqdsData_Selected" OnSelecting="linqdsData_Selecting" EnableUpdate="True">
</asp:LinqDataSource>
<asp:QueryExtender ID="GridQueryExtender" TargetControlID="linqdsData" runat="server">
</asp:QueryExtender>
Your help will be greatly appreciated.
It sounds like you are trying to do a lot on one web page. This creates complications of the type you are experiencing: each table requires distinct filters and MetaTables. Trying to keep each item straight requires a bunch of switch and/or if...then statements. I recommend an alternate approach. Instead of doing all of this on one page:
Create a web page for each table
Setup the appropriate filters and MetaTables
Copy the DropDownList containing the table names of all the tables to each web page, and use it to redirect to the appropriate web page.
ASP.net Dynamic Data makes it easy to create web pages for each table. That is what scaffolding is all about. With the approach above, each web page will handle its own set of concerns that are focused on the particular table.
Hope this helps.

PostBack DataBind error: "Ensure that the control is added to the page before calling DataBind."

I have a program that allows the user to use a few dropdowns to pick a topic and attribute, then the data are pulled that match on both of those conditions. In the gridview are a lot of templatefields use textboxes for instant editing (a submit button saves all changes) as well as a template with a dropdown bound to a parameter. This was all working hunky-dory for quite a while.
Then, we changed some of the data in the tables (keeping all the same field names) and now the page loads perfectly fine on launch but then as soon as you select something different in any of the drilldown dropdowns the page fails. I get an error saying
"The DropDownList control 'TagDDL' does not have a naming container.
Ensure that the control is added to the page before calling DataBind."
(TagDDL is the dropdown in the templatefield in gridview). If I simply remove this templatefield, I get a similar (though different) error on a hyperlinkfield, removing this gives me an error in a boundfield, so obviously it's not tied to any one thing.
My idea is that it has something to do with how databinding works on post-back, since the page loads perfectly initially, the dropdowns have 'Enable PostBack' and the error messages refer to DataBind. Any ideas?
The SqlDataSource that builds Gridview (leaving out the drilldown dropdowns for now)
<asp:SqlDataSource ID="MasterTable" runat="server"
ConnectionString="<%$ ConnectionStrings:spvConnectionString %>"
SelectCommand="exec pmtv2.maintable_display 1, #IPG_Assigned, #CompetitorName, #enterprise_zone, #Banner, #BrandName"
<SelectParameters>
<asp:ControlParameter ControlID="ChooseBanner" Name="Banner" PropertyName="SelectedValue" Type="String" />
<asp:ControlParameter ControlID="ChooseIPGs" Name="IPG_Assigned" PropertyName="SelectedValue" Type="Int32" />
<asp:ControlParameter ControlID="ChooseBrands" Name="BrandName" PropertyName="SelectedValue" Type="String" />
<asp:ControlParameter ControlID="ChooseComps" Name="CompetitorName" PropertyName="SelectedValue" Type="String" />
<asp:ControlParameter ControlID="ChooseZone" Name="enterprise_zone" PropertyName="SelectedValue" Type="Int32" />
</SelectParameters>
<div id="MasterDiv" style="width:90%">
<asp:GridView ID="MasterDisplay" runat="server"
AllowSorting="True" AutoGenerateColumns="False"
DataKeyNames="productKey,banner,enterprise_zone,userID" DataSourceID="MasterTable"
OnRowDataBound="MasterDisplay_RowDataBound"
OnSorting="MasterDisplay_Sorting"
class="mGrid" AlternatingRowStyle-CssClass="mGridAlt">
</AlternatingRowStyle>
<Columns>
<asp:TemplateField HeaderText="Description" SortExpression="productdescriptionlong">
<ItemTemplate>
<a href="javascript:openPopup('JustinPractice4.aspx?UPC=<%# Eval("UPC") %>
&banner=<%# Eval("banner") %>&enterprise_zone=<%# Eval("enterprise_zone") %>')"><%# Eval("productdescriptionlong")%></a>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="BrandName" HeaderText="Brand"
SortExpression="BrandName" />
<asp:TemplateField HeaderText="New Price" SortExpression="new_base_retail">
<ItemTemplate>
<asp:TextBox ID="RWNextPrice" runat="server"
Text='<%# Bind("new_base_retail", "{0:N2}") %>' Width="60px"
class="calculate" onchange="lineItemRipple(this)"
Visible='<%# ShowBox %>'></asp:TextBox>
<asp:Label ID="RNextPrice" runat="server" Text='<%# Eval("new_base_retail", "{0:c}") %>'
Visible='<%# ShowLabel %>'></asp:Label>
<asp:HiddenField ID="lineCode" runat="server" Value='<%# Eval("line_code") %>'/>
</ItemTemplate>
</asp:TemplateField>
<asp:ImageField DataImageURLField="unique_flags" HeaderText="Flags"
DataImageURLFormatString="Media/Images/{0}.png" SortExpression="unique_flags"/>
<asp:TemplateField HeaderText="Tag Type" SortExpression="tag_type">
<ItemTemplate>
<asp:DropDownList ID="TagDDL" runat="server"
DataSourceID="dimTags"
DataTextField="Tag_type_name"
DataValueField="Tag_type_name"
SelectedValue='<%#Bind("tag_type") %>'
visible='<%#ShowBox %>'>
</asp:DropDownList>
<asp:Label ID="TagR" runat="server"
Text='<%# Eval("tag_type") %>'
Visible='<%# ShowLabel %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<asp:Button ID="Commit" runat="server" Text="Commit Changes" OnClick="Commit_Click"
class="button"/>
and the relevant code behind:
protected void Page_Load(object sender, EventArgs e) {
ErrorMsg.Text = "test45";
}
protected void MasterDisplay_RowDataBound(object sender, GridViewRowEventArgs e) {
DataSourceSelectArguments sr = new DataSourceSelectArguments();
DataView dv = (DataView)CheckForCommit.Select(sr);
if (dv.Count != 0) {
CommittedOrNot.Text = dv[0][0].ToString();
}
//pulling results from a SqlDataSource confirming presence of data
//calculations to maintain a running tally of certain fields for later use
}
protected void Commit_Click(Object sender, EventArgs e) {
string tagValue = "FLAG";
foreach (GridViewRow gvr in MasterDisplay.Rows) {
tagValue = ((DropDownList)gvr.FindControl("TagDDL")).SelectedValue;
MasterDisplay.UpdateRow(gvr.RowIndex, false);
} //for every row, update it
MasterDisplay.DataBind();
}
It was a simple error of trying to add to a DDL before I had actually pulled the data needed to bind it. Changing the order of things slightly did the trick
I am glad you found your answer. I had a similar issue on a UserControl (ascx) that was being loaded a run-time. I, too, had made a change to my data source and the corresponding sql data sources. (In my case, I was replacing the sql data sources with an entity model.)
What I found was that one of my controls would bind to the new data source (via the code behind) with no problems. The code looked as follows:
gridSomeData.DataSource = controller.GetListOfAssociatedParts();
gridSomeData.DataBind();
However, in the same method, the next section of code would fail when the DataBind() method was called. The code looked as follows:
drpDataList.DataSource = controller.GetListOfParts();
drpDataList.DataTextField = "PartID"
drpDataList.DataValueField = "PartKey"
drpDataList.DataBind();
It turned out, that when I removed the prior ASCX markup for the SqlDataSource objects, I failed to remove the reference in the DataSourceID attribute of the drop down control. So when I called the DataBind() method, the binding engine checked the attributes of the control, found a name DataSourceID, and immediately went looking for it in the control hierarchy of the UserControl. When the binding engine failed to find the object, it threw the exception "The DropDownList control [...] does not have a naming container..."
I will admit that this particular exception is somewhat misleading, as it is really the binder being confused over which instructions to follow for the data source (the code behind, or the markup in the ascx file).
I hope this helps with some perspective. :)

ASP.NET DropDownList bound to data but allows for nulls?

I'm using LINQ to SQL and want to be able to select a parent or no parent. Let's say I have a People table with PersonId, Name and ParentId columns. In ASP I want to enter the name, select a parent and click 'Add' to create a new Person record, but I also want to be able to leave the ParentId null. Don't ask why, this is just a simplified explanation for what I want to do.
<asp:LinqDataSource ID="LinqPeople" runat="server"
ContextTypeName="MyDataContext" EntityTypeName=""
Select="new (PersonId, Name)" TableName="People"/>
<asp:TextBox ID="textName" runat="server" />
<asp:DropDownList runat="server" ID="dropParent"
DataSourceID="LinqPeople" DataTextField="Name" DataValueField="PersonId" />
<asp:Button ID="buttonAddPerson" runat="server" Text="Add" />
Is there any way to display 'None' in the list box with a value of null? I have thought of a few options, which is best or are there any others?
Create a stored procedure for the SQL "SELECT PersonId, Name FROM People UNION SELECT Null, 'NONE'"
Add a CheckBox for "NO PARENT"
Put a ListItem in the markup for the DropDownList
Add the item on the DataBound event handler
I found a better way, adding a ListItem in the markup:
<asp:LinqDataSource ID="LinqPeople" runat="server"
ContextTypeName="MyDataContext" EntityTypeName=""
Select="new (PersonId, Name)" TableName="People"/>
<asp:TextBox ID="textName" runat="server" />
<asp:DropDownList runat="server" ID="dropParent"
DataSourceID="LinqPeople" DataTextField="Name" DataValueField="PersonId">
<asp:ListItem Value="">(none)</asp:ListItem>
</asp:DropDownList>
<asp:Button ID="buttonAddPerson" runat="server" Text="Add" />
I cannot find any way to return the actual value 'NULL' in SelectedValue however, but I can handle that I guess. I think the ListItem way is the best because it is defined in the markup and doesn't require any code...
Don't think you can set the value of NULL since it's a string type.
I don't like the check for NULL, typically, I would use something that doesn't make sense, like -1 or something and check for that. You could also assume that your selected index is 0, however, that could cause problems somewhere else in code if you don't follow throughout the app.

How do I data bind a drop down list in a gridview from a database table using VB?

So in this gridview, there is a column for status and I want to have a drop down list with Pass, Pending, Fail appear when the edit button is clicked. These values are already in a table, so I need to somehow bind from this table to each ddl for every row.
Here is the column from the gridview. As you can see, I would like to just have a label showing when not in edit mode, and a ddl when the edit button is pressed
<asp:TemplateField HeaderText="During Production Status" SortExpression="DuringProductionStatus">
<EditItemTemplate>
<asp:DropDownList ID="ddlStatus" runat="server" datavaluefield="Name"
datatextfield="Name" DataSource="*What goes here?*"> />
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="lblStatus" runat="server"
Text='I don't understand how to get this from the ddl' />
</ItemTemplate>
</asp:TemplateField>
For clarity's sake, my table is named Status, and the database is named DirectImport
There's a few steps to go through here - none of them are particularly difficult, but they can be a bit fiddly (IMHO). The good news is once you've got this working once, it gets easier to do it again!
I'm assuming you've got a <asp:*DataSource> control on your page - my preference is for an ObjectDataSource but I don't think it matters, I think a SqlDataSource works equally well. I've never tried doing this with GridView.DataSource = MyDataSet in code-behind, so I don't know whether that would work or not, but my assumption is that it wouldn't as you wouldn't get the proper two-way binding that you want. This data source feeds your grid with your main data. The key point here is that your database query must return both the Status text field and the Status id.
So your gridview will now look something like:
<asp:objectdatasource runat="server" id="MainDataSource" ... />
<asp:gridview runat="server" id="MyGridView" DataSourceID="MainDataSource">
<Columns>
<asp:TemplateField HeaderText="During Production Status" SortExpression="DuringProductionStatus">
<ItemTemplate>
<asp:Label ID="lblStatus" runat="server"
Text="<%# Bind('Status') %>" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:gridview>
The Text="<%# Bind('Status') %>" is the bit you're missing to get the status text into the grid.
Now add a second data source into your markup that reads in the set of values from the Status table.
<asp:objectdatasource runat="server" id="StatusObjectDataSource" ... />
And add the EditItemTemplate into the GridView, which is bound to the Status DataSource.
<EditItemTemplate>
<asp:DropDownList ID="ddlStatus" runat="server" datavaluefield="StatusID"
datatextfield="Status" DataSourceID="StatusObjectDataSource"
SelectedValue="<%# Bind('StatusId') %>" />
</EditItemTemplate>
The SelectedValue="<%# Bind('StatusId') %>" is what connects up the two datasets so that when you flip a row into Edit mode, the dropdownlist has the correct item already selected, and when you then save it you've got the Status ID to put into your database.
And you're done.
I have used the RowDataBound event. Here is a small code snippet. HTH
you would have an ItemTemplate in your aspx/ascx
<asp:TemplateField HeaderText="Column Headings">
<ItemTemplate>
<asp:DropDownList ID="ddlName" runat="server" Width="150"></asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
and in your code behind, you will have
protected void grdDataMap_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DropDownList ddl = (DropDownList)e.Row.FindControl("ddlName");
ddl.DataSource = someList;//the source of your dropdown
ddl.DataBind();
}
}
so when you bind your grid with grdDataMap.Databind (assuming your grid id is grdDataMap), row databound event will be called for each row (including header/footer, and thats the reason you check RowType)
so you can probably decide what controls/columns to hide/show/bind inside this row databound event
In the winforms world I pull my objects from the DB into a List(Of Whatever) and use the list as the datasource.
This also lets me add extra "convenience" fields in the object so that I can populate it with stuff from other tables.
I don't know asp.net at all so if you can do something similar, it might help.
A really quick solution is to create a custom web control for the status dropdown. The control will always contain the same data. When it renders you populate the datasource. When it gets added to the gridview, the data will be in the drop down. Hope that helps!

Resources