ASP.NET 2.0 with conditional radio button in a GridView - c#

I'm looking to have a GridView displaying "Events" from a database, and then in the last column I want to do another database lookup (for each row) to see if that event is full or not.
If it's not full, display a radio button. If it is full display text "Full".
I think this is best done with OnRowDataBound event but could use a little help.
I can see how to change an asp label text but not display a radio button.
register.aspx:
<asp:GridView ID="GridView2" runat="server" DataSourceID="SqlDataSource2" AutoGenerateColumns=false CellPadding="5" HeaderStyle-BackColor="DarkGray" Width="450px" OnRowDataBound="GridView2_OnRowDataBound">
<Columns>
<asp:BoundField DataField="sessionDate" HeaderText="Date" DataFormatString="{0:D}" />
<asp:BoundField DataField="sessionTime" HeaderText="Time" />
<asp:BoundField DataField="site" HeaderText="Site" />
<asp:BoundField DataField="room" HeaderText="Room" DataFormatString="{0:D}" />
<asp:TemplateField HeaderText="">
<ItemTemplate>
<input type="radio" name="rdoSessionID" value='<%# Eval("ses_ID") %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
<HeaderStyle BackColor="#99CCFF" />
</asp:GridView>
<br />
<asp:SqlDataSource ID="SqlDataSource2" runat="server" ConnectionString="<%$ ConnectionStrings:sqlConnection2 %>"
SelectCommand="SELECT * FROM dbo.sessions WHERE site LIKE #ses_site AND sessionDate = #ses_date ORDER BY sessionDate">
<SelectParameters>
<asp:SessionParameter name="ses_site" SessionField="ses_site" Type="String" />
<asp:SessionParameter name="ses_date" SessionField="ses_date" Type="String" />
</SelectParameters>
</asp:SqlDataSource>

There are a few ways you can do this.
You can do this on the OnRowDataBound , If the Item you're dealing with is a DataItem, grab the value you need from the current row, and do a quick DB Lookup
When you get your resultset back from the database, do another lookup on each event. This way when your data leaves your data layer / methods you already have everything you need.
Modify your SQL query to return this information with the list of events. You already know the Events, you could just have a sub query to query to see if it's full or not (or the # of people registered, and the Max # allowed so you can show that). This way you only have to do 1 hit against the database and it will save you a bunch of processing. (My favorite)
You would still need to overload the OnRowDataBound event for all 3 of those solutions. You'd hide the radio button if it was full, and ensure it was visible if the event was not full. The difference is where do you get your data.
Do you want to do:
1 Good hit (list of events)
X amounts of small hits for each event
or
1 Good hit for list of events + if each event is full or not.
If you want to entertain #3, post your SQL Query and we can go from there.
Quick example of the OnRowDataBound event.
protected void MyGridView_OnRowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
CheckBox cbox = (CheckBox)e.Row.FindControl("chkBox");
// Do some funky logic
cbox.Visible = Event.HasRoom; //Boolean Propery
// Or
cbox.Visible = Convert.ToBoolean(DataBinder.Eval(e.Row.DataItem, "HasRoom").ToString());
}
}
Update 1:
For your GridView, You can use
<ItemTemplate>
<asp:CheckBox runat="server" ID="Checkbox1" ToolTip=" Sign up For event " text="Event stuff" />
</ItemTemplate>
If you want to use a template, don't use a regular control, use a control.
For the query you could do the following. I'm not 100% sure on your table structure so I did it the way I normally would:
Table: Session (sess_id(PK), SessionDate, SessionTime, Site, Room)
Table: Registrants (RegistrantID (PK), sess_id (FK to Session), UserID (FK to users that are registered)
SELECT SessionDate, SessionTime, Site, Room, ses_ID,
(SELECT Count(ses_ID) FROM Registrants R WHERE R.Ses_ID= S.ses_Id) as [Registrants]
FROM dbo.Sessions s

Use the OnRowDataBound event, like this:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
RadioButton radio = e.Row.FindControl("RadioButton1") as RadioButton;
if (radio != null)
{
radio.Visible = SomeCheckThatReturnsBoolean((int)GridView1.DataKeys[e.Row.RowIndex]["SomeID"]);
}
}
If possible though, you should return the data with the GridView results, and store the value in a data key, so you can do something like this:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
RadioButton radio = e.Row.FindControl("RadioButton1") as RadioButton;
if (radio != null)
{
radio.Visible = (bool)GridView1.DataKeys[e.Row.RowIndex]["SomeBooleanValue"];
}
}
EDIT: Based on your comment to #Ryan, I think you should be able to include that flag in your query. I don't know your database at all, but you can try using a derived table or subquery to get the registrant session counts. Here's a rough example to work off of:
SELECT ID,
ISNULL(Registrants.RegistrantCount, 0) RegistrantCount
...
FROM Table1 t1
LEFT OUTER JOIN (
SELECT ForeignKeyID,
COUNT(RegistrantID) RegistrantCount
FROM Registrants
GROUP BY ForeignKeyID
) Registrants
ON Registrants.ForeignKeyID = t1.ID

