My question is basically whether I should try this new gridview thing, or do it my old school way with a datalist. Basically I have a mini Content managment situation. I am using a gridview to display a listing of employees. In the database i have a column
called sortid, which is used to order the records for display on the front side of the site.
Now with the datalist i would access the clicked rows datakey and the previous rows datakey and swap them.
case "sortup"
MoveRecord(e.commandArgument.tostring(),employeeDL.DataKeys(e.Item.ItemIndex - 1).ToString())
case "sortdown"
MoveRecord(e.commandArgument.tostring(),employeeDL.DataKeys(e.Item.ItemIndex + 1).ToString())
The e.Item.ItemIndex does not seem to be a property of the Gridview's EventCommand (GridViewCommandEventArgs). Any suggestion is greatly appreciated. I really love the simplicity of the gridviews editing and deleting.
Nope not looking to sort, but rather move an individual item up or down one row in a listing. For example, if you have some print ad pricing in a grid, you may want them to appear in a certain order.
Full Page
Half Page
1/4 Page
1/8 page
Sorting will not always work, so i wanted to give the user complete control on which order the records are displayed. I add a sortid column to the db and that will control "importance". In the gridview you can choose to move half page above full page. With
a gridview it works like this :
sub ChangeSort(ByVal sender As Object, ByVal e As GridViewCommandEventArgs)
Select Case e.Commandname
case "sortup"
try
MoveRecord(printAdGrid.DataKeys(e.commandArgument).value.ToString(),printAdGrid.DataKeys(e.commandArgument - 1).value.ToString())
catch ex as exception
end try
case "sortdown"
try
MoveRecord(printAdGrid.DataKeys(e.commandArgument).value.ToString(),printAdGrid.DataKeys(e.commandArgument+ 1).Value.ToString())
catch ex as exception
end try
end select
end sub
'''''''''''''''' then have a sub for updating the sql, im sure someone has a better way, but this is my hack
sub MoveRecord(thisid as string,movetoid as string)
Dim strConn as string
Dim conn as SQLConnection
Dim intResults as Integer
strConn = ""
conn = New SQLConnection(strConn)
conn.Open()
dim strSQL1 = new String("update printads set sortid = '99999' where sortid = '"+movetoid+"'")
dim strSQL2 = new String("update printads set sortid = '"+movetoid+"' where sortid = '"+thisid+"'")
dim strSQL3 = new String("update printads set sortid = '"+thisid+"' where sortid = '99999'")
dim command1 = new SQLCommand(strSQL1, conn)
dim command2 = new SQLCommand(strSQL2, conn)
dim command3 = new SQLCommand(strSQL3, conn)
try
intResults = command1.ExecuteNonQuery()
intResults = command2.ExecuteNonQuery()
intResults = command3.ExecuteNonQuery()
Sqlsource.SelectCommand="SELECT * FROM printads order by sortid asc"
catch ex as exception
response.Write(ex.message)
end try
Yes - your solution is pretty simple. I had some coding done on the page where I needed this feature, because I had Insert, Edit and Delete options there as well. Also I implemented this through AJAX without posting back the whole page. The code becomes
more chalanging when you need to make sure your order stays the same or moves one up when you delete a record. Also - I moved my Up / Down buttons out of the GridView.
Here is an exact example of what I've implemented
http://www.obout.com/grid/grid_move_rc_up_down.aspx - buttons "Move Up" and "Move Down" are outside the gridview, although most of the examples on the web have those buttons in each row of the grid. Also I had decided to save the sequence to the database
every time the row was moved because if somebody moves the row and than decides to delete it before saving the sequence - you 've got the wrong record deleted...ops...
I see this thread is old but perhaps someone might still benefit from my code samples below. My GridView, named gvInvItem, allows the user to move rows up and down and retain a custom row order. Procedures below include how to deal with inserts and deletes. I
find that using the GridView events to do a custom row sort is more efficient than writing separate procedures that are redundant to features already available in GridView.
Private intGvInvItemLastRow
As Integer = 0 ' remember last row to use in RowdataBound tasks
Protected Sub gvInvItem_DataBound(ByVal sender As Object, ByVal e As System.EventArgs) Handles gvInvItem.DataBound
' This event fires after all RowDataBound events, so here we do some cleanup that is difficult to do in RowDatBound:
Try
' If this datagrid only has one row, disable the Down button (Top button has already been disables in RowCommand event)
If gvInvItem.Rows.Count = 1 Then
' Create a reference to the Down button
Dim butMoveDown As Button
butMoveDown = gvInvItem.Rows(0).FindControl("butMoveDown")
' This event appears to fire after a row has been deleted. When user has deleted the last row, here it still shows a gvInvItem.Rows.Count = 1.
' Don't know why it doesn't show gvInvItem.Rows.Count = 0 here. So, to avoid an error, we must check for existance of butMoveDown
If butMoveDown IsNot Nothing Then
butMoveDown.Enabled = False
End If
End If
Catch ex As Exception
ProjectCommon.ReportErrors(Page, ex, "reported from gvInvItem_RowDataBound")
End Try
End Sub
Protected Sub gvInvItem_RowCommand(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewCommandEventArgs) Handles gvInvItem.RowCommand
' Purpose: process Up, Down and Delete buttons.
' Note: Logic below works in conjunction with procedure:
' butInsertItem_Click (only inserting at botton of sort and inserting proper sort order value)
' gvInvItem_DataBound (top row "Up" button disabling)
' gvInvItem_RowDataBound (bottom row, "Up" and "Down" button disabling).
' gvInvItem_RowCreated (sets button command arguments)
Dim intRowIndex As Integer
Try
' Process clicking the Move Up button or Move Down buttons that swap row order
If e.CommandName.ToString = "MoveUp" Or e.CommandName.ToString = "MoveDown" Or e.CommandName.ToString = "Delete" Then
' User wants to move the current row up or down one in the sort order
' Convert the row index stored in the CommandArgument
' property to an Integer.
intRowIndex = Convert.ToInt32(e.CommandArgument)
' Get the value of the key field of the row being updated
Dim strKey As String = gvInvItem.DataKeys(intRowIndex).Value.ToString
Dim lblEveSortOrderView As Label
Dim txtEveSortOrderEdit As TextBox
Dim intSafetyOut As Integer = 0
Dim intOriginalEveSortOrder As Integer = 0
' Get the label control holding the yet unchanged sort order integer
lblEveSortOrderView = gvInvItem.Rows(intRowIndex).FindControl("lblEveSortOrderView")
' Store this into an integer
intOriginalEveSortOrder = Val(lblEveSortOrderView.Text)
' Loop through all rows, top to bottom.
' Note: If-Else logic must consider that any update within the loop resorts the rows per intEveSortOrder between each loop.
For intIndex As Integer = 0 To gvInvItem.Rows.Count - 1 And intSafetyOut < 1000
' Safety below, I managed while debugging this to once go into an unbreakable update loop. I had to kill the
' SQL Server process to recover. So, as a safety, this loop forcefully stops itself after 1000 loops.
intSafetyOut += 1
' Edit the row that we our now on as we are looping
gvInvItem.EditIndex = intIndex
' Bind is required to get into edit mode. Note this resorts grid, but since we are going top to bottom, should be no problem.
gvInvItem.DataBind()
' Get a reference to the textbox that holds the 0-based sort order integer
txtEveSortOrderEdit = gvInvItem.Rows(intIndex).FindControl("txtEveSortOrderEdit")
If e.CommandName.ToString = "MoveUp" Then
If Val(txtEveSortOrderEdit.Text) < (Val(lblEveSortOrderView.Text) - 1) Then
' If the current rows's sort order is less than the original sort order -1, do nothing and loop.
ElseIf Val(txtEveSortOrderEdit.Text) = (intOriginalEveSortOrder - 1) Then
' If the current rows's sort order is exactly 1 less than the original sort order -1, Add 1
txtEveSortOrderEdit.Text = Val(txtEveSortOrderEdit.Text) + 1
gvInvItem.UpdateRow(intIndex, False)
' Since sort order updates on every databind, substract one from inIndex to make sure we do not skip processing the original row
intIndex = intIndex - 1
ElseIf gvInvItem.DataKeys(intIndex).Value.ToString = strKey Then
' If we are on the original row, Subtract 1
txtEveSortOrderEdit.Text = Val(txtEveSortOrderEdit.Text) - 1
gvInvItem.UpdateRow(intIndex, False)
Else
' ' Do nothing and loop.
End If
ElseIf e.CommandName.ToString = "MoveDown" Then
If Val(txtEveSortOrderEdit.Text) < intOriginalEveSortOrder Then
' If the current rows's sort order is less than the original sort order, do nothing and loop.
ElseIf gvInvItem.DataKeys(intIndex).Value.ToString = strKey And Val(txtEveSortOrderEdit.Text) = intOriginalEveSortOrder Then
' If we are on the original row, Add 1 if we have not already done so
txtEveSortOrderEdit.Text = Val(txtEveSortOrderEdit.Text) + 1
gvInvItem.UpdateRow(intIndex, False)
' Since sort order updates on every databind, substract one from inIndex to make sure we do not skip processing the original row
intIndex = intIndex - 1
ElseIf (Val(txtEveSortOrderEdit.Text) = (intOriginalEveSortOrder + 1)) _
And (gvInvItem.DataKeys(intIndex).Value.ToString <> strKey) Then
' If the current rows's sort order is exactly 1 more than the original sort order, Subtract 1
txtEveSortOrderEdit.Text = Val(txtEveSortOrderEdit.Text) - 1
gvInvItem.UpdateRow(intIndex, False)
Else
' Do nothing and loop.
End If
ElseIf e.CommandName.ToString = "Delete" Then
' Process clicking the Delete button, reorder the intEveSortOrder values.
' Note this event fires before the actual row is deleted. So reorder rows now.
' one row, make each sort value the first row a sort order of 0
If intIndex <= intOriginalEveSortOrder Then
' Sort order is before the deleted row
If intOriginalEveSortOrder = 0 Then
' User deleted top row. Do nothng and loop.
End If
Else
' subtract 1
txtEveSortOrderEdit.Text = Val(txtEveSortOrderEdit.Text) - 1
gvInvItem.UpdateRow(intIndex, False)
End If
End If
Next
' Cleanup: take any current row out of edit mode
gvInvItem.EditIndex = -1
End If
Catch ex As Exception
ProjectCommon.ReportErrors(Page, ex, "reported from gvInvItem_RowCommand")
End Try
End Sub
Protected Sub gvInvItem_RowCreated(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles gvInvItem.RowCreated
' Purpose:
' - Add a row index flag for later use in procedure gvInvItem_RowCommand
' - Add a warning on the Delete button.
' Note: The GridViewCommandEventArgs class does not contain a
' property that indicates which row's command button was
' clicked. To identify which row's button was clicked, use
' the Move Up button's CommandArgument property by setting it to the
' row's index.
Try
If e.Row.RowType = DataControlRowType.DataRow Then
If e.Row.RowState = DataControlRowState.Alternate Or e.Row.RowState = DataControlRowState.Normal Then
' Retrieve the Move Up Button control from the first column.
Dim butMoveUp As Button = e.Row.FindControl("butMoveUp")
If Not butMoveUp Is Nothing Then
' Set the Button's CommandArgument property with the row's index.
butMoveUp.CommandArgument = e.Row.RowIndex.ToString()
' Set the Button's Behaviors
ProjectCommon.SetBehaviors(butMoveUp, "iiButtonOver", "iiButtonOut")
End If
' Retrieve the Move Down Button control from the first column.
Dim butMoveDown As Button = e.Row.FindControl("butMoveDown")
If Not butMoveDown Is Nothing Then
' Set the Button's CommandArgument property with the row's index.
butMoveDown.CommandArgument = e.Row.RowIndex.ToString()
' Set the Button's Behaviors
ProjectCommon.SetBehaviors(butMoveDown, "iiButtonOver", "iiButtonOut")
End If
' Retrieve the Edit Button control from the first column.
Dim butEdit As Button = e.Row.FindControl("butEdit")
If Not butEdit Is Nothing Then
' Set the Button's Behaviors
ProjectCommon.SetBehaviors(butEdit, "iiPanelButtonOver", "iiPanelButtonOut")
End If
' Adds a client-side onclick handler to Delete
Dim butDelete As Button = e.Row.FindControl("butDelete")
If Not butDelete Is Nothing Then
butDelete.Attributes("onclick") = "return confirm('Do you really want to delete this payment item?');"
' Set the Button's CommandArgument property with the row's index.
butDelete.CommandArgument = e.Row.RowIndex.ToString()
' Set the Button's Behaviors
ProjectCommon.SetBehaviors(butDelete, "iiButtonOver", "iiButtonOut")
End If
End If
End If
Catch ex As Exception
ProjectCommon.ReportErrors(Page, ex, "reported from gvInvItem_RowCommand")
End Try
End Sub
Protected Sub gvInvItem_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles gvInvItem.RowDataBound
Try
If e.Row.RowType = DataControlRowType.DataRow Then
If e.Row.RowState = DataControlRowState.Normal Or e.Row.RowState = DataControlRowState.Alternate Then
' If in Edit mode, set focus to first control on edit row
If e.Row.RowState = DataControlRowState.Edit Then
' Set focus to the txtNameEdit textbox control
' Create a reference to the TextBox
Dim txtNameEdit As TextBox
txtNameEdit = e.Row.FindControl("txtNameEdit")
txtNameEdit.Focus()
End If
' If top row, disable the Up button
If e.Row.RowIndex = 0 Then
' Create a reference to the Up button
Dim butMoveUp As Button
butMoveUp = e.Row.FindControl("butMoveUp")
butMoveUp.Enabled = False
intGvInvItemLastRow = 0
Else
intGvInvItemLastRow += 1
End If
End If
Else
' Disable the Down button on the bottom row (when we have more than one row)
' To work with objects on the bottom row, tests shows that after RowDataBound enumerates through all
' DataControlRowType.DataRow rows, it returns here one more time. We us the intGvInvItemLastRow
' to track the enumeration of datarows.
' Create a reference to the Down button
Dim butMoveDown As Button
If intGvInvItemLastRow > 0 Then
butMoveDown = gvInvItem.Rows(gvInvItem.Rows.Count - 1).FindControl("butMoveDown")
' Note the button will not be found if previous row is e.Row.RowState = DataControlRowState.Edit, So test..
If Not butMoveDown Is Nothing Then
butMoveDown.Enabled = False
End If
intGvInvItemLastRow = 0
End If
End If
Catch ex As Exception
ProjectCommon.ReportErrors(Page, ex, "reported from gvInvItem_RowDataBound")
End Try
End Sub
Protected Sub gvInvItem_RowEditing(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewEditEventArgs) Handles gvInvItem.RowEditing
' After user clicks the Edit button, we warn if session has expired.
Try
If Session("strPeoCnt") Is Nothing Then
ProjectCommon.PopUpMessage(Page, "SearchPrefRowEditSesExpWarning", "Your session has expired. Please sign-in again.")
Exit Sub
End If
Catch ex As Exception
ProjectCommon.ReportErrors(Page, ex, "reported from gvInvItem_RowEditing")
End Try
End Sub
Protected Sub gvInvItem_RowUpdated(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewUpdatedEventArgs) Handles gvInvItem.RowUpdated
' Purpose: Handle update errors
' Note: We decide to handle update errors here instead of SqlDataSourceItems_Updated
' Use the Exception property to determine whether an exception
' occurred during the update operation.
Try
If e.Exception Is Nothing Then
' Sometimes an error might occur that does not raise an
' exception, but prevents the update operation from
' completing. Use the AffectedRows property to determine
' whether the record was actually updated.
If e.AffectedRows = 1 Then
' Use the Keys property to get the value of the key field.
Dim keyFieldValue As String = e.Keys("prmInvItemCnt").ToString()
' Display a confirmation message.
lblMessage.Visible = True
lblMessage.ForeColor = System.Drawing.Color.Green
lblMessage.Text = "Payment Item ID # " & keyFieldValue & " updated successfully at " & Now()
Else
ProjectCommon.ReportErrors(Page, e.Exception)
' Display an error message.
lblMessage.Visible = True
lblMessage.ForeColor = System.Drawing.Color.Red
lblMessage.Text = "Error updating payment items. Item was not updated. Error details were sent to Technical Support. "
' When an error occurs, keep the GridView
' control in edit mode.
e.KeepInEditMode = True
End If
Else
' Handle the error
' Display the new and original values in the error message, extra message area.
Dim strExtraMsg As String = ""
strExtraMsg += DisplayValues(CType(e.NewValues, OrderedDictionary), CType(e.OldValues, OrderedDictionary))
strExtraMsg += vbCrLf
ProjectCommon.ReportErrors(Page, e.Exception, strExtraMsg)
lblMessage.Visible = True
lblMessage.ForeColor = System.Drawing.Color.Red
lblMessage.Text = "Error updating payment item. Error details were sent to Technical Support. "
' Use the ExceptionHandled property to indicate that the
' exception is already handled.
e.ExceptionHandled = True
e.KeepInEditMode = True
End If
Catch ex As Exception
ProjectCommon.ReportErrors(Page, ex, "reported from gvInvItem_RowDataBound")
End Try
End Sub
Function DisplayValues(ByVal newValues As OrderedDictionary, ByVal oldValues As OrderedDictionary) As String
' Purpose: Error reporting subroutine
DisplayValues = vbCrLf
' Iterate through the new and old values. Return the values.
Dim i As Integer
For i = 0 To oldValues.Count - 1
If oldValues(i) IsNot Nothing Then
DisplayValues += "Old Value=" & oldValues(i).ToString()
Else
DisplayValues += "Old Value is Nothing"
End If
DisplayValues += vbCrLf
If newValues(i) IsNot Nothing Then
DisplayValues += "New Value=" & newValues(i).ToString()
Else
DisplayValues += "New Value is Nothing"
End If
DisplayValues += vbCrLf
Next
DisplayValues &= vbCrLf
End Function
Protected Sub gvInvItem_RowUpdating(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewUpdateEventArgs) Handles gvInvItem.RowUpdating
' Purpose: this procedure is used to:
' - Alert user that their session expired, cancel update and exit (a security measure).
' - Clean user input, such as trim spaces from text entry controls.
' - Change format of data from the user-friendly display to a format expected by SQL Server
' Note this procedure fires after user clicks the Update button, but before the update request is sent to SQL Server.
Try
If Session("strPeoCnt") Is Nothing Then
ProjectCommon.PopUpMessage(Page, "gvInvItemRowUpdSesExpWarning", "Your session has expired. Please sign-in again.")
e.Cancel = True
Exit Sub
End If
' Get the value of the key field of the row being updated
Dim key As String = e.Keys(0).ToString
' Clean the value of the txtName TextBox control
If Not IsNothing(e.NewValues("strName")) Then
e.NewValues("strName") = Mid(e.NewValues("strName").Trim, 1, 13)
End If
' Clean the value of the txtFullName TextBox control
If Not IsNothing(e.NewValues("strFullName")) Then
e.NewValues("strFullName") = Mid(e.NewValues("strFullName").Trim, 1, 69)
End If
' Clean the value of the txtDescrEdit TextBox control
If Not IsNothing(e.NewValues("strDescr")) Then
e.NewValues("strDescr") = e.NewValues("strDescr").Trim
End If
If Not IsNumeric(e.NewValues("curUnitPrice")) Then
ProjectCommon.PopUpMessage(Page, "gvInvItemRowUpdatingBadCurUnitPrice", "Price contains a non-numeric character. Please correct.")
e.Cancel = True
Exit Sub
End If
If e.NewValues("curUnitPrice") IsNot Nothing Then
e.NewValues("curUnitPrice") = Decimal.Parse(e.NewValues("curUnitPrice").ToString(), _
System.Globalization.NumberStyles.Currency)
End If
Dim dateValue As Date
' We allow null dates. If user leaves date blank, no error will occur
If e.NewValues("dtmStart") IsNot Nothing Then
If Date.TryParse(e.NewValues("dtmStart").ToString(), dateValue) = True Then
e.NewValues("dtmStart") = DateTime.Parse(e.NewValues("dtmStart").ToString(), System.Globalization.CultureInfo.CreateSpecificCulture("en-US"))
Else
ProjectCommon.PopUpMessage(Page, "gvInvItemRowUpdatingBadCurUnitPrice", "Price Start contains an invalid date and time. Please correct.")
e.Cancel = True
Exit Sub
End If
End If
If e.NewValues("dtmEnd") IsNot Nothing Then
If Date.TryParse(e.NewValues("dtmEnd").ToString(), dateValue) = True Then
e.NewValues("dtmEnd") = DateTime.Parse(e.NewValues("dtmEnd").ToString(), System.Globalization.CultureInfo.CreateSpecificCulture("en-US"))
Else
ProjectCommon.PopUpMessage(Page, "gvInvItemRowUpdatingBadCurUnitPrice", "Price End contains an invalid date and time. Please correct.")
e.Cancel = True
Exit Sub
End If
End If
lblMessage.Visible = True
lblMessage.ForeColor = System.Drawing.Color.Green
lblMessage.Text = "Payment Items last updated at " & Now() & "."
Catch ex As Exception
lblMessage.Visible = True
lblMessage.ForeColor = System.Drawing.Color.Red
lblMessage.Text = "Error before updating payment items. Error details were sent to Technical Support. "
ProjectCommon.ReportErrors(Page, ex)
End Try
End Sub
Protected Sub butInsertItem_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles butInsertItem.Click
' Purpose: Insert a new Payment Item, with default values, at last row, and place in edit mode.
Try
' Setting these default values using the VS 2008, SQLDataSource control GUI does not seem to work, so we set them here.
SqlDataSourceItems.InsertParameters("strItemType").DefaultValue = "Event"
' Suggest and Item code based on event id and the row count.
' Note we add one to the current row count because we haven't insert a new row yet.
SqlDataSourceItems.InsertParameters("strName").DefaultValue = txtEveCnt.Text & "Fee" & gvInvItem.Rows.Count + 1
SqlDataSourceItems.InsertParameters("strFullName").DefaultValue = "Fee" ' does not allow nulls
SqlDataSourceItems.InsertParameters("curUnitPrice").DefaultValue = 0
SqlDataSourceItems.InsertParameters("intEve").DefaultValue = CType(txtEveCnt.Text, Integer)
' Note that because we use a zero-base sort order, we can set a newly inserted rows' intEveSortOrder to the row count
' when setting the initial sort order, and this adds it nicely as the bottom sorted row
SqlDataSourceItems.InsertParameters("intEveSortOrder").DefaultValue = gvInvItem.Rows.Count
' Inert the new row in the database
SqlDataSourceItems.Insert()
' Set to edit mode on this new row; the last row per intEveSortOrder
gvInvItem.EditIndex = gvInvItem.Rows.Count
' Bind (sets focus in gvInvItem_RowDataBound)
gvInvItem.DataBind()
Catch ex As SqlException
lblMessage.ForeColor = System.Drawing.Color.Red
lblMessage.Text = ex.Message
ProjectCommon.ReportErrors(Page, ex)
Finally
End Try
End Sub
Steve Brown
Partner
Ideas Inc.
http://ideasinc.net
dwoods11
Member
19 Points
16 Posts
Gridview - Move record up / down in listing
May 05, 2006 04:14 AM|LINK
My question is basically whether I should try this new gridview thing, or do it my old school way with a datalist. Basically I have a mini Content managment situation. I am using a gridview to display a listing of employees. In the database i have a column called sortid, which is used to order the records for display on the front side of the site.
Inside the gridview i have two buttons
<ItemTemplate>
<asp:ImageButton ID="Button1" CommandName="sortup" Runat="Server" ImageUrl="../images/sort_up.gif" />
<asp:ImageButton ID="Button2" Runat="Server" CommandName="sortdown" ImageUrl="../images/sort_down.gif" />
</ItemTemplate>
Now with the datalist i would access the clicked rows datakey and the previous rows datakey and swap them.
case "sortup"
MoveRecord(e.commandArgument.tostring(),employeeDL.DataKeys(e.Item.ItemIndex - 1).ToString())
case "sortdown"
MoveRecord(e.commandArgument.tostring(),employeeDL.DataKeys(e.Item.ItemIndex + 1).ToString())
The e.Item.ItemIndex does not seem to be a property of the Gridview's EventCommand (GridViewCommandEventArgs). Any suggestion is greatly appreciated. I really love the simplicity of the gridviews editing and deleting.
Thanks
David
sophia
Contributor
2920 Points
584 Posts
Re: Gridview - Move record up / down in listing
May 05, 2006 07:21 AM|LINK
Do you mean you need sorting?
Check out the sorting part in the tutorials. http://www.asp.net/QuickStart/aspnet/doc/ctrlref/data/gridview.aspx
dwoods11
Member
19 Points
16 Posts
Re: Gridview - Move record up / down in listing
May 07, 2006 02:07 AM|LINK
Nope not looking to sort, but rather move an individual item up or down one row in a listing. For example, if you have some print ad pricing in a grid, you may want them to appear in a certain order.
Full Page
Half Page
1/4 Page
1/8 page
Sorting will not always work, so i wanted to give the user complete control on which order the records are displayed. I add a sortid column to the db and that will control "importance". In the gridview you can choose to move half page above full page. With a gridview it works like this :
sub ChangeSort(ByVal sender As Object, ByVal e As GridViewCommandEventArgs)
Select Case e.Commandname
case "sortup"
try
MoveRecord(printAdGrid.DataKeys(e.commandArgument).value.ToString(),printAdGrid.DataKeys(e.commandArgument - 1).value.ToString())
catch ex as exception
end try
case "sortdown"
try
MoveRecord(printAdGrid.DataKeys(e.commandArgument).value.ToString(),printAdGrid.DataKeys(e.commandArgument+ 1).Value.ToString())
catch ex as exception
end try
end select
end sub
'''''''''''''''' then have a sub for updating the sql, im sure someone has a better way, but this is my hack
sub MoveRecord(thisid as string,movetoid as string)
Dim strConn as string
Dim conn as SQLConnection
Dim intResults as Integer
strConn = ""
conn = New SQLConnection(strConn)
conn.Open()
dim strSQL1 = new String("update printads set sortid = '99999' where sortid = '"+movetoid+"'")
dim strSQL2 = new String("update printads set sortid = '"+movetoid+"' where sortid = '"+thisid+"'")
dim strSQL3 = new String("update printads set sortid = '"+thisid+"' where sortid = '99999'")
dim command1 = new SQLCommand(strSQL1, conn)
dim command2 = new SQLCommand(strSQL2, conn)
dim command3 = new SQLCommand(strSQL3, conn)
try
intResults = command1.ExecuteNonQuery()
intResults = command2.ExecuteNonQuery()
intResults = command3.ExecuteNonQuery()
Sqlsource.SelectCommand="SELECT * FROM printads order by sortid asc"
catch ex as exception
response.Write(ex.message)
end try
conn.close()
end sub
Maybe someone else will be able to use this.
Cheers
David
AspForumTany...
Member
207 Points
113 Posts
Re: Gridview - Move record up / down in listing
Jan 15, 2008 01:52 PM|LINK
Hey there!
I know this is a very old post, I was just wondering if you ever found a solution and if you have a complete code source to share? [;)]
danyeung
Participant
754 Points
369 Posts
Re: Gridview - Move record up / down in listing
Jan 18, 2008 09:32 PM|LINK
I am having problem now and would like to see your code. Thanks.
DanYeung
kiwikoder
Member
21 Points
14 Posts
Re: Gridview - Move record up / down in listing
Feb 21, 2008 09:56 PM|LINK
Heya, I just went about it like this:
<asp:TemplateField ShowHeader="False"> <ItemTemplate> <asp:LinkButton ID="LinkButton3" runat="server" CausesValidation="False" Text="Move Up" CommandArgument='<%#Bind("ID") %>' CommandName="Up" OnCommand="Sort_Page"></asp:LinkButton> <asp:LinkButton ID="LinkButton4" runat="server" CausesValidation="False" Text="Move Down" CommandArgument='<%#Bind("ID") %>' CommandName="Down" OnCommand="Sort_Page"></asp:LinkButton> </ItemTemplate> </asp:TemplateField>Then all you need is a function to sort your data (I just used a SQL Query)AspForumTany...
Member
207 Points
113 Posts
Re: Gridview - Move record up / down in listing
Feb 21, 2008 10:08 PM|LINK
Yes - your solution is pretty simple. I had some coding done on the page where I needed this feature, because I had Insert, Edit and Delete options there as well. Also I implemented this through AJAX without posting back the whole page. The code becomes more chalanging when you need to make sure your order stays the same or moves one up when you delete a record. Also - I moved my Up / Down buttons out of the GridView.
kiwikoder
Member
21 Points
14 Posts
Re: Gridview - Move record up / down in listing
Feb 21, 2008 10:42 PM|LINK
What do you mean by moved them out of the gridview?
AspForumTany...
Member
207 Points
113 Posts
Re: Gridview - Move record up / down in listing
Feb 22, 2008 04:21 PM|LINK
Here is an exact example of what I've implemented http://www.obout.com/grid/grid_move_rc_up_down.aspx - buttons "Move Up" and "Move Down" are outside the gridview, although most of the examples on the web have those buttons in each row of the grid. Also I had decided to save the sequence to the database every time the row was moved because if somebody moves the row and than decides to delete it before saving the sequence - you 've got the wrong record deleted...ops...
I've taken their layout, look and performance and implemented exactly the same thing using AJAX. Here is the web blog where I got a good start from: http://www.webswapp.com/codesamples/aspnet20/datatable_rowsreorder_ondatagrid/sort_on_rank.aspx
Steve.Brown
Member
2 Points
4 Posts
Re: Gridview - Move record up / down in listing
Mar 19, 2009 02:13 PM|LINK
I see this thread is old but perhaps someone might still benefit from my code samples below. My GridView, named gvInvItem, allows the user to move rows up and down and retain a custom row order. Procedures below include how to deal with inserts and deletes. I find that using the GridView events to do a custom row sort is more efficient than writing separate procedures that are redundant to features already available in GridView.
Private intGvInvItemLastRow As Integer = 0 ' remember last row to use in RowdataBound tasks
Protected Sub gvInvItem_DataBound(ByVal sender As Object, ByVal e As System.EventArgs) Handles gvInvItem.DataBound ' This event fires after all RowDataBound events, so here we do some cleanup that is difficult to do in RowDatBound: Try ' If this datagrid only has one row, disable the Down button (Top button has already been disables in RowCommand event) If gvInvItem.Rows.Count = 1 Then ' Create a reference to the Down button Dim butMoveDown As Button butMoveDown = gvInvItem.Rows(0).FindControl("butMoveDown") ' This event appears to fire after a row has been deleted. When user has deleted the last row, here it still shows a gvInvItem.Rows.Count = 1. ' Don't know why it doesn't show gvInvItem.Rows.Count = 0 here. So, to avoid an error, we must check for existance of butMoveDown If butMoveDown IsNot Nothing Then butMoveDown.Enabled = False End If End If Catch ex As Exception ProjectCommon.ReportErrors(Page, ex, "reported from gvInvItem_RowDataBound") End Try End Sub Protected Sub gvInvItem_RowCommand(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewCommandEventArgs) Handles gvInvItem.RowCommand ' Purpose: process Up, Down and Delete buttons. ' Note: Logic below works in conjunction with procedure: ' butInsertItem_Click (only inserting at botton of sort and inserting proper sort order value) ' gvInvItem_DataBound (top row "Up" button disabling) ' gvInvItem_RowDataBound (bottom row, "Up" and "Down" button disabling). ' gvInvItem_RowCreated (sets button command arguments) Dim intRowIndex As Integer Try ' Process clicking the Move Up button or Move Down buttons that swap row order If e.CommandName.ToString = "MoveUp" Or e.CommandName.ToString = "MoveDown" Or e.CommandName.ToString = "Delete" Then ' User wants to move the current row up or down one in the sort order ' Convert the row index stored in the CommandArgument ' property to an Integer. intRowIndex = Convert.ToInt32(e.CommandArgument) ' Get the value of the key field of the row being updated Dim strKey As String = gvInvItem.DataKeys(intRowIndex).Value.ToString Dim lblEveSortOrderView As Label Dim txtEveSortOrderEdit As TextBox Dim intSafetyOut As Integer = 0 Dim intOriginalEveSortOrder As Integer = 0 ' Get the label control holding the yet unchanged sort order integer lblEveSortOrderView = gvInvItem.Rows(intRowIndex).FindControl("lblEveSortOrderView") ' Store this into an integer intOriginalEveSortOrder = Val(lblEveSortOrderView.Text) ' Loop through all rows, top to bottom. ' Note: If-Else logic must consider that any update within the loop resorts the rows per intEveSortOrder between each loop. For intIndex As Integer = 0 To gvInvItem.Rows.Count - 1 And intSafetyOut < 1000 ' Safety below, I managed while debugging this to once go into an unbreakable update loop. I had to kill the ' SQL Server process to recover. So, as a safety, this loop forcefully stops itself after 1000 loops. intSafetyOut += 1 ' Edit the row that we our now on as we are looping gvInvItem.EditIndex = intIndex ' Bind is required to get into edit mode. Note this resorts grid, but since we are going top to bottom, should be no problem. gvInvItem.DataBind() ' Get a reference to the textbox that holds the 0-based sort order integer txtEveSortOrderEdit = gvInvItem.Rows(intIndex).FindControl("txtEveSortOrderEdit") If e.CommandName.ToString = "MoveUp" Then If Val(txtEveSortOrderEdit.Text) < (Val(lblEveSortOrderView.Text) - 1) Then ' If the current rows's sort order is less than the original sort order -1, do nothing and loop. ElseIf Val(txtEveSortOrderEdit.Text) = (intOriginalEveSortOrder - 1) Then ' If the current rows's sort order is exactly 1 less than the original sort order -1, Add 1 txtEveSortOrderEdit.Text = Val(txtEveSortOrderEdit.Text) + 1 gvInvItem.UpdateRow(intIndex, False) ' Since sort order updates on every databind, substract one from inIndex to make sure we do not skip processing the original row intIndex = intIndex - 1 ElseIf gvInvItem.DataKeys(intIndex).Value.ToString = strKey Then ' If we are on the original row, Subtract 1 txtEveSortOrderEdit.Text = Val(txtEveSortOrderEdit.Text) - 1 gvInvItem.UpdateRow(intIndex, False) Else ' ' Do nothing and loop. End If ElseIf e.CommandName.ToString = "MoveDown" Then If Val(txtEveSortOrderEdit.Text) < intOriginalEveSortOrder Then ' If the current rows's sort order is less than the original sort order, do nothing and loop. ElseIf gvInvItem.DataKeys(intIndex).Value.ToString = strKey And Val(txtEveSortOrderEdit.Text) = intOriginalEveSortOrder Then ' If we are on the original row, Add 1 if we have not already done so txtEveSortOrderEdit.Text = Val(txtEveSortOrderEdit.Text) + 1 gvInvItem.UpdateRow(intIndex, False) ' Since sort order updates on every databind, substract one from inIndex to make sure we do not skip processing the original row intIndex = intIndex - 1 ElseIf (Val(txtEveSortOrderEdit.Text) = (intOriginalEveSortOrder + 1)) _ And (gvInvItem.DataKeys(intIndex).Value.ToString <> strKey) Then ' If the current rows's sort order is exactly 1 more than the original sort order, Subtract 1 txtEveSortOrderEdit.Text = Val(txtEveSortOrderEdit.Text) - 1 gvInvItem.UpdateRow(intIndex, False) Else ' Do nothing and loop. End If ElseIf e.CommandName.ToString = "Delete" Then ' Process clicking the Delete button, reorder the intEveSortOrder values. ' Note this event fires before the actual row is deleted. So reorder rows now. ' one row, make each sort value the first row a sort order of 0 If intIndex <= intOriginalEveSortOrder Then ' Sort order is before the deleted row If intOriginalEveSortOrder = 0 Then ' User deleted top row. Do nothng and loop. End If Else ' subtract 1 txtEveSortOrderEdit.Text = Val(txtEveSortOrderEdit.Text) - 1 gvInvItem.UpdateRow(intIndex, False) End If End If Next ' Cleanup: take any current row out of edit mode gvInvItem.EditIndex = -1 End If Catch ex As Exception ProjectCommon.ReportErrors(Page, ex, "reported from gvInvItem_RowCommand") End Try End Sub Protected Sub gvInvItem_RowCreated(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles gvInvItem.RowCreated ' Purpose: ' - Add a row index flag for later use in procedure gvInvItem_RowCommand ' - Add a warning on the Delete button. ' Note: The GridViewCommandEventArgs class does not contain a ' property that indicates which row's command button was ' clicked. To identify which row's button was clicked, use ' the Move Up button's CommandArgument property by setting it to the ' row's index. Try If e.Row.RowType = DataControlRowType.DataRow Then If e.Row.RowState = DataControlRowState.Alternate Or e.Row.RowState = DataControlRowState.Normal Then ' Retrieve the Move Up Button control from the first column. Dim butMoveUp As Button = e.Row.FindControl("butMoveUp") If Not butMoveUp Is Nothing Then ' Set the Button's CommandArgument property with the row's index. butMoveUp.CommandArgument = e.Row.RowIndex.ToString() ' Set the Button's Behaviors ProjectCommon.SetBehaviors(butMoveUp, "iiButtonOver", "iiButtonOut") End If ' Retrieve the Move Down Button control from the first column. Dim butMoveDown As Button = e.Row.FindControl("butMoveDown") If Not butMoveDown Is Nothing Then ' Set the Button's CommandArgument property with the row's index. butMoveDown.CommandArgument = e.Row.RowIndex.ToString() ' Set the Button's Behaviors ProjectCommon.SetBehaviors(butMoveDown, "iiButtonOver", "iiButtonOut") End If ' Retrieve the Edit Button control from the first column. Dim butEdit As Button = e.Row.FindControl("butEdit") If Not butEdit Is Nothing Then ' Set the Button's Behaviors ProjectCommon.SetBehaviors(butEdit, "iiPanelButtonOver", "iiPanelButtonOut") End If ' Adds a client-side onclick handler to Delete Dim butDelete As Button = e.Row.FindControl("butDelete") If Not butDelete Is Nothing Then butDelete.Attributes("onclick") = "return confirm('Do you really want to delete this payment item?');" ' Set the Button's CommandArgument property with the row's index. butDelete.CommandArgument = e.Row.RowIndex.ToString() ' Set the Button's Behaviors ProjectCommon.SetBehaviors(butDelete, "iiButtonOver", "iiButtonOut") End If End If End If Catch ex As Exception ProjectCommon.ReportErrors(Page, ex, "reported from gvInvItem_RowCommand") End Try End Sub Protected Sub gvInvItem_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles gvInvItem.RowDataBound Try If e.Row.RowType = DataControlRowType.DataRow Then If e.Row.RowState = DataControlRowState.Normal Or e.Row.RowState = DataControlRowState.Alternate Then ' If in Edit mode, set focus to first control on edit row If e.Row.RowState = DataControlRowState.Edit Then ' Set focus to the txtNameEdit textbox control ' Create a reference to the TextBox Dim txtNameEdit As TextBox txtNameEdit = e.Row.FindControl("txtNameEdit") txtNameEdit.Focus() End If ' If top row, disable the Up button If e.Row.RowIndex = 0 Then ' Create a reference to the Up button Dim butMoveUp As Button butMoveUp = e.Row.FindControl("butMoveUp") butMoveUp.Enabled = False intGvInvItemLastRow = 0 Else intGvInvItemLastRow += 1 End If End If Else ' Disable the Down button on the bottom row (when we have more than one row) ' To work with objects on the bottom row, tests shows that after RowDataBound enumerates through all ' DataControlRowType.DataRow rows, it returns here one more time. We us the intGvInvItemLastRow ' to track the enumeration of datarows. ' Create a reference to the Down button Dim butMoveDown As Button If intGvInvItemLastRow > 0 Then butMoveDown = gvInvItem.Rows(gvInvItem.Rows.Count - 1).FindControl("butMoveDown") ' Note the button will not be found if previous row is e.Row.RowState = DataControlRowState.Edit, So test.. If Not butMoveDown Is Nothing Then butMoveDown.Enabled = False End If intGvInvItemLastRow = 0 End If End If Catch ex As Exception ProjectCommon.ReportErrors(Page, ex, "reported from gvInvItem_RowDataBound") End Try End Sub Protected Sub gvInvItem_RowEditing(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewEditEventArgs) Handles gvInvItem.RowEditing ' After user clicks the Edit button, we warn if session has expired. Try If Session("strPeoCnt") Is Nothing Then ProjectCommon.PopUpMessage(Page, "SearchPrefRowEditSesExpWarning", "Your session has expired. Please sign-in again.") Exit Sub End If Catch ex As Exception ProjectCommon.ReportErrors(Page, ex, "reported from gvInvItem_RowEditing") End Try End Sub Protected Sub gvInvItem_RowUpdated(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewUpdatedEventArgs) Handles gvInvItem.RowUpdated ' Purpose: Handle update errors ' Note: We decide to handle update errors here instead of SqlDataSourceItems_Updated ' Use the Exception property to determine whether an exception ' occurred during the update operation. Try If e.Exception Is Nothing Then ' Sometimes an error might occur that does not raise an ' exception, but prevents the update operation from ' completing. Use the AffectedRows property to determine ' whether the record was actually updated. If e.AffectedRows = 1 Then ' Use the Keys property to get the value of the key field. Dim keyFieldValue As String = e.Keys("prmInvItemCnt").ToString() ' Display a confirmation message. lblMessage.Visible = True lblMessage.ForeColor = System.Drawing.Color.Green lblMessage.Text = "Payment Item ID # " & keyFieldValue & " updated successfully at " & Now() Else ProjectCommon.ReportErrors(Page, e.Exception) ' Display an error message. lblMessage.Visible = True lblMessage.ForeColor = System.Drawing.Color.Red lblMessage.Text = "Error updating payment items. Item was not updated. Error details were sent to Technical Support. " ' When an error occurs, keep the GridView ' control in edit mode. e.KeepInEditMode = True End If Else ' Handle the error ' Display the new and original values in the error message, extra message area. Dim strExtraMsg As String = "" strExtraMsg += DisplayValues(CType(e.NewValues, OrderedDictionary), CType(e.OldValues, OrderedDictionary)) strExtraMsg += vbCrLf ProjectCommon.ReportErrors(Page, e.Exception, strExtraMsg) lblMessage.Visible = True lblMessage.ForeColor = System.Drawing.Color.Red lblMessage.Text = "Error updating payment item. Error details were sent to Technical Support. " ' Use the ExceptionHandled property to indicate that the ' exception is already handled. e.ExceptionHandled = True e.KeepInEditMode = True End If Catch ex As Exception ProjectCommon.ReportErrors(Page, ex, "reported from gvInvItem_RowDataBound") End Try End Sub Function DisplayValues(ByVal newValues As OrderedDictionary, ByVal oldValues As OrderedDictionary) As String ' Purpose: Error reporting subroutine DisplayValues = vbCrLf ' Iterate through the new and old values. Return the values. Dim i As Integer For i = 0 To oldValues.Count - 1 If oldValues(i) IsNot Nothing Then DisplayValues += "Old Value=" & oldValues(i).ToString() Else DisplayValues += "Old Value is Nothing" End If DisplayValues += vbCrLf If newValues(i) IsNot Nothing Then DisplayValues += "New Value=" & newValues(i).ToString() Else DisplayValues += "New Value is Nothing" End If DisplayValues += vbCrLf Next DisplayValues &= vbCrLf End Function Protected Sub gvInvItem_RowUpdating(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewUpdateEventArgs) Handles gvInvItem.RowUpdating ' Purpose: this procedure is used to: ' - Alert user that their session expired, cancel update and exit (a security measure). ' - Clean user input, such as trim spaces from text entry controls. ' - Change format of data from the user-friendly display to a format expected by SQL Server ' Note this procedure fires after user clicks the Update button, but before the update request is sent to SQL Server. Try If Session("strPeoCnt") Is Nothing Then ProjectCommon.PopUpMessage(Page, "gvInvItemRowUpdSesExpWarning", "Your session has expired. Please sign-in again.") e.Cancel = True Exit Sub End If ' Get the value of the key field of the row being updated Dim key As String = e.Keys(0).ToString ' Clean the value of the txtName TextBox control If Not IsNothing(e.NewValues("strName")) Then e.NewValues("strName") = Mid(e.NewValues("strName").Trim, 1, 13) End If ' Clean the value of the txtFullName TextBox control If Not IsNothing(e.NewValues("strFullName")) Then e.NewValues("strFullName") = Mid(e.NewValues("strFullName").Trim, 1, 69) End If ' Clean the value of the txtDescrEdit TextBox control If Not IsNothing(e.NewValues("strDescr")) Then e.NewValues("strDescr") = e.NewValues("strDescr").Trim End If If Not IsNumeric(e.NewValues("curUnitPrice")) Then ProjectCommon.PopUpMessage(Page, "gvInvItemRowUpdatingBadCurUnitPrice", "Price contains a non-numeric character. Please correct.") e.Cancel = True Exit Sub End If If e.NewValues("curUnitPrice") IsNot Nothing Then e.NewValues("curUnitPrice") = Decimal.Parse(e.NewValues("curUnitPrice").ToString(), _ System.Globalization.NumberStyles.Currency) End If Dim dateValue As Date ' We allow null dates. If user leaves date blank, no error will occur If e.NewValues("dtmStart") IsNot Nothing Then If Date.TryParse(e.NewValues("dtmStart").ToString(), dateValue) = True Then e.NewValues("dtmStart") = DateTime.Parse(e.NewValues("dtmStart").ToString(), System.Globalization.CultureInfo.CreateSpecificCulture("en-US")) Else ProjectCommon.PopUpMessage(Page, "gvInvItemRowUpdatingBadCurUnitPrice", "Price Start contains an invalid date and time. Please correct.") e.Cancel = True Exit Sub End If End If If e.NewValues("dtmEnd") IsNot Nothing Then If Date.TryParse(e.NewValues("dtmEnd").ToString(), dateValue) = True Then e.NewValues("dtmEnd") = DateTime.Parse(e.NewValues("dtmEnd").ToString(), System.Globalization.CultureInfo.CreateSpecificCulture("en-US")) Else ProjectCommon.PopUpMessage(Page, "gvInvItemRowUpdatingBadCurUnitPrice", "Price End contains an invalid date and time. Please correct.") e.Cancel = True Exit Sub End If End If lblMessage.Visible = True lblMessage.ForeColor = System.Drawing.Color.Green lblMessage.Text = "Payment Items last updated at " & Now() & "." Catch ex As Exception lblMessage.Visible = True lblMessage.ForeColor = System.Drawing.Color.Red lblMessage.Text = "Error before updating payment items. Error details were sent to Technical Support. " ProjectCommon.ReportErrors(Page, ex) End Try End Sub Protected Sub butInsertItem_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles butInsertItem.Click ' Purpose: Insert a new Payment Item, with default values, at last row, and place in edit mode. Try ' Setting these default values using the VS 2008, SQLDataSource control GUI does not seem to work, so we set them here. SqlDataSourceItems.InsertParameters("strItemType").DefaultValue = "Event" ' Suggest and Item code based on event id and the row count. ' Note we add one to the current row count because we haven't insert a new row yet. SqlDataSourceItems.InsertParameters("strName").DefaultValue = txtEveCnt.Text & "Fee" & gvInvItem.Rows.Count + 1 SqlDataSourceItems.InsertParameters("strFullName").DefaultValue = "Fee" ' does not allow nulls SqlDataSourceItems.InsertParameters("curUnitPrice").DefaultValue = 0 SqlDataSourceItems.InsertParameters("intEve").DefaultValue = CType(txtEveCnt.Text, Integer) ' Note that because we use a zero-base sort order, we can set a newly inserted rows' intEveSortOrder to the row count ' when setting the initial sort order, and this adds it nicely as the bottom sorted row SqlDataSourceItems.InsertParameters("intEveSortOrder").DefaultValue = gvInvItem.Rows.Count ' Inert the new row in the database SqlDataSourceItems.Insert() ' Set to edit mode on this new row; the last row per intEveSortOrder gvInvItem.EditIndex = gvInvItem.Rows.Count ' Bind (sets focus in gvInvItem_RowDataBound) gvInvItem.DataBind() Catch ex As SqlException lblMessage.ForeColor = System.Drawing.Color.Red lblMessage.Text = ex.Message ProjectCommon.ReportErrors(Page, ex) Finally End Try End SubPartner
Ideas Inc.
http://ideasinc.net