Link to home
Start Free TrialLog in
Avatar of wdarnellg
wdarnellgFlag for United States of America

asked on

So, What if they are just tardy...?

I have code that maks students present or absent. I now need to modify the code so that other attendance types can be recorded such as tardy, excused or unexcused absences. I am not very good with C#, but I don't want that to matter. I have set up some imagebuttons and I would like to run the code and depending on which button was clicked, record the appropriate atendance type.
PresentImageButton_Click = Present
TardyImageButton_Click = Tardy
RainoutImageButton_Click = Rainout
etc... (there are six attendance types)

The code should loop through all CHECKED rows and do nothing to the unchecked ones in this scenario. I am a lost on how to make the changes.
Thanks for help.

wdg

attendancecode.txt
Avatar of Tom Beck
Tom Beck
Flag of United States of America image

I scratching my head here thinking about how I could get this to work with ImageButtons. Problem #1 is there's no way I know of to make a set of ImageButtons mutually exclusive. Meaning, when one is clicked in a set, all others in the same set must be unclicked. You have to prevent users from clicking more than one choice per row. They would need to function like grouped radio buttons. Problem #2, ImageButtons require a postback each time they are clicked. That means the gridview will reload for each ImageButton click. You would have to record each students attendance, one at a time. The way your code is now, you are recording all students' attendance at one time. That's the right way to do this.

The only way I can think to do this is with client side script. For that you'll want a regular html <img wrapped in an <a. Then for each click of an image in a set, you use javascript or jquery to unclick the others in the set AND record the choice in an asp:HiddenField for that row so you can retrieve it server side.

The simpler way might be to have images as labels only and have regular radio buttons centered below each image. The user clicks the radio button of choice rather than an image.
Avatar of wdarnellg

ASKER

User generated imageThanks Tommy.
I am hoping there is a way to point each button's click event to the modified version of the current method, check to determine which button is clicked then insert the right attendance type to the names checked. In the image, I have methods to check or uncheck the boxes. Originally I had a single 'Mark Attendance' linkbutton, but I have the six image buttons in place to give a visual. If the end user clicks a button (say 'E' for excused absence) the E_ImageButton's click event should call the modified UpdateAttendanceButton_Click method. The checked players attendances should record while the unchecked boxes are skipped. The way I have the code now, all rows are recorded with either Present or Absent. The code does quite well really. I just need to meet this new need.
Sorry to only be an Advanced Beginner at this.
You can certainly set this up the way you describe. However, if this is ever going to be used in a real world scenario, you will want to either record all rows in one postback or each row asynchronously as it is clicked. Otherwise, every click will cause the gridview to reload. Depending on how many rows there are, it could take an end user quite a while to get through the list and they would have to endure the constant reloads. Plus, for the sake of the end user's sanity you will want to make sure the selections are preserved in the rendered GridView for each postback.

If you want to do this with six ImageButtons, then your code for recording the attendance becomes very simple. No point anymore in looping through all the rows in the GridView. Instead you will have six OnCommand event handlers, one for each ImageButton. Inside the OnCommand event handlers you can call a function to update the appropriate record. If the person's name is all you need to update the proper record, you can pass the name with the CommandArgument attribute. Here's some information on CommandArgument.
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.imagebutton.commandargument.aspx
ASKER CERTIFIED SOLUTION
Avatar of Alan Warren
Alan Warren
Flag of Philippines image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
@Alan...
I need to update several records at the same time. I don't see how to use a dropdownlist to cover 20 to 60 records at once... can you elaborate more?

@Tommy...
When the Check All link is clicked or if several boxes are clicked and the appropriate letter is clicked, a bulk insert occurs. I think they all record in a single postback.
As for using the imagebutton command, I am confused on how to use a Switch statement since I don't think C# has If-ElseIf.
I am thinking something like

string attendanceType;

Switch(e.CommandName)
Case "Present"
attendanceType = "Present";