Related

Gridview Delete Button - Object Reference Error

I am trying to develop a web page in asp .NET with a GridView. I want the GridView to have an edit and delete button. Following is my markup for GridView:
<asp:GridView ID="EduGrid" CssClass="edugrid table table-striped table-hover table-borderless" runat="server" AutoGenerateColumns="False" GridLines="None" OnRowDeleted="EduGrid_RowDeleted" OnRowDeleting="EduGrid_RowDeleting">
<Columns>
<asp:CommandField SelectText="" ShowSelectButton="True" ControlStyle-CssClass="btn btn-dark btn-sm fa fa-edit" />
<asp:CommandField DeleteText="" ShowDeleteButton="true" ControlStyle-CssClass="btn btn-dark btn-sm fa fa-trash" />
<asp:BoundField DataField="degree" HeaderText="Degree" SortExpression="degree" />
<asp:BoundField DataField="major" HeaderText="Major" SortExpression="major" />
<asp:BoundField DataField="year" HeaderText="Passing Year" SortExpression="year" />
<asp:BoundField DataField="total marks" HeaderText="Total Marks" SortExpression="total marks" />
<asp:BoundField DataField="obt marks" HeaderText="Obtained Marks" SortExpression="obt marks" />
<asp:BoundField DataField="division" HeaderText="Division" SortExpression="division" />
<asp:BoundField DataField="board" HeaderText="Board/University" SortExpression="board" />
</Columns>
<HeaderStyle CssClass="thead-dark" Font-Names="Calibri" Font-Size="Larger" />
<RowStyle Font-Names="calibri" Font-Size="Medium" />
</asp:GridView>
I also have a label on the page "CandId" that contains ID to get records in GridView and delete the records from DataBase. But, as there are more than 1 records for each candidate, I want to delete the records on the base of 2 parameters i.e. ID & Degree (the first column). It deletes on the base of ID only but deletes all the records of that specific ID, but I only want to delete one specific entry. If I provide the degree column as a parameter, it gives an object reference exception. Following is my backend code in c#:
protected void EduGrid_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
GridViewRow row = EduGrid.SelectedRow;
conn = new SqlConnection(connString);
string query = "DELETE FROM [Edu Info] WHERE cnic = #cnic AND degree = #degree";
sqlcmd = new SqlCommand(query, conn);
sqlcmd.Parameters.AddWithValue("#cnic", lblID.Text);
sqlcmd.Parameters.AddWithValue("#degree", row.Cells[1].Text);
try
{
conn.Open();
sqlcmd.ExecuteNonQuery();
lblInfo.Text = "Record deleted successfully.";
lblInfo.Visible = true;
Get_Edu();
}
catch (Exception ex)
{
lblInfo.Text = "An error occurred. Please contact the administrator.";
lblInfo.Visible = true;
}
finally
{
conn.Close();
conn.Dispose();
SqlConnection.ClearAllPools();
}
}
I think the problem is that the method OnRowDeleting is not suitable to work with GridView.SelectedRow and that .SelectedRow can only work in the OnSelectedIndexChanged method. If that is the case and I am right, what should I do to fix it? Can anyone please provide a solution?
Thanks.
Ok, lot of issues here. And I not clear why your data source does NOT include the primary key of the database. And as a result, you should not need to use both cnic and degree to identify a row. I cannot EVER recall having rows in a grid in which I don't have a PK ID. (so, very strange on your part).
However, do keep in mind that the delete event does NOT change the selected index. In fact if you drop in say a button, use commandName/CommandText, you find that the row command fires FIRST (selected index not yet changed), and THEN the selected index event fires.
In your example - index will not change.
However, in that event, you can get the row clicked on with with this:
e.RowIndex
So, you can now go like this:
GridViewRow row = EduGrid.Rows[e.RowIndex];
So, the rest of what you have thus should be ok. So, just keep in mind that for command buttons, and most buttons in the grid, the selected index even (if it were to fire) in fact fires AFTER the button event stub. In some cases then you could in theory move the code to the selected index changed event - but that does not even fire in this case. So selected index is NOT available. Use e.RowIndex to get that row.
Also, if you include the PK from the datbase, then you don't need to use the two columns to identify that row in the datbase, but ONLY the PK row id. And you do NOT have to have the PK even display in the grid.
That's what DataKeyNames = "the PK row column name" is for"
eg:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataKeyNames="ID" >
So, DataKeyNames = "PK FROM database"
Thus in above RowDeleting event, then
e.RowIndex - gets you row index clicked on
e.Keys["ID"] - gets you database PK
So, note how you can (should) try and set the DataKeyNames = "primary key" from database. then you can get with e.Keys["ID"] the PK row id.

