GridView and DropDownlist - asp.net

I have a gridview that when enter to edit mode one of the column change to dropdownlist:
<EditItemTemplate>
<asp:DropDownList ID="DropDownList2" runat="server"
DataSourceID="SqlDataSource1" DataTextField="name" DataValueField="name">
</asp:DropDownList>
</EditItemTemplate>
Now i have a SqlDataSource with update method that define in this aspx file:
<UpdateParameters>
<asp:Parameter Name="name" Type="String" />
<asp:ControlParameter ControlID="DropDownList2" Type="string"
PropertyName="SelectedValue" Name="genre" />
</UpdateParameters>
now i want to get the selected value and insert it but when i press the Update button in the row in the gridview i get this error:
Could not find control 'DropDownList2' in ControlParameter 'genre'
any idea why it happen?

Yes. ControlParameters only work when the DOM can find the control you're referring to that's within the same branch of the GridView. The problem is that Gridviews are a poor way of handling DOM controls because as soon as you go into a "mode" of the GridView like the EDIT mode, the entire DOM structure changes. The DOM by the way, is the Document Object Model. Because it's changed, therefore ASP cannot find the control you're referring to.
I've overcome this by doing one of two things.
First see if it works by simply tailing the control name with the '$' character.
<UpdateParameters>
<asp:Parameter Name="name" Type="String" />
<asp:ControlParameter ControlID="MyGridView$DropDownList2" Type="string"
PropertyName="SelectedValue" Name="genre" />
</UpdateParameters>
This sometimes works if you're lucky.
If not, then you'll need to find the control, get its value and pass it into the SQL parameter programmatically in code behind.
Try something like this (I use C#) ...
protected void MyGridView_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
...
GridViewRow gvRow = (GridViewRow)sender;
DropDownList myDDL = (DropDownList)gvRow.FindControl("DropDownList2");
if (myDDL != null)
{
//assuming your datasource is outside the gridview, you have to find it!
SqlDataSource sds1 = (SqlDataSource)page.FindControl("myDataSource");
if (sds1 != null)
{
sds1.UpdateParameter["genre"].DefaultValue = myDDL.SelectedValue;
... and do your databinding etc
sds1.Update();
}
}
}
I always rely on the client-side code (ASPX) to do most of the work for me, like Bind(), Eval(), etc, but over time you'll realise that to really control your program, you'll have to rely on JavaScript or code behind to do the finer bits. ASP is not always "clever" in doing what you expect it to do.

Related

Using a dropdownlist control inside a formview

I am new to asp.net and i have a problem using a dropdownlist control inside a formview and passing its value to the related sqldatasource. When i use the code below i get the following exception
Exception Details: System.InvalidOperationException: Could not find control 'ddlCategory' in ControlParameter 'categoryId'.
The Dropdownlist inside a formview.
<asp:DropDownList ID="ddlCategory" DataSourceID="ObjectDataSourceCategory" DataTextField="NAME" DataValueField="ID" runat="server" />
The SQL Data Source
<asp:ObjectDataSource ID="sqlDataSourceItem" TypeName="Item" runat="server"
SelectMethod="getItem"
InsertMethod="insertItem"
UpdateMethod="updateItem">
<SelectParameters>
<asp:QueryStringParameter QueryStringField="id" Name="id" />
</SelectParameters>
<InsertParameters>
<asp:ControlParameter ControlID="ddlCategory" Name="categoryId" PropertyName="selectedValue" />
</InsertParameters>
</asp:ObjectDataSource>
And i have found the solution to this problem. I have changed the ID of the DDL in the control parameter. It works like below since this is the final generated id of that control. But i think there must be an easier and better way. Any help would be appriciated.
<asp:ControlParameter ControlID="ctl00$main$frmViewItem$ddlCategory" Name="categoryId" PropertyName="selectedValue" />
This answer will provide a solution to your problem:
You need a recursive findcontrol() method.
It is because of your ddlCategory is inside formview and you are using the master page. The best way is to overwrite the 'FindControl' function of master page.
pls see the following link for detail:
http://geekswithblogs.net/AzamSharp/archive/2006/08/27/89475.aspx

How do I bind dependent drop down lists in ASP.NET

