color styling tablecell based upon value - asp.net

I am trying to style tablecells based upon the text value of the cell. This is being done on specific fields to draw user attention These tablecells are hosted inside of a formview with an itemTemplate of asp:table object. The cells have an ID and are set to run at the server side so that I can grab them from codebehind.
I attempted to hook into the individual cells by handling the onDatabound, onPrerender, onLoad events of the tablecell. onPreRender is used in my code snippet but results were same on all three tablecell events. In handling these events I always had a string.empty for the text property instead of the actual value (even after databind was called). Because I didn't have the actual value my comparisons did not pass and my color styling did not get set as desired.
edit: I also tried handling the databound event of my formview to get to my cell values. No luck there either.
Here's relevant markup:
<asp:FormView ID="fvShipments" runat="server" DefaultMode="readonly">
<ItemTemplate>
<asp:Table ID="tblShipments" runat="server" GridLines="Both">
<asp:TableRow runat="server">
<asp:TableCell runat="server" ID="tbcCartonSizeOverride" CssClass="table-displayrow centerText" OnPreRender="tbcCartonSizeOverride_PreRender"><%#Eval("CartonSizeOverRide")%></asp:TableCell>
Here's relevant codebehind
Protected Sub tbcCartonSizeOverride_PreRender(sender As Object, e As EventArgs)
markAflag(CType(sender, TableCell))
End Sub
Private Sub markAflag(ByRef cell As TableCell)
If cell.Text.Trim.Length > 0 Then
cell.BackColor = Drawing.Color.Orange
Else
cell.BackColor = Drawing.Color.White
End If
End Sub
I'm not understanding why this isn't working. Unless my Eval markup solves AFTER prerender event?
Thanks for reading. I don't work with asp often so it's possible I have something simple confused here.

Ok I solved this issue by setting some datakeys on my formview object and doing a findcontrol call at runtime to get a reference to my table on the page. Here's some sample code that demonstrates what I did.
Private Sub colorReturncode()
Dim schedreturncode As Integer
schedreturncode = FormView1.DataKey(1)
Dim qtable As New Table
qtable = CType(FormView1.FindControl("table1"), Table)
If schedreturncode = 0 Then
qtable.Rows(4).Cells(2).BackColor = System.Drawing.Color.Green
qtable.Rows(4).Cells(2).ForeColor = System.Drawing.Color.White
ElseIf schedreturncode = -1 Then
qtable.Rows(4).Cells(2).BackColor = System.Drawing.Color.White
Else
qtable.Rows(4).Cells(2).BackColor = System.Drawing.Color.Red
qtable.Rows(4).Cells(2).ForeColor = System.Drawing.Color.White
End If
End Sub

Related

how to pass textbox value in asp.net to a code on update click