Case "Tardy"
attendanceType = "Tardy";

...and so forth...

One click inserts multiple records.
The current code will 'else' to absent and I would like to just insert the checked rows and do nothing with the unchecked ones.
The end user will usually click several rows to mark present, and fewer ones for another choice. Sometimes a single check all will cover everyone such as in a rainout...
But I don't think the grid should reload for each inserted row. I think the loop just runs the stored procedure for each checked row all in a single postback.

Am I remotely on the right track?
In the screenshots you can see the errors I have as I don't quite know how to work through the code yet. Hopefully I am on a the right track.

My first attempt at the switch statement.
User generated image

The switch statement should put the appropriate string in the variable 'attendanceType'.

User generated image
The switch statement is a fine idea but you have not solved the problem with using ImageButtons in this situation. ImageButtons are not check boxes. They do not hold a "clicked" state that can be saved while other buttons are clicked and retrieved on postback the way a checkbox holds a "checked" state. They are a command button just like any other button control in asp.net. AutoPostBack cannot be turned off on an ImageButton so as soon as the user clicks the first one, the page will post back. You will not be able to do inserts on multiple rows at one time.
I like @Alan's idea of using a dropdown. A dropdown box in a GridView row will hold its selection while other rows are being set thus allowing multiple records to be inserted on one postback. I believe you can use images in a dropdown instead of words.
If you desire that all six choices be visible as images for every row then a drop down of course not provide that. Plus, it requires two clicks per row to set. I revert to my original suggestion. Use HTML <img wrapped in <a. Be sure to have a distinct "clicked" state for each image. Then use an asp:HiddenField and javascript to save the selection for each row. This will allow one click per row selection, all choices always visible, and multiple record insert on one submit. JavaScript or jquery will allow you to have "select all" checkboxes at the top of each of the six columns of images.
My basic idea is to have the ability to quickly insert the needed info into the attendance table with minimum effort for the end user.
I am currently adding test data so I can check out both the dropdown idea which I originally misinterpreted. I didn't think to put it in the grid.

I am also confused about how to set up a 'clicked state' for each image. This has me thinking that I need all choices to be available on each row. Is that what you have in mind?
Having all choices available on each row is what I have in mind and it's what was inferred from your original idea of using ImageButtons. I'm suggestion regular html controls instead of ImageButtons since you are only interested in the selections made. Those can be easily recorded for each row on the client side. An ImageButton provides a postback for each selection made and you don't want that. The dropdown would work because selections for each dropdown are returned to the server on postback of the page. AutoPostback can be turned off on an asp:DropDown. Visually however, the user will see only the default selection inside the dropdown on initial load. They would have to click on the dropdown to see the other choices. From the standpoint of giving the user visual clues, a line of images with just letters inside to represent the six attendance possibilities would be like "Attendance Taking for Dummies". They have simple graphics to provide an at-a-glance picture of the day's attendance.

Here's what I am picturing from your description. The user is first presented with a grid listing all the players names and in the images column to the right of the name, all the "P" images are lit up ("present" would be the default). Then the user is free to click (for example) the "A" image next to any player absent and it will lite up instead of "P" for that row. In the header is another group of six images that when clicked, will lite up every image in that category and darken all other images. Do I have the picture correct?