How do I get the row I clicked with a button

I have a grid view and when I click on the button I wanted to do a SQL command to see which Order number was pressed. How do I get the row I have clicked on?
asp
<asp:GridView ID="GridView1" runat="server"
DataKeyNames="No_" AutoGenerateColumns="false" style="color:Black;border-collapse:collapse;margin-right: auto;display: table;text-align: center;" OnPageIndexChanging="MyGrid_PageIndexChanging" OnRowDataBound="MyGrid_RowDataBound" AllowPaging="True" PageSize="20" AllowCustomPaging="False" >
<Columns>
<asp:BoundField DataField="No_" HeaderText="No_Encomenda" />
<asp:BoundField DataField="[Item No_]" HeaderText="Item number" />
<asp:BoundField DataField="Quantity" HeaderText="Quantity" />
<asp:TemplateField HeaderText="Select">
<ItemTemplate>
<asp:CheckBox ID="CheckBox1" runat="server" OnCheckedChanged="CheckBox1_CheckedChanged" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
<PagerSettings Mode="NumericFirstLast" PageButtonCount="4" FirstPageText="First" LastPageText="Last"/>
<PagerStyle CssClass="gridview" HorizontalAlign="Center" VerticalAlign="Middle"/>
</asp:GridView>
cs
protected void ButtonDetails_Click(object sender, EventArgs e)
{
MyGrid.Visible = false;
GridView1.Visible = true;
}
Gridview image:
Well, first of all, in your markup, I don't see a button in your markup. So the picture you have, and the markup don't agree with each other.
There are about 3 great ways to get the row click with a button.
Most common:
Drop in a the button. Say like this:
<asp:TemplateField HeaderText="View">
<ItemTemplate>
<asp:Button ID="cmdView" runat="server" Text="Details" CommandName="Select" />
</ItemTemplate>
</asp:TemplateField>
Note how we added the CommandName = "select". This is a special option that will trigger the Gridivew RowIndexed changed. It ALSO triggers the row command. But, in row command the "selected row event" has not yet triggered. So, I just ignore the row command event, and put your code in the selected index changed event.
protected void MyGrid_SelectedIndexChanged(object sender, EventArgs e)
{
// Get selected row
GridViewRow dG = MyGrid.SelectedRow;
Response.Write("Row index was " + dG.RowIndex.ToString());
// get non templated columns - they appear in cells
Response.Write("2nd colum value = " + dG.Cells[1].Text);
// get templated fields - say a combo box for city
DropDownList CityComboBox = (DropDownList)dG.FindControl("DropDownList1");
Response.Write("City selected from combo box = " + CityComboBox.SelectedValue);
}
So by JUST adding the CommandName = "Select", then this will trigger the SelectedinddexChanged event.
Another way is to use the row command (but you have to pass the row index to that event).
But, a really slick way is to 100% ignore the grid events, and JUST use your button.
You can do it this way:
Drop in the button. But now you can't double click on the button to wire up the click event, but you CAN STILL set the event for the click.
While in the markup you can thus type in OnClick= NOTE VERY careful the intli-sense that pops up - it looks like this:
So in the above choices - choose the create new event - it SEEMS like nothing occurred, but when you flip back to code-behind, you have a nice simple clean, good old regular button click event.
Droop a button - create click event. You can now just 100% ignore the complex GridView events (and that select command etc.).
You do this way now:
protected void Button3_Click(object sender, EventArgs e)
{
Button MyButton = (Button)sender;
GridViewRow dG = (GridViewRow)MyButton.Parent.Parent;
Response.Write("Row index was " + dG.RowIndex.ToString());
// get non templated columns - they appear in cells
Response.Write("2nd colum value = " + dG.Cells[1].Text);
// get templated fields - say a combo box for city
DropDownList CityComboBox = (DropDownList)dG.FindControl("DropDownList1");
Response.Write("City selected from combo box = " + CityComboBox.SelectedValue);
}
I find the above is less hassle, but also LESS learning curve to use. We drop in a button - click event. You just pick up the "sender" into a button, and then get parent.parent which turns out to be the grid row we want.
The first parent is I think some cell divider. In fact I use this .parent trick all the time. Thus buttons are a simple button dropped into the grid markup, and we use the standard button click event and code approach.
But, hey, we really don't care about the GridVieew row command, and we really dont' care about the Selected index changed.
We have a button click. So now you can use this slick trick to save world poverty's, save using complex GridView events, and just code up a simple button like any other button.
And we get FULL USE of the grid view row with this trick.