I have an issue with the following code, the markup is as follows:
<asp:GridView ID="GridView" runat="server"
AutoGenerateEditButton="True"
OnRowDataBound="GridView_RowDataBound"
OnRowEditing="GridView_RowEditing"
OnRowUpdating="GridView_RowUpdating"
CssClass="gridv">
<Columns>
<asp:TemplateField HeaderText="ASN">
<ItemTemplate>
<asp:Label ID="lblASN" runat="server" Text='<% #Eval("ASN")%>'></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="txtASN" runat="server" Text='<%# Bind("ASN")%>' CssClass="form-control"></asp:TextBox>
</EditItemTemplate>
</asp:TemplateField>
...
However when I run this code to get the new changed values from the textboxes that were successfully generated and populated, I only get the initial values not the news that user has entered, the code behind this is:
Protected Sub GridView_RowUpdating(sender As Object, e As System.Web.UI.WebControls.GridViewUpdateEventArgs) Handles GridView.RowUpdating
Try
Dim row As GridViewRow = GridView.Rows(e.RowIndex)
Dim ID As Integer = DirectCast(row.FindControl("txtID"), TextBox).Text
Dim sASN As String = DirectCast(row.FindControl("txtASN"), TextBox).Text
Dim sDescription As String = DirectCast(row.FindControl("txtDescription"), TextBox).Text
Dim sManufacturer As String = DirectCast(row.FindControl("ddlmanufacturer"), DropDownList).SelectedValue
GridView.EditIndex = -1
Catch
End Try
ShowEmpDetails()
End Sub
So when I click the update button I use a message box to write the variables above and the values that I get are the same ones that got initially written to the textboxes, not the text that the user has changed?
I have worked out this code from a similar example in which this works with no issues, I honestly can not figure out what I am doing wrong?
As requested Page_Load event is calling this function:
Private Sub ShowEmpDetails()
Dim query As String = "SELECT * from inventory.all_items"
Dim cmd As MySqlCommand
cmd = New MySqlCommand(query)
cmd.Connection = myConn
Dim sda As New MySqlDataAdapter
sda.SelectCommand = cmd
Dim dt As New DataTable
sda.Fill(dt)
GridView.DataSource = dt
GridView.DataBind()
End Sub
Ok... there are so many things wrong with your coding approach that I don't know where to begin. Sorry.
Lets' start again and I'll explain how to properly pass values between the DOM and your code-behind.
Firstly, you need to understand how the DOM populates and builds the HTML for the browser to know what's going on.
I would test your project in Firefox and use the Inspector tool (right-click wep page). That tool is gold and has saved my already bald-head from revealing my skull!! :-)
As you know, the GridView control binds both the "view" and "edit" portions of the control into the same code. I can see you have Eval() for the view portion of the control (or the mode of the control I should say) and you have Bind() for the Edit mode. That is good. I personally hate BoundControls, as you cannot really see what's going on under the hood.
Next, avoid using AutoPostBack like the plaque! It's just ugly.
Get familiar with AjaxControlToolKit (there are others too, but start with the Ajax), and the ASP:UpdatePanel.
So in your case something like this ...
<asp:UpdatePanel ID="upADDMAIN" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:GridView ID="GridView" runat="server"
AutoGenerateEditButton="True"
OnRowDataBound="GridView_RowDataBound"
OnRowEditing="GridView_RowEditing"
OnRowUpdating="GridView_RowUpdating"
CssClass="gridv">
Try and put as much functionality back into the defaults of the GridView control. So go back to your DESIGNER mode in VStudio and add all the functionality you need like EDIT, UPDATE, DELETE, etc in the design mode of the GridView. This will also make sure your SQLDataSource is updated at the same time with the right SQL for the task.
Now why are you using OnRowEditing and OnRowUpdating?
My rule-of-thumb is always to keep things to a minimum and give as much control to ASP.net as possible. This avoids re-inventing the wheel with code-behind stuff that ASP.net can handle straight out of the box.
I generally use OnDataBound(), OnRowDataBound(), and OnRowUpdating() to both read the data and pre-UPDATE the data before the Update() gets called by the controls.
ie:
protected void gvLogins_RowDataBound(object sender, GridViewRowEventArgs e)
{
GridViewRow gvRow = (GridViewRow)e.Row;
{
if (gvRow.RowType == DataControlRowType.DataRow)
{
and
protected void gvLogins_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
//apply values to the SQL parameters for UPDATE, etc
GridViewRow gvRow = (GridViewRow)gvLogins.Rows[e.RowIndex];
to do some pre-Update updates outside of the GridView for example.
I never do prerendering or preloading of data in the PageLoad(). That is just re-inventing the wheel, when by default most ASP.net controls already have connectivity and updating built in!
Oh and to get the values of controls inside a GridView... just use FindControl() but in the right place! ie: the DataBound() events etc.
DropDownList ddlAgent = (DropDownList)gvRow.FindControl("ddlAgent");
HiddenField hfAgentID = (HiddenField)gvRow.FindControl("hfAgentID"); //from overall state,as EDIT mode defaults the hfAgentID to 0!
if (ddlAgent != null && hfAgentID != null)
ddlAgent.SelectedValue = hfAgentID.Value;
Sorry I only use C#, not VB.
Good luck.

ASP.NET Losing listbox binding on viewchange?

Ok so what seems like a basic problem is getting the better of me and my exstensive google efforts have come up short. Perhaps I don't understand enough to ask the right questions.
Here's my problem:
I have a formview control, or rather a series of them, each page displaying entry from previous forms, for a higher level access to approve/edit as needed. So, on form "B", I have the contents of form "A" and the blank part of "B" to filled out...So two seperate fromviews on the page.."A" and "B"
That works fine, the issue is when I change the mode to edit previous entry. So if I have a button or the default linkbutton to change from ReadOnly to Edit I not only lose bindings but any efforts to counteract that have left me with issues when I postback.
DUE TO LENGTH I'M LEAVING SOME CODE OUT
On my button I'm using FormView2.ChangeMode(FormViewMode.Edit) to change view, the default link button I've not changed
Bindings on my listboxes are setup like:
If Not Page.IsPostBack Then
'pulling bindings from table
cmd = New OleDbCommand("SELECT * FROM mslToi", objCon)
objReader = cmd.ExecuteReader
lst1.DataValueField = "listing"
lst1.DataTextField = "listing"
lst1.DataSource = objReader
lst1.DataBind()
'pre-selecting input data from form "A"
cmd = New OleDbCommand("SELECT [type_of_injury] FROM S2childToi WHERE ID = " & qs & "", objCon)
objReader = cmd.ExecuteReader
Do While objReader.Read
For Each y As ListItem In lst1.Items
If y.Text = objReader.Item(0) Then
y.Selected = True
End If
Next
Loop
end if
In the page load event.
MARKUP FOR THE FORMVIEW AS ASKED
<asp:FormView ID="FormView2" runat="server"
Width="100%" DataSourceID="AccessDataSource4">
<ItemTemplate>
</ItemTemplate>
<EditItemTemplate>
</EditItemTemplate>
</asp:FormView>
'''that is the short and sweet of the formview markup as requested. It may also be worth noting that it doesn't matter what mode I start in, if I change modes it equals same result'''
That works fine so far...it's when I change view to Edit that my listbox appears to no longer be bound (controls appear but have no content). My thought is that obviously I'm blocking out my code from postback events (I have a reason for this). I can use this code (without the If Not Page.IsPostBack) to force the selections and bindings but whenever I postback they will defualt to the table data, which can't happen, each listbox needs to postback so I can check for a certain selection. So what happens is the user input is trumped. Short and sweet.
I'm sorry that I can't explain better, any advice is much appreciated. If I can asnwer any questions or post code let me know.
Try this:
<asp:FormView ID="FormView1" runat="server">
<ItemTemplate>
<asp:ListBox ID="ListBoxReadonly" runat="server"></asp:ListBox>
</ItemTemplate>
<EditItemTemplate>
<asp:ListBox ID="ListBoxEdit" runat="server"></asp:ListBox>
</EditItemTemplate>
</asp:FormView>
Then, in your FormView's databound event, bind the data into your listbox depending on the current view.
Protected Sub FormView1_DataBound(sender As Object, e As EventArgs) Handles FormView1.DataBound
Dim myListBox As ListBox
If FormView1.CurrentMode = FormViewMode.ReadOnly Then
myListBox = DirectCast(FormView1.FindControl("ListBoxReadonly"), ListBox)
ElseIf FormView1.CurrentMode = FormViewMode.Edit Then
myListBox = DirectCast(FormView1.FindControl("ListBoxEdit"), ListBox)
End If
If myListBox IsNot Nothing Then
myListBox.DataValueField = "listing"
myListBox.DataTextField = "listing"
myListBox.DataSource = GetListingData()
myListBox.DataBind()
' your pre-select code here...
End If
End Sub

Gridview Linkbutton Code behind

Until now, I was working with VS 2003 and recently migrated to VS 2008. I am facing some peculiar problems.
In Vs 2003,I had a Datagrid, and one of the field was ButtonField(Link button). It was not a template field. The user clicks on the field and some data gets generated.
I have written a code, in Vb, like this, on dg_ItemCommand:
Strid = Ctype(e.commandsource,linkbutton).text
Now i want to use same method,for the gridview (I think datagrid is gridview in 2008). I wrote a code like this on dg_Rowcomand
Private Sub dgSampleCustomer_RowCommand(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewCommandEventArgs) Handles dgSampleCustomer.RowCommand
Try
Dim strid As String
Dim i As Integer
strid = CType(e.CommandSource, LinkButton).Text
...
It is throwing a error.
Unable to cast object of type 'System.Web.UI.WebControls.GridView' to
type 'System.Web.UI.WebControls.ButtonField'.
Can anybody help me out!
It looks like the source of the command is the GridView itself, not the button you are clicking. What you probably want to do is set this value you are looking for in the "CommandArgument" property of the Linkbutton. The markup would look something like this:
<asp:LinkButton ID="myLinkButton" runat="server"
CommandName="MyCommandName"
CommandArgument="MySpecialValue"
Text="Click Me" />
Then in the event you would simply:
' strid = "MySpecialValue"
strid = e.CommandArgument.ToString()
Instead of pulling the ID from the name of the control, you can now easily get it from the command. CommandName is optional in this particular case, but comes in handy if you have multiple buttons on a grid that do different things, such as "Edit" and "Delete". Then you can use the command name to handle each command in their own way in the same event:
If (e.CommandName = "Edit") Then
' Do Some Edit Code
End If
I'm wondering why you are trying to cast the command source to a LinkButton? If you would like to attach or otherwise send some kind of row-specific information to your button handler, you are able to do this with the CommandName and CommandArgument attributes of the ButtonField.
Like:
<asp:Gridview ID="...">
...
<columns>
<asp:buttonfield buttontype="Link"
commandname="Generate"
text="Generate"/>
...
</columns>
</asp:GridView>
This will be retrievable in the event handler by using:
if(e.CommandName=="Generate")
{
// Convert the row index stored in the CommandArgument
// property to an Integer.
string rowIndex = Convert.ToInt32(e.CommandArgument);
...
}
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.rowcommand.aspx
UPDATE: (use DataKeys)
Since e.CommandArgument returns a row index, and you want the ID, use the DataKeys collection, first add your ID column to the DataKeyNames collection...
<asp:GridView ... DataKeyNames="ID">
... and then retrieve the values from the DataKeys collection, like:
GridView sourceGridView = (GridView) e.CommandSource;
rowIndex = Convert.ToInt32(e.CommandArgument);
strID = sourceGridView.DataKeys[rowIndex]["ID"];
You can try this in your rowcommand event
Dim index = Convert.ToInt32(e.CommandArgument)
Dim row = dg.Rows(index)
'find your linkbutton in template field (replace "lnkBtn" with your's)
Dim myLinkButton = CType(row.FindControl("lnkBtn"), LinkButton)
Dim strid As String = myLinkButton.Text
Let me know if it helps.

Why is My GridView FooterRow Referencing the Wrong Row?

I have a GridView and, using a fairly common method, I'm using a FooterRow and TemplateFields to provide the missing insert ability. So far so good.
The footer contains a TemplateField with a LinkButton to provide the postback that does the insertion. In the handler for the LinkButton's click, the Insert() method is called on the ObjectDataSource that the GridView is bound to. The ObjectDataSource's insert parameters are populated in the handler for its Inserting event. The code for all of this (abridged) looks like this:
Markup:
<asp:GridView ID="gvComplexRates" runat="server" AutoGenerateColumns="False"
DataKeyNames="id" DataSourceID="odsComplexMileageRates"
EnableModelValidation="True" ShowFooter="True">
<Columns>
<asp:TemplateField ShowHeader="False">
:
:
<FooterTemplate>
<asp:LinkButton ID="addLinkButton" runat="server" CausesValidation="false"
CommandName="Insert" Text="Add"></asp:LinkButton>
</FooterTemplate>
</asp:TemplateField>
:
:
</asp:GridView>
Code Behind:
Private Sub gvComplexRates_RowCommand(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewCommandEventArgs) Handles gvComplexRates.RowCommand
Select Case e.CommandName
Case "Insert"
odsComplexMileageRates.Insert()
End Select
End Sub
Private Sub odsComplexMileageRates_Inserting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ObjectDataSourceMethodEventArgs) Handles odsComplexMileageRates.Inserting
Dim fuelTypeDropDown As DropDownList = gvComplexRates.FooterRow.FindControl("ddFuelTypeInsert")
Dim engineTypeDropDown As DropDownList = gvComplexRates.FooterRow.FindControl("ddEngineTypeInsert")
Dim rateTextBox As TextBox = gvComplexRates.FooterRow.FindControl("tbRateInsert")
Dim vatRateTextBox As TextBox = gvComplexRates.FooterRow.FindControl("tbVatRateInsert")
e.InputParameters("expense_type_id") = ddExpenseTypeSelect.SelectedValue
e.InputParameters("fuel_type_id") = fuelTypeDropDown.SelectedValue
e.InputParameters("engine_type_id") = engineTypeDropDown.SelectedValue
e.InputParameters("rate") = rateTextBox.Text
e.InputParameters("vat_rate") = vatRateTextBox.Text
End Sub
Two of the fields in my FooterRow are DropDownLists that are populated from other tables. Again this works fine and I can add, edit and remove rows without problem.
The problem comes when I use a modal dialog from this page to insert extra rows into the tables used to populate the DropDownLists in the FooterRow. The insert operations work fine and the modal dialog closes and at this point I use a javascript postback (basically a call to __doPostBack()) so that my FooterRow DropDownLists can be updated. The code for this is:
Protected Sub updateFuelEngineDropdowns()
odsFuelTypes.Select()
odsEngineTypes.Select()
Dim dropDown As DropDownList = gvComplexRates.FooterRow.FindControl("ddFuelTypeInsert")
dropDown.DataBind()
dropDown = gvComplexRates.FooterRow.FindControl("ddEngineTypeInsert")
dropDown.DataBind()
End Sub
This sub, updateFuelEngineDropdowns(), is called from the Page Load event. The first time I called it it worked fine. For some reason in subsequent runs through the debugger I'm getting NullReferenceExceptions. Digging into the debug object viewer it is apparent that the GridView FooterRow is referencing the row above the footer which contains no controls (at least not at this non-editing stage) and so, quite reasonably, gives my the Null reference.
The debug QuickView expressions I use are:
gvComplexRates.FooterRow.Controls(3)
DirectCast(gvComplexRates.FooterRow.Controls(3),System.Web.UI.WebControls.DataControlFieldCell).Controls(1)
The first of these shows a tag of td. Which makes sense. The second shows text of "10" which is the content for the row above the footer.
Does anybody know why this is happening?
Thanks Dan
Where are you "providing the missing insert ability"?
You have to rebuild the footer-controls on every postback, the GridView.RowCreated-Event would be a good place.
Update:
You have to Databind your GridView after you inserted new rows into your Dropdowns' Tables.
Right, this is a bit embarrassing. I gave a little white lie in the original question. By omission rather than a deliberate attempt to mislead. I am not, in fact, using a GridView but a subclass of it that will display rows when the datasource contains no data. This enables the user to insert new rows when the table is empty. This subclass overrides the FooterRow property and, to my shame, it was this that was getting things wrong. So I made two errors here: first I failed to test my GridView subclass properly and second I sought to prevent what I thought would be unnecessary attention on my subclass by not showing its use in the code snippets I included in the question. My bad. Thanks to Tim for taking the time to try and help me.
Dan

DropDownList SelectedIndex value not updating on AutoPostback

It looks like this question was addressed here, but his solution did not work for me. I am creating a dynamic dropdown menu system that populates a secondary dropdownlist with the results of a query based on the selected item in the first dropdown.
First dropdown getting populated:
Dim db As New linqclassesDataContext
Dim categories = (From c In db.faq_cats)
NewFaqDropDownCategory.DataSource = categories
NewFaqDropDownCategory.DataTextField = "category"
NewFaqDropDownCategory.DataValueField = "category_id"
NewFaqDropDownCategory.DataBind()
Unset(categories)
Unset(db)
Second dropdown getting populated:
Protected Sub NewFaqDropDownCategory_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs)
Dim temp As Integer = CInt(Val(NewFaqDropDownCategory.SelectedIndex))
MsgBox(theDrop.SelectedValue)
Return
'Dim db As New linqclassesDataContext
'Dim faqs = (From f In db.faqs Where f.category = NewFaqDropDownCategory.SelectedValue)
'NewFaqDropDownList.DataSource = faqs
'NewFaqDropDownList.DataTextField = "question"
'NewFaqDropDownList.DataValueField = "id"
'NewFaqDropDownList.DataBind()
'NewFaqLabel.Visible = True
'NewFaqDropDownList.Visible = True
'Unset(faqs)
'Unset(db)
End Sub
The markup for the first dropdown...
<asp:DropDownList ID="NewFaqDropDownCategory" AutoPostBack="true" runat="server" OnSelectedIndexChanged="NewFaqDropDownCategory_SelectedIndexChanged">
</asp:DropDownList>
And the second...
<asp:DropDownList ID="NewFaqDropDownList" runat="server" Visible="false">
</asp:DropDownList>
No matter what I have tried, I always get "1" (the value of the first item in the second dropdown). The post I referenced earlier said this had to do with AutoPostBack and the server not knowing the list was updated yet.
Can anyone clarify this for me a little more?
Set a break point on the line that reads: NewFaqDropDownCategory.DataBind() and one in your event handler (NewFaqDropDownCategory_SelectedIndexChanged).
I suspect the databind is being called right before your NewFaqDropDownCategory_SelectedIndexChanged event fires causing your selected value to change.
If so, you need either to make sure you only databind if you aren't in the middle of your autopostback or instead of using NewFaqDropDownCategory.SelectedIndex on the first line of your event handler you can cast the sender parameter to a DropDownList and use its selected value.
I had the same problem. Found I forgot to look if I was posting back to the page or not and I was binding my DropDownList control in the Page_Load event of the page.
I had forgot to use:
if (!IsPostBack)
{
.... do databind ....
}
I think there is a bug in your LINQ query for the second drop down box
Dim faqs = (From f In db.faqs Where f.category = NewFaqDropDownCategory.SelectedValue)
Here you are comparing SelectedValue to category. Yet in the first combobox you said that the DataValueField should be category_id. Try changing f.category to f.category_id

Resources