As for setting up a "click" state for each image, this would all be accomplished client side the old fashioned way by swapping in a replacement image (or changing the background position using a sprite) for clicked images. That's just for the user's benefit to give them a visual. For your benefit, handle each image click client side and run some script to record the selection in the hidden field associated with that row. Using an asp:HiddenField in your aspx markup will allow you to retrieve the values of all the hidden fields during one postback. To line up hidden fields with players make sure each player in the database has a unique id. (Bad practice to use names because two players could have the same name.) You can set the id of the hidden field to the player id so that back on the server side you have everything you need to update the rows properly.
Below is the Try-Catch block that I have in place. I just want to be clear that when this code runs it is actually POSTING BACK TO THE PAGE on EACH RECORD. I was under the impression that this code looped through a collection that the grid provides and executes the stored procedure on each selected record upon a single command.
My vision is to have the buttons in a single location. Each button has a different CommandArgument and are linked by the same CommandName. The argument gets passed to the code below and it iterates through the collection and does not post back to the page. Do I have that right?


 New-Microsoft-Word-Document.docx
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I am cool with the dropdownlist. It looks like it will be fine. I was just trying to understand the postback issue as it seems to me the code would run the same stored proc the same way regardless of clicked, checked, or selected control values from a collection. I just wonder if I have that understood correctly or not.

Meanwhile while I am trying to get C# to see the selected values in the datagrid.  :o)
ImageButtons always cause a postback when clicked. During that postback the command event should be handled for that ImageButton. Then the page is returned to the user and the ImageButton is ready to be clicked again. It has no memory of the previous click, it does not hold any value. When you have a GridView full of ImageButtons, clicking any of them causes a postback. When the page returns, that ImageButton is ready for action again. Because of this behavior, there's no way using ImageButtons in a GridView to do multiple inserts on one postback. At what point in the process would a multiple insert occur since any ImageButtons in the GridView that were clicked previously have no "clicked" value to deliver to the server? Once clicked, they have done their job and retain no memory of it.

ImageButton_Command fires only for the ImageButton that was clicked. Actually, when an ImageButton is inside a GridView and it is clicked, the event is "bubbled up" to the GridView so the event handler will know which row's ImageButton was clicked. That's why looping through the rows in the case of an ImageButton is unnecessary.

The way to accomplish this with a single postback is to allow the user to make their selections, record them, have them click a single "Submit" button whichsends the whole lot back to the server for processing. Or use the dropdown, or use radio button groups.
I see. Well, the imagebuttons are NOT in the gridview. The image I show is inside a panel that sits above the gridview and the background colors are the same. :-)
The imagebuttons would do exactly what I need then, IF I could get the correct switch statement.

But, I do like the dropdown list idea better. It will be much faster for the end user and like you said, fewer buttons to deal with. At the moment, I am getting an error that I am scratching my head over...

System.InvalidCastException: The SqlParameterCollection only accepts non-null SqlParameter type objects, not String objects.

It seems I need to find a better way to assign the dropdownlist values to the sql parameter.
The ImageButtons are not in the GridView? How did I get this far into this question and not know that?
IF I could get the correct switch statement.
C sharp switch statement are the same as in javascript.


if (e.CommandName == "Mark")      
{
    switch(e.CommandArgument)
    {
        case "Present":
            attendanceType = "Present";
            break;
        case "Tardy":
            attendanceType = "Tardy";
            break;
        case "Excused":
           
            ....
     
            ....

         default:
            attendanceType = "Present";
    }
}
                        
Having said that, since your attendanceType winds up being the same as the e.CommandArgument in every case except "Instructor", would it not be easier to just say:

attendanceType = e.CommandArgument

... and be done with it?

BTW, how are dropdown lists faster than clickable images if the end user has to click twice on a dropdown list to change the default selection?

I like @informaniac's radio buttons sample better than a dropdown.
I have tried the radio buttons once I saw the post from @informaniac (I actually missed it earlier). Thank you informaniac!

 I am having a problem getting the values from them however. The .selectedvalue keeps returning an empty string.

ASCX CODE
<asp:TemplateField HeaderText="Mark Attendance">
				<ItemTemplate>
                <asp:RadioButtonList id="MarkAttendanceRadioButtonList" runat="server" RepeatDirection="Horizontal">
                    <asp:ListItem Text="Present" Value="0"></asp:ListItem>
                    <asp:ListItem Text="Tardy" Value="1"></asp:ListItem>
                    <asp:ListItem Text="Excused" Value="2"></asp:ListItem>
										<asp:ListItem Text="Unexcused" Value="3"></asp:ListItem>
                </asp:RadioButtonList>
				</ItemTemplate>
			</asp:TemplateField>