Selecting multiple rows in GridView with checkboxes: Program not pulling data

I have been coming across a strange bug/error in my code when attempting to select and pull data from multiple rows in GridView controls.
Background:
In short, I have a GridView item, populated with rows of different equipment items that are "checked in" and available to check out of our system. I want to have the user able to select multiple items and check them out at once, rather than doing it X times.
I am using a check box item on each row to do this, like so: http://i.imgur.com/fPYV2.png
There is a button at the bottom to check the equipment out of our database.
Code:
The code I am using to generate the ASPX page is:
<asp:GridView ID="grdEquipment" runat="server" AutoGenerateColumns="false" ShowHeaderWhenEmpty="true" CssClass="table table-bordered">
<Columns>
<asp:TemplateField HeaderText="Select">
<ItemTemplate>
<asp:CheckBox ID="chkMultiSelect_Out" runat="server" />
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField HeaderText="Equipment Name" DataField="Name" />
<asp:BoundField HeaderText="Category" DataField="Category.Name" />
</Columns>
<EmptyDataTemplate>
There is no equipment to display.
</EmptyDataTemplate>
</asp:GridView>
<div class="well">
<asp:Button ID="btnCheckOut" runat="server" CssClass="btn btn-small btn-inverse" Text="Check Out" OnClick="btnCheckOut_Click" />
</div>
This works and compiles with no problem.
The code running the button to check everything out is:
protected void btnCheckOut_Click(object sender, EventArgs e)
{
int checkoutNumber = 0;
//string id = (sender as Button).Attributes["data-id"].ToString();
SortedBindingList<Tracker.Business.Equipment> eqList = Tracker.Business.EquipmentList.FetchAll();
foreach (GridViewRow row in this.grdEquipment.Rows)
{
CheckBox chkMultiSelect_Out = (CheckBox)row.FindControl("chkMultiSelect_Out") ;
if (chkMultiSelect_Out.Checked)
{
checkoutNumber++;
Tracker.Business.Equipment equip = Tracker.Business.Equipment.GetByIdentification(Int32.Parse(row.ID.ToString()));
eqList.Add(equip);
}
}
//If checkoutNumber is 0, do nothing.
//If checkoutNumber is 1, launch popup for only 1 item
//If checkoutNumber is more than 1, launch popup for multiple items.
if (checkoutNumber == 0)
{
Response.Redirect("~/Equipment/CheckInOut/Default.aspx");
}
else if (checkoutNumber == 1)
{
}
else if (checkoutNumber > 1)
{
}
}
Now, OBVIOUSLY, this code isn't finished. I am debugging as I go to make my life easier.
The important code is the foreach loop where I check each row for the control item, and see if it is checked or not.
The Problem:
When I run the code, and test with some check boxes checked, it looks at all the rows, and ALL of them have "Checked = false" as an attribute. What's worse, I found out later that it doesn't even grab the data from the row, as shown in this screen shot here: http://i.imgur.com/clRuk.png
The text should be "Optimus Prime" or "Switch #1", however it is not! And both are checked when I run the code, yet the code sees only false checked items.
The code runs through the foreach loop for each row, i.e., 3 rows, it runs through the loop 3 times. So it sees each row, yet it is not pulling the data...
Where should I start looking?
I fixed my problem. As Tim Schmelter said, I was postbacking the page on every click, so I changed my code to databind the gridview table only on a page load, and not on a post back. Works now!

Get selected value from drop down inside GridView on Update

