I've got a gridview connected to an objectdatasource which is bound to some custom objects in my code (code is below). The problem I'm having is that the value passed into my update method is the old value, not the new value. Thoughts?
Imports System.Configuration
Imports System.Web.Configuration
Imports System.Security.Cryptography
Imports System.Collections.Generic
Partial Public Class ManageUsersControl
Inherits System.Web.UI.UserControl
Dim auth As AuthenticationSection
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Users.DataBind()
End Sub
End Class
Public Class Users
Private sName As String
Private sPassword As String
Public Sub New()
End Sub
Public Sub New(ByVal nm As String, ByVal pass As String)
Name = nm
Password = pass
End Sub
Public Property Name() As String
Get
Return sName
End Get
Set(ByVal value As String)
sName = value
End Set
End Property
Public Property Password() As String
Get
Return sPassword
End Get
Set(ByVal value As String)
sPassword = value
End Set
End Property
End Class
Public Class UserData
Dim auth As AuthenticationSection
Shared userTable As List(Of Users)
Public Sub New()
auth = CType(WebConfigurationManager.GetSection("system.web/authentication"), AuthenticationSection)
End Sub
Public Function CreateData() As List(Of Users)
Dim dt As New List(Of Users)
For Each user As FormsAuthenticationUser In auth.Forms.Credentials.Users
dt.Add(New Users(user.Name, user.Password))
Next
userTable = dt
Return userTable
End Function
Public Function SelectMethod() As List(Of Users)
If userTable Is Nothing Then
Return CreateData()
Else
Return userTable
End If
End Function
Public Function UpdateMethod(ByVal userInfo As Users) As Integer
Dim user As FormsAuthenticationUser = auth.Forms.Credentials.Users(userInfo.Name)
Dim pass As String
Dim sha As New SHA1CryptoServiceProvider()
Dim enc As New System.Text.ASCIIEncoding()
pass = enc.GetString(sha.ComputeHash(enc.GetBytes(userInfo.Password)))
userTable.Add(New Users(userInfo.Name, pass))
user.Password = pass
Return 1
End Function
End Class
and the markup:
<%# Control Language="vb" AutoEventWireup="false" CodeBehind="ManageUsers.ascx.vb" Inherits="mystuff.ManageUsersControl" %>
<asp:GridView ID="Users" runat="server" AutoGenerateColumns="False"
AutoGenerateEditButton="True" AutoGenerateDeleteButton="True"
DataSourceID="UsersData">
<Columns>
<asp:BoundField DataField="Name" HeaderText="User Name" />
<asp:TemplateField HeaderText="Password" >
<InsertItemTemplate>
<asp:TextBox runat="server" ID="InsertPassword" Text='<%# Bind("Password") %>' />
</InsertItemTemplate>
<EditItemTemplate>
<asp:TextBox runat="server" ID="EditPassword" Text='<%# Bind("Password") %>' />
</EditItemTemplate>
<ItemTemplate>
<asp:Label runat="server">*****</asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="UsersData"
DataObjectTypeName="mystuff.Users"
UpdateMethod="UpdateMethod"
SelectMethod="SelectMethod"
TypeName="mystuff.UserData"
runat="server"
OldValuesParameterFormatString="original_{0}"></asp:ObjectDataSource>
Just found the solution.
Partial Public Class ManageUsersControl
Inherits System.Web.UI.UserControl
Dim auth As AuthenticationSection
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then Users.DataBind()
End Sub
End Class
Also, discovered that you can't edit the users during execution of the application.
Related
Connection String (Conn) is set globally on page load.
(As below. I use this for all sqldatasources and it work perfectly.)
VB.NET (Page Load)
Imports Connections
Dim Conn As New System.Data.SqlClient.SqlConnection
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Conn.ConnectionString = ConfigurationManager.ConnectionStrings(StringConn).ConnectionString
sqlRepeater.ConnectionString = Conn.ConnectionString
End Sub
How to set a nested datasource from code behind?
I have a nested gridview inside a repeater and am trying to set the sqldatasource's connectionstring on itemdatabound instead of page load. (As below.)
VB.NET (Repeater Item Databound)
Protected Sub rpt_ItemDataBound(ByVal sender As Object, ByVal e As RepeaterItemEventArgs) Handles rpt.ItemDataBound
If e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem Then
Dim sqlGridview As SqlDataSource = DirectCast(e.Item.FindControl("sqlGridview"), SqlDataSource)
sqlGridview.ConnectionString = Conn.ConnectionString
End If
End Sub
ASPX
<asp:Repeater ID="rpt" runat="Server" DataSourceID="sqlRepeater">
<ItemTemplate>
<asp:GridView ID="gv" runat="Server" AutoGenerateColumns="False" DataSourceID="sqlGridview">
...
</GridView>
<asp:SqlDataSource ID="sqlGridview" runat="Server" SelectCommand="sp" SelectCommandType="StoredProcedure"/>
</ItemTemplate>
</asp:Repeater>
<asp:SqlDataSource ID="sqlRepeater" runat="Server" SelectCommand="sp" SelectCommandType="StoredProcedure"/>
This code outputs error:
The ConnectionString property has not been initialized.
TRIED TO CREATE FUNCTION TO PASS IN THE CONNECTION STRING
ASPX
Replaceed above sqlsource with this to call function
<asp:SqlDataSource ID="sqlGridview" runat="Server" SelectCommand="sp" SelectCommandType="StoredProcedure" ConnectionString='<%# GetConnectionString()%>'/>
VB.NET
Protected Function GetConnectionString() As String
Dim Conn As New System.Data.SqlClient.SqlConnection
Conn.ConnectionString = ConfigurationManager.ConnectionStrings(StringConn).ConnectionString
Return Conn.ConnectionString
End Function
This is just an idea, but the problem might be the fact that by the time ItemDataBound is called GridView's data binding is already done, or was attempted to be done. And during this attempt a connection string was not set indeed.
To correct that you might want to do two things. First - set connection string in markup, so that data source has it before data binding is done. Something like this:
<asp:SqlDataSource ID="sqlGridview" runat="Server"
ConnectionString='<%# GetConnectionString(); %>' ... />
Where GetConnectionString is a protected method in code behind that just returns the
connection string:
Protected Function GetConnectionString() As String
Return Conn.ConnectionString
End Function
Of course that means that there is no need to handle ItemDataBound anymore, unless you were doing something else there as well.
Second - reverse the order of controls inside the item template. This most likely is not necessary, but I am not entirely sure about an exact time when the GridView will be data bound, so this will help to ascertain that connection string is set:
<ItemTemplate>
<asp:SqlDataSource ID="sqlGridview" runat="Server"
<asp:GridView ID="gv" runat="Server" ...
</ItemTemplate>
In Your Class Library
Use this to cast initially the sqlConnection then execute the connection when using it.
Public Class MyLibrary
'-------------------SQL Database Variables----------------
Dim SerialMACDatabase As String = Nothing
Dim SerialMac As SqlConnection
Dim CMD As New SqlCommand
Dim sqlAdapter As SqlDataAdapter
Public Sub New(ByVal lserialMACDatabase As String)
SerialMACDatabase = lserialMACDatabase
End Sub
Private Sub connectToDB()
Try
SerialMac = New SqlConnection(SerialMACDatabase)
SerialMac.Open()
Catch ex As Exception
End Try
End Sub
Public Sub issueCommand(ByVal sQuery As String)
Try
connectToDB()
CMD = New SqlCommand(sQuery, TestResult)
CMD.ExecuteNonQuery()
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
End Class
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim Libraryy As New MyLibrary(strSQLCONNECTION)
Libraryy.IssueCommand("INSERT SOMETHING")
End Sub
I'm creating an web form more complicated than what I'm listing below.
Bottom line, I'm updating a GridView and I'd like to have the 2nd Gridview update itself based on the GridView change made on the first one!
Please, help! I've already tried including a GridView2.DataBind() line in the updateNumber() method, but I receive an instance reference error or something like that. I've been stuck on this for days!
I update the number in GridView1, it refreshes and updates with new number, but NOT GridView2, which should display the updated number on GridView1 (and yes, I do need GridView2 to call GetUpdateNumber() GridView2 still shows the old number... the ones prior to updating GridView1
Here is the code behind
Option Strict On
Imports Team.MyWebProject
Public Class Blah
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim myNumberClass As New myClass1
Dim mylist As New List(Of myClass1)
Try
If (Not IsPostBack) Then
If Session("Number") Is Nothing Then
myNumberClass.number = 2
mylist.Add(myNumberClass)
Session("Number") = mylist
Else
myNumberClass = Nothing
mylist = CType(Session("Number"), List(Of myClass1))
End If
Else
mylist = CType(Session("Number"), List(Of myClass1))
End If
Catch ex As Exception
MsgBox(ex.Message & "/Blah.aspx.vb Page_Load")
End Try
End Sub
Public Function getNumber() As List(Of myClass1)
Try
Dim mylist As List(Of myClass1) = CType(Session("Number"), List(Of myClass1))
Return mylist
Catch ex As Exception
MsgBox(ex.Message & "/Blah.aspx.vb GetNumber")
End Try
End Function
Public Function getUpdatedNumber() As List(Of myClass1)
Try
Dim mylist As List(Of myClass1) = CType(Session("Number"), List(Of myClass1))
Return mylist
Catch ex As Exception
MsgBox(ex.Message & "/Blah.aspx.vb GetUpdateNumber")
End Try
End Function
Public Sub updateNumber(ByVal number As Integer)
Try
Dim mylist As List(Of myClass1) = CType(Session(Number"), List(Of myClass1))
Dim LoopIndex As New Integer
LoopIndex = 0
For Each Match In mylist
mylist(LoopIndex).Number = number
LoopIndex += 1
Next
Session("Number") = mylist
Catch ex As Exception
MsgBox(ex.Message & "blah.aspx.vb updateNumber")
End Try
End Sub
Protected Sub GridView1_RowCommand(sender As Object, e As GridViewCommandEventArgs) Handles GridView1.RowCommand
End Sub
Protected Sub GridView1_RowEditing(sender As Object, e As GridViewEditEventArgs) Handles GridView1.RowEditing
End Sub
Protected Sub GridView1_RowUpdating(sender As Object, e As GridViewUpdateEventArgs) Handles GridView1.RowUpdating
Try
Catch ex As Exception
MsgBox(ex.Message & "Blah.aspx.vb GridView13_RowUpdating()")
End Try
End Sub
Protected Sub GridView2_DataBinding(sender As Object, e As EventArgs) Handles GridView2.DataBinding
Try
Dim mylist As List(Of myClass1) = CType(Session("Number"), List(Of myClass1))
getUpdatedNumber()
Catch ex As Exception
MsgBox(ex.Message & "Blah.aspx GridView2_Databinding()")
End Try
End Sub
End Class
Here is the myClass1.vb class:
Namespace MyWebProject
Public Class myClass1
Private _number As Integer
Public Sub New()
_number = 0
End Sub
Public Sub New(ByVal number As Integer)
_number = number
End Sub
Public Property Number() As Integer
Get
Return _number
End Get
Set(value As Integer)
_number = value
End Set
End Property
End Class
End Namespace
And here is the MarkUp page:
<%# Page Language="vb" AutoEventWireup="false" CodeBehind="Blah.aspx.vb" Inherits="GridViewUpdateTest.Blah" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
</div>
<br />
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataSourceID="ObjectDataSource1">
<Columns>
<asp:CommandField ShowEditButton="True" />
<asp:BoundField DataField="Number" HeaderText="Number" SortExpression="Number" />
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" SelectMethod="getNumber" TypeName="GridViewUpdateTest.Blah" UpdateMethod="updateNumber">
<UpdateParameters>
<asp:Parameter Name="number" Type="Int32" />
</UpdateParameters>
</asp:ObjectDataSource>
<asp:GridView ID="GridView2" runat="server" AutoGenerateColumns="False" DataSourceID="ObjectDataSource2">
<Columns>
<asp:BoundField DataField="Number" HeaderText="Number" SortExpression="Number" />
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ObjectDataSource2" runat="server" SelectMethod="getUpdatedNumber" TypeName="GridViewUpdateTest.Blah"></asp:ObjectDataSource>
</form>
</body>
</html>
I have a Windows form with 1 DataGrid which has a Dropdownlist in one of its columns.
I also have another dropDownlist outside of this DataGrid.
Both of these dropdowns are bound to same dataset and both get populated with same items.
Both of DropDowns have their Autopostbacks set to true.
Problem is only for the dropdownlist Outside of Datagrid SelectedIndexChange Event gets fired:
(I have seen multiple similar questions on SO but none of suggestions works for me. So I really appreciate if you can help me here.
)
Protected Sub ABCD(ByVal sender As System.Object, ByVal e As System.EventArgs)
End Sub
For both Dropdownlists: AutoPostBack="True"
Here is Vb code:
Imports System.Data.OleDb
Public Class WebForm1
Inherits System.Web.UI.Page
Protected WithEvents dg As New System.Web.UI.WebControls.DataGrid
Private cnDB As New OleDbConnection
Private ds As New DataSet
Private daDB As New OleDbDataAdapter
Protected allNames As New DataSet
Protected MyDataSet As DataSet
Protected WithEvents DropDownList1 As System.Web.UI.WebControls.DropDownList
Protected WithEvents DropDownList2 As System.Web.UI.WebControls.DropDownList
Protected WithEvents ddlName As New System.Web.UI.WebControls.DropDownList
#Region " Web Form Designer Generated Code "
'This call is required by the Web Form Designer.
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
End Sub
'NOTE: The following placeholder declaration is required by the Web Form Designer.
'Do not delete or move it.
Private designerPlaceholderDeclaration As System.Object
Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
'CODEGEN: This method call is required by the Web Form Designer
'Do not modify it using the code editor.
InitializeComponent()
End Sub
#End Region
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
MyDataSet = NameBudget()
GridDataLoad()
End Sub
Protected Sub Grid_EditCommand(ByVal source As Object, ByVal e As DataGridCommandEventArgs)
dg.EditItemIndex = e.Item.ItemIndex
dg.DataSource = ds
dg.DataBind()
End Sub
Protected Sub Grid_CancelCommand(ByVal source As Object, ByVal e As DataGridCommandEventArgs)
dg.DataSource = ds.Tables(0).DefaultView
dg.EditItemIndex = -1
dg.DataSource = ds
dg.DataBind()
End Sub
Protected Sub Grid_UpdateCommand(ByVal source As Object, ByVal e As DataGridCommandEventArgs)
End Sub
Private Function GridDataLoad()
ddlName.DataSource = MyDataSet
Dim i As Object = MyDataSet.Tables(0)
ddlName.DataBind()
DropDownList1.DataSource = MyDataSet
DropDownList1.DataBind()
Dim strCon As String = _
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\AccessTestDataBases\TestDB.mdb; "
Dim cnDB As New OleDbConnection(strCon)
cnDB.Open()
daDB = New OleDbDataAdapter("Select * from [Persons]", cnDB)
daDB.Fill(ds, "tbl1")
Dim j As Object = ds.Tables(0)
dg.DataSource = ds
dg.DataBind()
cnDB.Close()
Dim ii As Object = ds.Tables(0)
End Function
Protected Function NameEditable(ByVal n As String) As Boolean
Return True
End Function
Protected Function NameBudget() As DataSet
Dim strCon As String = _
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\AccessTestDataBases\TestDB.mdb; "
Dim cnDB As New OleDbConnection(strCon)
cnDB.Open()
daDB = New OleDbDataAdapter("Select ID,Name from [Persons]", cnDB)
Dim ds As New DataSet
daDB.Fill(ds, "tbl1")
cnDB.Close()
Return ds
End Function
Sub SetDefaultListItem(ByVal sender As Object, ByVal e As System.EventArgs)
'*************************************************************************
'* Use this sub to set the Default List for DropDown Listboxes *
'*************************************************************************
Try
If Len(sender.DefaultValue) > 0 Then
If sender.Items.FindByValue(sender.DefaultValue).ToString.Length > 0 Then
sender.Items.FindByValue(sender.DefaultValue).Selected = True
End If
End If
Catch ex As System.Exception
'Throw New System.Exception(ex.ToString())
End Try
End Sub
Protected Sub ABCD(ByVal sender As System.Object, ByVal e As System.EventArgs)
End Sub
End Class
Here is the HTML for datagrid and Dropdownlists:
<Columns>
<ASP:ButtonColumn Text="Delete" CommandName="Delete"></ASP:ButtonColumn>
<asp:EditCommandColumn ButtonType="LinkButton" UpdateText="Update" CancelText="Cancel"
EditText="Edit"></asp:EditCommandColumn>
<ASP:TemplateColumn HeaderText="Name" SortExpression="FY" HeaderStyle-HorizontalAlign="center" HeaderStyle-Wrap="True">
<ItemStyle Wrap="false" HorizontalAlign="left" />
<ItemTemplate>
<ASP:Label ID="Name" Text='<%# DataBinder.Eval(Container.DataItem, "Name") %>' runat="server"/>
</ItemTemplate>
<EditItemTemplate>
<ASP:DropDownList id="DropDownlist2" datasource="<%# MyDataSet %>" DataTextField= "Name" DataValueField="ID" runat="server" AutoPostBack="True" OnSelectedIndexChanged="ABCD">
</ASP:DropDownList>
</EditItemTemplate>
</ASP:TemplateColumn>
</Columns>
<asp:DropDownList id="DropDownList1"
datasource="<%# MyDataSet %>" DataTextField= "Name"
DataValueField="ID" runat="server" AutoPostBack="True"
OnSelectedIndexChanged="ABCD">
</asp:DropDownList>
I am attempting to sort a gridview in an updatepanel. It compiles, but I get an Object reverence not set to an instance of an object error. I am trying to follow this guide, but in vb
default.aspx
<ajx:UpdatePanel ID="ajaxpanel" runat="server">
<ContentTemplate>
<asp:GridView ID="gvProgramDetails" runat="server" AutoGenerateColumns="False"
CssClass="gridview" DataKeyNames="ProgramNumber"
AllowPaging="True" PageSize="2" AllowSorting="True" OnSorting="gvProgramDetails_Sorting">
<Columns>
<asp:CommandField ControlStyle-CssClass="button delete" ShowDeleteButton="True">
<ControlStyle CssClass="button delete" />
</asp:CommandField>
<asp:CommandField ControlStyle-CssClass="button save" ShowEditButton="True">
<ControlStyle CssClass="button save" />
</asp:CommandField>
<asp:BoundField DataField="ProgramNumber" HeaderText="ProgramNumber"
InsertVisible="False" ReadOnly="True" SortExpression="ProgramNumber" />
<asp:BoundField DataField="ProgramName" HeaderText="ProgramName"
SortExpression="ProgramName" />
<asp:BoundField DataField="ProgramStatus" HeaderText="ProgramStatus"
SortExpression="ProgramStatus" />
<asp:BoundField DataField="RecordType" HeaderText="RecordType"
SortExpression="RecordType" />
<asp:BoundField DataField="ProgramInformation" HeaderText="ProgramInformation"
SortExpression="ProgramInformation" />
</Columns>
</asp:GridView>
</ContentTemplate>
default.aspx.vb
Imports System.Web.Services
Partial Class processes_ProgramTrack_Default
Public Property SortOrder() As String
Get
If (ViewState("SortOrder").ToString = "desc") Then
ViewState("SortOrder") = "asc;"
Else
ViewState("SortOrder") = "desc"
End If
Return ViewState("SortOrder").ToString()
End Get
Set(ByVal value As String)
ViewState("SortOrder") = value
End Set
End Property
Public Sub bindGridView(Optional ByVal sortExp As String = "", Optional ByVal sortDir As String = "")
Dim connstr As String = ConfigurationManager.ConnectionStrings("WEBConnectionString").ConnectionString
Dim conn As New SqlConnection(connstr)
If conn.State = ConnectionState.Closed Then
conn.Open()
End If
Dim myDataView As New DataView()
Dim mysqlCommand As New SqlCommand("SELECT tblPrgTrackPrograms.ProgramNumber, tblPrgTrackPrograms.ProgramName, tblPrgTrackPrograms.ProgramStatus, tblPrgTrackProgramDocumentation.RecordType, tblPrgTrackProgramDocumentation.ProgramInformation FROM tblPrgTrackPrograms INNER JOIN tblPrgTrackProgramDocumentation ON tblPrgTrackPrograms.ProgramNumber = tblPrgTrackProgramDocumentation.ProgramNumber")
Dim myDataSet As New DataSet()
Dim mySQLAdapter As New SqlDataAdapter(mysqlCommand)
mySQLAdapter.SelectCommand.Connection = conn
mySQLAdapter.Fill(myDataSet)
myDataView = myDataSet.Tables(0).DefaultView
If sortExp <> String.Empty Then
myDataView.Sort = String.Format("{0}{1}", sortExp, sortDir)
End If
gvProgramDetails.DataSource = myDataView
gvProgramDetails.DataBind()
End Sub
Protected Sub gvProgramDetails_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles gvProgramDetails.Load
bindGridView()
End Sub
Protected Sub gvProgramDetails_PageIndexChanging(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewPageEventArgs) Handles gvProgramDetails.PageIndexChanging
gvProgramDetails.PageIndex = e.NewPageIndex
bindGridView()
End Sub
Protected Sub gvProgramDetails_RowDeleting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewDeleteEventArgs) Handles gvProgramDetails.RowDeleting
End Sub
Protected Sub gvProgramDetails_Sorting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewSortEventArgs) Handles gvProgramDetails.Sorting
SortOrder = ViewState("SortOrder").ToString
bindGridView(e.SortExpression, SortOrder)
End Sub
End Class
I get the error message as a popup msgbox. What I think is happening, SortOrder isn't getting assigned a value.
You need to make sure that you ViewState("SortOrder") has a value in it before you try to call ToString. Otherwise, it will throw that exception (as you've seen) because you cannot call the ToString method on null.
Essentially, you need to wrap your references to that ViewState variable in a "If (ViewState("SortOrder") IsNot Nothing Then" block, and possibly provide special handling in the "Else" section (if you need that).
Something like this for your property:
Public Property SortOrder() As String
Get
If (ViewState("SortOrder") IsNot Nothing Then
If (ViewState("SortOrder").ToString = "desc") Then
ViewState("SortOrder") = "asc;"
Else
ViewState("SortOrder") = "desc"
End If
End If
Return ViewState("SortOrder").ToString()
End Get
Set(ByVal value As String)
ViewState("SortOrder") = value
End Set
End Property
And then the same thing for your sorting event:
Protected Sub gvProgramDetails_Sorting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewSortEventArgs) Handles gvProgramDetails.Sorting
If (ViewState("SortOrder") IsNot Nothing Then
SortOrder = ViewState("SortOrder").ToString
bindGridView(e.SortExpression, SortOrder)
End If
End Sub
Note: This is my best guess at your problem, given the information you've provided so far. If you provide the line that's throwing the error, I'd be glad to take another look.
I am using nested repeater and child repeater has a user control in it.
<asp:repeater>
<asp:repeater>
<uc:userControl />
</asp:repeater>
</asp:repeater>
UserControl saves the information in database and raise the itemsaved event passing success message as event args.
I do have public event in usercontrol that will be raised but there is no way I can bind that event in the main page. (it would be really good if I can do that).
But I found another way to handle it in parent repeater's itemcommand. First it will fire usercontrol's button event and then repeater's itemcommand. I can recognize that usercontrol's event in itemcommand but how do I pass whether the information saved successfully or not? Is there any way I can pass true/false(successful save or not) from usercontrol's button event to itemcommand event?
You can handle your UserControl's event in the page. You have to add the handler in ItemCreated-event of your inner repeater.
Here is a working example(VB.Net):
Main-Page codebehind:
Public Class RepeaterTest
Inherits System.Web.UI.Page
Sub Page_Load(ByVal Sender As Object, ByVal e As EventArgs) Handles Me.Load
If Not IsPostBack Then
Dim comps As New List(Of Company)
comps.Add(New Company("Microsoft"))
comps.Add(New Company("Intel"))
comps.Add(New Company("Dell"))
Repeater1.DataSource = comps
Repeater1.DataBind()
End If
End Sub
Protected Sub Repeater1_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs)
Select Case e.Item.ItemType
Case ListItemType.Item, ListItemType.AlternatingItem
Dim company As Company = DirectCast(e.Item.DataItem, Company)
Dim repeater2 As Repeater = DirectCast(e.Item.FindControl("Repeater2"), Repeater)
Dim deps As New List(Of Department)
deps.Add(New Department("purchasing", company))
deps.Add(New Department("management", company))
deps.Add(New Department("marketing", company))
deps.Add(New Department("logistics ", company))
repeater2.DataSource = deps
repeater2.DataBind()
End Select
End Sub
Protected Sub Repeater2_ItemCreated(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs)
Select e.Item.ItemType
Case ListItemType.Item, ListItemType.AlternatingItem
Dim uc_department As UC_Department = DirectCast(e.Item.FindControl("UC_Department1"), UC_Department)
'*** Here is all the "magic" ***'
AddHandler uc_department.NameChanged, AddressOf DepartmentSaved
End Select
End Sub
Protected Sub Repeater2_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs)
Select Case e.Item.ItemType
Case ListItemType.Item, ListItemType.AlternatingItem
Dim department As Department = DirectCast(e.Item.DataItem, Department)
Dim uc_department As UC_Department = DirectCast(e.Item.FindControl("UC_Department1"), UC_Department)
uc_department.Department = department
End Select
End Sub
Private Sub DepartmentSaved(ByVal uc_Department As UC_Department)
' do something f.e. save to database '
End Sub
End Class
<Serializable()>
Public Class Company
Public Sub New(ByVal name As String)
Me.Name = name
End Sub
Public Property Name As String
Public Overrides Function ToString() As String
Return Me.Name
End Function
End Class
<Serializable()>
Public Class Department
Public Sub New(ByVal name As String, ByVal company As Company)
Me.Name = name
Me.Company = company
End Sub
Public Property Name As String
Public Property Company As Company
Public Overrides Function ToString() As String
Return Me.Name
End Function
End Class
aspx:
<asp:Repeater id="Repeater1" OnItemDataBound="Repeater1_ItemDataBound" runat="server">
<HeaderTemplate>
<table border="1">
<tr>
<td><b>Company</b></td>
<td><b>Departments</b></td>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<%# DataBinder.Eval(Container.DataItem, "Name")%>
</td>
<td>
<asp:Repeater ID="Repeater2" OnItemCreated="Repeater2_ItemCreated" OnItemDataBound="Repeater2_ItemDataBound" runat="server">
<HeaderTemplate>
<table border="1">
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<uc1:UC_Department ID="UC_Department1" runat="server" />
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
The usercontrol's codebehind:
Public Class UC_Department
Inherits System.Web.UI.UserControl
Public Event NameChanged(ByVal ucDepartment As UC_Department)
Public Property Department As Department
Get
If ViewState("Company") Is Nothing Then Return Nothing
Return New Department(Me.TxtName.Text, DirectCast(ViewState("Company"), Company))
End Get
Set(ByVal value As Department)
Me.TxtName.Text = value.Name
ViewState("Company") = value.Company
End Set
End Property
Private Sub BtnSave_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles BtnSave.Click
RaiseEvent NameChanged(Me)
End Sub
End Class
and its ascx:
<%# Control Language="vb" AutoEventWireup="false" CodeBehind="UC_Department.ascx.vb" Inherits="DemoProject.UC_Department" %>
<asp:TextBox ID="TxtName" runat="server"></asp:TextBox>
<asp:Button ID="BtnSave" runat="server" Text="Save" />