I need a way to bind multiple drop down lists that are populated based on their parent node.
RootDDL <- child <- grandchild[]
The code looks something similar to
<FormView DataSoureceID="rootDatasource">
<DropDownList ID="RootDLL" AutoPostBack="true">
<!--items-->
</DropDownList>
<DropDownList ID="child" AutoPostBack="true" DataSourceID="ChildDataSource" />
<SqlDataSource ID="ChildDataSource" />
<DropDownList ID="grandchild" DataSourceID="GrandChildDataSource" SelectedValue='<%# Bind('SomeFieldInRootDatasource') %>' />
<SqlDataSource ID="GrandChildDataSource">
<SelectParameters>
<ControlParameter ControlID="child" PropertyName="SelectedValue" />
</SelectParameters>
</SqlDataSource>
<Button Command="Update" />
</FormView>
<SqlDataSource ID="rootDatasource">
<InsertParameters>
<asp:Parameter Name="SomeFieldInRootDatasource" />
</InsertParameters>
<UpdateParameters>
<asp:Parameter Name="SomeFieldInRootDatasource" />
</UpdateParamters>
</SqlDataSource>
Changing the rootDDL works, unfortunately when the Child selectedvalue changes the grand child <%# Bind %> tries to rebind but cannot as it the FormView is no longer acting as a container.
It fails with
Databinding methods such as Eval(), XPath(), and Bind() can only be used in the context of a databound control.
Is there any solution to this problem that will not require me to add event (multiple) handlers?
I ended up creating a hiddenfield for each child dropdownlist that I then bound with the value I needed. I created a generic indexchange handler to then update the hiddenfeild with the desired result. This results in the bound field not being updated by a datasource (avoiding the rebind system call that was causing the issue in the first place).
Not sure if this is the best solution but it should work for most cases.

asp.ControlParamter control id conflict

<asp:ControlParameter ControlID="ddListPlayerPointSystems" Name="profileid" PropertyName="SelectedValue" />
<asp:ControlParameter ControlID="ddListCmty" Name="cmty" PropertyName="SelectedValue" />
<asp:ControlParameter ControlID="ctl00$MainContent$TabContainer1$TabPanel1$FormView3$pointsTextBox" Name="InsertPts" PropertyName="Text" Type="Decimal" />
I am having trouble understanding why in the first controlparameter i can call the dropdownbox id but not the textboxes id which is pointsTextBox. I am using a master page with an asp ajax tab container with multiple panels. If i take off the "ctl00$MainContent$TabContainer1$TabPanel1$FormView3$" i get a control not found but i dont know why this works for the other two controlparameters
EDIT
So I found a solution to my problem. Thanks to #TheGeekYouNeed and #JamesJ I understand why I would require the longer path name for that particular textbox (the drops were outside of the tabcontainer so the direct name worked). But I found that since I was assigning the value of that textbox via '<%# Bind("name", "{0:n}") %>' I was able to instead just use an asp:Parameter rather than the ControlParameter like so:
"<asp:Parameter Name="name" Type="String" />"
Problem is that i don't quite understand how that all works.
The ControlID for the pointsTextBox is not 'ct100$MainContent$TabContainer..etc... on the server side.
Set the COntrolID in the code behind, so you can use FindControl("pointsTextBox") to get a reference to the textbox control.
You could do something like:
TextBox t = this.FindControl("pointsTextBox") as TextBox;
if(t != null)
{
ddListPlayerPOintSystems.Add(new { COntrolID = t, Name = "InsertPts", PropertyName="Text", Type="Decimal"});
}
I haven't tested it, so I am not claiming the code is perfect, but the method you need to follow is illustrated here.

EntityDataSource Null Update Pameters not getting marked Modified