So I have some GridView. When you edit a row, a particular column changes from a label to a DropDownList. The content of this drop down is populated via some SQL data source.
The user may make a selection choice and click "Update".
How can I actually get at the SelectedValue property of the drop down?
I thought this would work:
<asp:GridView ... >
<Columns>
...
<EditItemTemplate>
<asp:DropDownList ID="ServiceCategoriesGvDropDown" AutoPostBack="True" .../>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ... />
</ItemTemplate>
</asp:TemplateField>
...
</Columns>
</asp:GridView>
And then wire it up with a ControlParameter in my SqlDataSource:
<UpdateParameters>
...
<asp:ControlParameter ControlID="ServiceCategoriesGvDropDown" PropertyName="SelectedValue" ... />
</UpdateParameters>
However, I get the following exception:
System.InvalidOperationException: Could not find control 'ServiceCategoriesGvDropDown' in ControlParameter 'ServiceCategoriesID'.
So clearly my drop down doesn't get found. Perhaps it's been destroyed by this point?
try this in the updating event of the grid.
protected void YourGrid_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
DropDownList ddl= (DropDownList )YourGrid.Rows[e.RowIndex].FindControl("ddlId");
string selectedvalue=ddl.selectedvalue;
//Your update code goes here
}
What I think you need to do is:
Attach a SelectedIndexChange event to the DropDownlist on your Gridview
Grab the SelectedValue on that event.
Grab a reference to your DataSource's UpdateParameters and populate the respective parameter programmatically with the SelectedValue.
Call your DataSource's Update method.
You can try doing this:
assuming the ID of the gridview is gridview1
<asp:ControlParameter ControlID="gridview1$ServiceCategoriesGvDropDown" PropertyName="SelectedValue" />

How to sort items that are databound

I have a problem that has been a thorn in my side for nearly a week. I have a site that users can create an account and load videos of there choosing from a database. I would like the videos to show up in a certain order on there page when they look at the ones they selected. My problem is that the videos show up in a random order. I know this may be basic but I am just now entry level (has only been two weeks since I graduated). All the functionality works, so no help needed there, just this darn order thing.
Specs:
Coded in C# ASP.NET
They add and delete selections via checkbox list.
I have the items databound so I can add and remove videos on the back end.
I know this may get me some minus votes, and though I would prefer it not, I just need some help with this issue to be done with the whole project. Before you yell at me for not having code, please tell me what you would like to see so I don't add tons of useless code.
I am not trying to me short, rather I am frustrated that everything I tried won't work.
Thank you in advance.
EDIT:
Here is the SqlDataSource for it:
<asp:SqlDataSource ID="SqlDataSource2" runat="server"
ConnectionString="<%$ ConnectionStrings:fivideoConnectionString %>"
ProviderName="<%$ ConnectionStrings:fivideoConnectionString.ProviderName %>"
InsertCommand="INSERT INTO dealervideo(DealerRecID,VideoRecID) VALUES (?,?)"
DeleteCommand="DELETE FROM dealervideo where RecID = ?" >
<DeleteParameters>
<asp:SessionParameter Name="recid" SessionField="videorecid" />
</DeleteParameters>
<InsertParameters>
<asp:ControlParameter ControlID="hidRecID" Name="recid" PropertyName="Value" />
<asp:SessionParameter Name="videorecid" SessionField="videorecid" />
</InsertParameters>
</asp:SqlDataSource>
And here is the Gridview:
<asp:GridView ID="GridView2" runat="server"
DataSourceID="SqlDataSource2" AutoGenerateColumns="False"
DataKeyNames="RecID" CellSpacing="5" BorderStyle="None" BorderWidth="0px">
<Columns>
<asp:TemplateField HeaderText="Delete">
<ItemTemplate>
<asp:CheckBox ID="cbDelete" runat="server" />
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Title" HeaderText="Title" SortExpression="Title" />
</Columns>
</asp:GridView>
And this is the event when they click to add a video to the list:
protected void btnAddVideo_Click(object sender, EventArgs e)
{
foreach (GridViewRow gvr in GridView3.Rows)
{
CheckBox chkItem = (CheckBox)gvr.FindControl("cbAdd");
if (chkItem.Checked)
{
String sRecID = GridView3.DataKeys[gvr.RowIndex].Value.ToString();
Session["videorecid"] = sRecID;
SqlDataSource2.Insert();
SqlDataSource2.SelectCommand = "SELECT * FROM dealervideo inner join videos on videos.RecID = dealervideo.VideoRecID inner join dealers on dealers.RecID = dealervideo.DealerRecID where dealers.RecID = " + hidRecID.Value;
}
}
GridView2.DataBind();
Add an "ORDER BY" to your Select Command and the field which you want it to be ordered on.
Example:
SqlDataSource2.SelectCommand = "SELECT * FROM dealervideo inner join videos on videos.RecID = dealervideo.VideoRecID inner join dealers on dealers.RecID = dealervideo.DealerRecID where dealers.RecID = " + hidRecID.Value + " ORDER BY videos.RecID";
I assume you are binding to the results of a stored procedure or sql command? In that case, why not use an "Order By" clause in your SQL statement? The items will be displayed in the order in which they are pulled from the database.

Categories