Open in new window



C# CODE:
				foreach (GridViewRow row in CurrentRosterGridView.Rows)
				{
					////The Attendance data to be collected
					var regId = (Label) row.FindControl("RegIDLabel");
					var rb1 = row.FindControl("MarkAttendanceRadioButtonList") as RadioButtonList;
					var ec = new SqlParameter("@ERRORCODEOUT", SqlDbType.Int) {Direction = ParameterDirection.Output};
					if (rb1 != null)
						{
							string strSelectedValue = rb1.SelectedValue; 
							var attType = new SqlParameter("@AttendanceType", SqlDbType.NVarChar) {Value = strSelectedValue};

Open in new window

Hi wdarnellg,

Curious how the CurrentRosterGridView is being populated, a SqlDataSource, some other means? Anyway by whatever means it is being populated, I expect there is some SQL in there somewhere, that SQL script might be helpful in providing a solution. Doesn't really matter how many records there are to be updated, we just need to know the rules to apply and some table schema. We can update the entire catalog with some SQL logic, then use the dropdownlist or radiobuttons or imagebutton array to maintain the data thereafter.

Alan
Hi Alan. I am using a storedproc to populate the grid. The user clicks the select link in order to view detailed profile info provided by the results of the query. If the end user wants to add attendance info they must select (as of now I have radio buttons to select the attendance type) then click Mark Attendance to check validation and run a separate insert stored proc.

Currently when the insert is processing, the values in the radio buttons are not being populated in the variables for processing... Anyway, below is the stored proc that populates the CurrentRosterGridView.

STORED PROCEDURE [dbo].[GetMyCurrentRosters] 
	-- Add the parameters for the stored procedure here
@username nvarchar(50)
,@SiteID nvarchar(100)
AS
BEGIN
	-- SET NOCOUNT ON added to prevent extra result sets from
	-- interfering with SELECT statements.
	SET NOCOUNT ON;
SELECT        Players.FirstName + ' ' + Players.LastName AS SlamJammer, Players.Gender, dbo.ufn_GetAge(Players.Birthdate, GETDATE()) AS Age, 
                         Players.Ethnicity, Programs.Title AS [SJ Level], Sessions.SessionName AS Session, Players.PlayerID, 
                         Registrations.RegID
FROM            Players INNER JOIN
                         Registrations ON Players.PlayerID = Registrations.PlayerID INNER JOIN
                         SiteReg ON Registrations.SiteRegID = SiteReg.SiteRegID INNER JOIN
                         Sessions ON SiteReg.SessionID = Sessions.SessionID INNER JOIN
                         Programs ON SiteReg.ProgramID = Programs.ProgramID INNER JOIN
                         Directors ON SiteReg.DirectorID = Directors.SiteDirectorID
WHERE        (Sessions.EndDate > GETDATE()) AND (Directors.Username = @username) AND (SiteReg.SiteID = @SiteID)
ORDER BY Session, [SJ Level], Players.LastName
END

Open in new window

Are you binding the GridView on PageLoad?

Have u ensured you have the

if(!isPostBack) in the Page_Load?
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hi wdarnellg,

where will you be storing the AttendanceType value?
I suspect there will be numerous events to attend in the Fall 2012 session.

I have everything else updating without any code at all, not styled yet, here's a preview.
I have dropdown lists for gender and ethnicity. The playerID column is currently visible, but will not be visible later.
User generated image
Alan
@alanwarren
I store the values in an attendance table which is a child to the registration table.
I tried using just the controls, but I use stored procedures to display from joined tables then have to update tables separately. I had some problems with sqldatasource and parameters that were not a part of the select statements.
This was a tough one to split the points on for me since I really liked two choices almost equally. But I learned a lot about the controls involved.