I am using an EntityDataSource with a FormView on VB.NET application. The FormView contains an AjaxControlToolKit TabContains with multiple tabs. Due to the fact that each tab is a naming container, Bind doesn't work properly for updating values (as discovered from reading other posts on stackoverflow). I instead have to declare UpdateParameters on my EntityDataSource. Example markup is as follows:
<asp:FormView ID="fv" runat="server" DataSourceID="eds" DataKeyNames="ID">
<EditItemTemplate>
<asp:TabContainer ID="tc" runat="server">
<asp:TabPanel ID="tp" runat="server" HeaderText="Tab 1">
<ContentTemplate>
<asp:TextBox ID="tbName" runat="server" Text='<%#Eval("Name") %>'></asp:TextBox>
</ContentTemplate>
</asp:TabPanel>
</asp:TabContainer>
</EditItemTemplate>
</asp:FormView>
<asp:EntityDataSource ID="eds" runat="server" ConnectionString="name=NDSEntities"
DefaultContainerName="NDSEntities" EnableFlattening="False" EntitySetName="Customers"
Where="it.ID = #ID" EnableUpdate="true" EnableInsert="true">
<WhereParameters>
<asp:QueryStringParameter Name="ID" QueryStringField="ID" DbType="Guid" />
</WhereParameters>
<UpdateParameters>
<asp:ControlParameter Name="Name" ControlID="fv$tc$tp$tbName" DbType="String" />
</UpdateParameters>
<InsertParameters>
<asp:ControlParameter Name="Name" ControlID="fv$tc$tp$tbName" DbType="String" />
</InsertParameters>
</EntityDataSource>
This works great, until a customer is edited and their name is set to nothing (assuming in this case, a null name is allowed). The Name UpdateParameter is set to Null but the ObjectStateEntry is not set to modified for Null properties, even if previously the Entity had a value specified. As long as the name is changed to something other than Null, everything is updated correctly.
I found a workaround by putting the following code in the Updating event of the EntityDataSource.
Dim ose As ObjectStateEntry = context.ObjectStateManager.GetObjectStateEntry(action)
For Each p As Parameter In eds.UpdateParameters
ose.SetModifiedProperty(p.Name)
Next
This makes sure that each property in the UpdateParameters has its state set to modified. It works, but it seems like a hack and I can see it causing problems down the road. Is there anything else I could do?
Do you have an "Concurrency Mode" set for the entity in question? Depending on how you actually update the entity (I haven't used the EntityDataSource, but I'm guessing it internally uses the ObjectContext.Attach method), the code that creates the SQL statement, will try to update only those columns that are actually changed.
Consider the following:
void UpdatePersonEntity(int id, string firstName, string lastName)
{
Person p = new Person { Id = id };
this.Context.People.Attach(p);
p.FirstName = firstName;
p.LastName = lastName;
this.Context.SaveChanges();
}
If firstName or lastName is null, the ObjectContext would assume that it's original value hasn't been touched. This might be something you should look into. I apologize if this isn't helpful, but it might push you in the right direction.

LinqDataSource and DateTime Format

I'm trying to create a LinqDataSource to bind to a DropDownList in an ASP.NET form. I only want to show the elements according to a date (which is one of the fields in the database).
Basically, the elements I want to show are the ones that will happen in the futures (i.e. after DateTime.Now).
I was trying the following markup :
<asp:DropDownList runat="server" ID="DropDownList1"
AppendDataBoundItems="True" DataSourceID="LinqDataSource1"
DataTextField="TextField" DataValueField="ValueField">
</asp:DropDownList>
<asp:LinqDataSource ID="LinqDataSource1" runat="server"
ContextTypeName="DataContext1" TableName="Table"
Where="DateField >= #DateField">
<WhereParameters>
<asp:Parameter DefaultValue="DateTime.Now" Name="DateField"
Type="DateTime" />
</WhereParameters>
</asp:LinqDataSource>
I'm getting a format exception saying that "The string was not recognized as a valid DateTime" when I try to run it. However, the dates in my database seem to be fine, because a DateTime.Parse works perfectly on them. The DateField is of type datetime in SQL.
What am I missing here?
Thanks!
The DefaultValue was what was wrong with the code as was suggested by the others.
However, setting the DefaultValue to
"<%# DateTime.Now %>"
like Andomar suggested (which would make the markup look something like this :
<WhereParameters>
<asp:Parameter DefaultValue="<%# DateTime.Now %>" Name="DateField" Type="DateTime" />
</WhereParameters>
will not work either because DataBinding expressions are only supported on objects that have a DataBinding Event, and neither Parameter or ControlParameter have one.
For a String, it's fairly easy to create a TextBox or Label and put the <%# %> expression in the value of that new field (more details here), but it was a bit more complicated with a DateTime value, as comparing an SQL DateTime with a .NET DateTime caused an exception.
It can be done quite easily in the Page_Load event by using
DataContext DataContext1 = new DataContext();
var c = from a in DataContext1.Field
where a.DateField >= DateTime.Now
select a;
DropDownList.DataSource = c;
DropDownList.DataBind();
I suspect it is failing on the DefaultValue.
Try:
DefaultValue="<%# DateTime.Now %>"

Resources