Pass Link-Button Click from One User Control to Another - asp.net

I have two user controls on the same page. One contains a ListView that displays navigation links, the second user control should be updated when user clicks on the buttonlink in the ListView. How can I do this?

UserControl A should handle the button-click and raise a custom event declared in the UserControl
The page handles this event and calls a public method of UserControl B that updates it's content
You could pass necessary informations from UserControl A to page via EventArgs(or pass the UserControl itself as argument and use it's public properties).
The page then passes the arguments to UserControl B via method parameter or by changing it's public properties before calling the Update-Method.
http://msdn.microsoft.com/en-us/library/fb3w5b53.aspx
http://chiragrdarji.blogspot.com/2007/08/raise-event-from-user-control-to-main.html
Here is the sample code you've requested.
Sorry for the meaningless naming but you haven't told what's this all about. You should use readable variables,properties,method and event-names instead.
Reduced UserControl A with a ListView:
<%# Control Language="vb" AutoEventWireup="false" CodeBehind="UsercontrolA.ascx.vb" Inherits="WebApplication1.UserControlA" %>
<asp:ListView ID="ListView1" runat="server">
<ItemTemplate>
<asp:LinkButton ID="LinkButton1"
CommandName="LinkClick"
CommandArgument='<%#Eval("ID") %>'
runat="server"
Text='<%#Eval("Text") %>'></asp:LinkButton>
</ItemTemplate>
</asp:ListView>
Removed the ListView databinding from codebehind because that doesn't matter. The important part is handling the ListView's ItemCommand and raising the custom event:
Public Event LinkClicked(sender As UserControlA, id As Int32)
Private Sub LV_ItemCommand(sender As Object, e As ListViewCommandEventArgs) Handles ListView1.ItemCommand
If e.CommandName = "LinkClick" Then
Dim id = CType(e.CommandArgument, Int32)
' This is the best way for UC's to commmunicate with the page: '
RaiseEvent LinkClicked(Me, id)
End If
End Sub
Simple UserControl B with nothing more than a Label(ascx):
<%# Control Language="vb" AutoEventWireup="false" CodeBehind="UserControlB.ascx.vb" Inherits="WebApplication1.UserControlB" %>
<asp:Label ID="Label1" runat="server"></asp:Label>
With an Update-Method in codebehind:
Public Sub Update(showID As Int32)
Me.Label1.Text = String.Format("Link {0} clicked", showID.ToString)
End Sub
Finally, here is the Page(aspx)
<uc1:UsercontrolA ID="UC_A" runat="server" />
<br />
<uc2:UserControlB ID="UC_B" runat="server" />
It controls both UserControls. It handles the event from UserControl A and calls the Update-Method that UserControl B provides:
Private Sub LinkClicked(sender As UserControlA, id As Integer) Handles UC_A.LinkClicked
Me.UC_B.Update(id)
End Sub
The advantage of this event-approach is that UserControls stay being reusable. You can use UserControl A in other pages as well even when they don't handle this event. It's part of the controller to decide what is needed and what should be done.
UserControls as a rule should not depend on specific controllers, otherwise they are hard-linked and not reusable. That would be also a good source for nasty erros. A UserControl might be a controller for other nested (User-)Controls but not for the page itself.
Communication Summary:
Page -> UserControl -> public properties and methods
UserControl -> Page -> Events
UserControl -> UserControl -> the controller-UserControl adopts the page-role(see above)

Related

How to access value in one Ascx control in another Ascx control on the same page

I have a aspx page that has two user controls one with a grid view in it and another with a label in it which is used for displaying user data when he logs in. Now I want use the data from one column in the grid view to be displayed in the label in second user control. How can I achieve this. The data in the gridview changes for each user based up on his security role.any inputs appreciated. Thank you
Gridview user control raises a custom event when it has the information you need. The event is handled in the main page and assigned to the UserControl with a label via a public property that has access to the Label Text embedded within the control.
Default.aspx
Page with both user controls
<%# Page Title="Home Page" Language="VB" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Default.aspx.vb" Inherits="StackOverFlowJunkVB._Default" %>
<%# Register Src="~/WebUserControlGridView1.ascx" TagPrefix="uc1" TagName="WebUserControlGridView1" %>
<%# Register Src="~/WebUserControlLabel1.ascx" TagPrefix="uc1" TagName="WebUserControlLabel1" %>
<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server">
<uc1:WebUserControlGridView1 runat="server" id="WebUserControlGridView1" />
<uc1:WebUserControlLabel1 runat="server" id="WebUserControlLabel1" />
</asp:Content>
Default.aspx.vb
Code behind that assigns text to Label user control via raised event from GridView user control
Public Class _Default
Inherits Page
Private Sub WebUserControlGridView1_ReallyImportantLabelTextHandler(sender As Object, e As GridViewLabelEvent) _
Handles WebUserControlGridView1.ReallyImportantLabelTextHandler
WebUserControlLabel1.ReallyImportLabelText = e.ImportantLabelText
End Sub
End Class
CodeBehind for the GridView UserControl
' Define a custom EventArgs class to pass some really important text
Public Class GridViewLabelEvent
Inherits EventArgs
Public Property ImportantLabelText As String
End Class
' The user control with a GridView
Public Class WebUserControlGridView1
Inherits System.Web.UI.UserControl
Public Event ReallyImportantLabelTextHandler As EventHandler(Of GridViewLabelEvent)
Private Sub GridView1_DataBound(sender As Object, e As EventArgs) Handles GridView1.DataBound
Dim gvle As New GridViewLabelEvent
gvle.ImportantLabelText = "This is really important"
RaiseEvent ReallyImportantLabelTextHandler(Me, gvle)
End Sub
End Class
CodeBehind for the Label UserControl
Public Class WebUserControlLabel1
Inherits System.Web.UI.UserControl
' Property to assign Label Text
Public Property ReallyImportLabelText As String
Get
Return Label1.Text
End Get
Set(value As String)
Label1.Text = value
End Set
End Property
End Class

How to determine which button caused postback

I have 2 button controls. When I click one i'm trying to determine which one caused a postback in the page load. How to do determine this?
What about using CommandName and CommandArgument has shown in this example. This way you can have just one handler.
<asp:Button id="Button1"
Text="Sort Ascending"
CommandName="Sort"
CommandArgument="Ascending"
OnCommand="CommandBtn_Click"
runat="server"/>
<asp:Button id="Button2"
Text="Sort Descending"
CommandName="Sort"
CommandArgument="Descending"
OnCommand="CommandBtn_Click"
runat="server"/>
Do you come from a Classic ASP background? When I first used ASP.NET, the same question occurred to me.
Consider an alternative approach:
Rather than detect the postback in the Form_Load, and then figure out what triggered it, create a specific event handler for each of your buttons. This is the whole point of Web Forms - so you can develop apps in very similar ways as you would Windows applications.
Really input with type button sends its value within post request. For example if you have you'll get in Post button-name=Quote like it's simple text input. So you can just check if post contains value for the button using code like following (sorry for my vb):
Dim isQuote As Boolean = HttpContext.Current.Request.Form(SubmitQuote.UniqueID) IsNot Nothing
so if it's not Nothing (null) then post has been sent by SubmitQuote button.
BTW for me HttpContext.Current.Request("__EVENTTARGET") didn't work either.
In my implementation there are several forms on my page; if a post-back was triggered by certain button controls further operations are necessary.
The controls are of the following type, which do not populate Request["__EVENTTARGET"]
Button (at the root of the form)
Image Button (nested within a Datagrid)
I determine if the following button controls instigated the post-back, by reviewing that the UniqueID of the control was passed to the form request within the Page_Load sub:
- ASP.NET:
<asp:Button ID="Button1" runat="server" />
<asp:Button ID="Button2" runat="server" />
To simply handle whether the following nested image button instigated the post-back I take advantage of the OnClientClick attribute which calls to a javascript function that will populate the value of a supplementary hidden field control with the UniqueID of the instigating control, then review the hidden control value similarly in the Page_Lode sub:
- ASP.NET:
<script type="text/javascript">
function SetSource(SourceID) {
var hiddenField = document.getElementById("<%=HiddenField1.ClientID%>");
hiddenField.value = SourceID;
}
</script>
<asp:HiddenField ID="HiddenField1" runat="server" Value="" />
<asp:ImageButton ID="ImageButton1" runat="server" OnClientClick="SetSource(this.id)" />
The Page_Load would then implement by some means:
-VB.NET
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Me.Load
' ...
If Not Page.IsPostBack Then
If Not String.IsNullOrEmpty(Me.Page.Request.Form(Button1.UniqueID)) Then
' ...
ElseIf Not String.IsNullOrEmpty(Me.Page.Request.Form(Button2.UniqueID)) Then
' ...
ElseIf Not Me.Page.Request.Form(HiddenField1.UniqueID) Is Nothing _
And Not String.IsNullOrEmpty(Me.Page.Request.Form(HiddenField1.UniqueID)) Then
' ...
HiddenField1.Value = String.Empty
Else
' ...
End If
End If
End Sub
on page load check this
String ButtonID = Request["__EVENTTARGET"];

Repeater won't let me access controls like buttons, dropdown, etc

I'm using a repeater ListOfArticles and have controls inside it like ddlSizes and btnSelectArticle. Normally you can just double click the control and in the aspx.vb page you can specify an action. I have heard something about Findcontrol, but can't figure out or find much information that I understand. I don't want to sound like an ass, but I would really prefer help for the aspx.vb page and not in C# or Javascript.
An example of what I'm trying to do is, once you've clicked btnSelectArticle the label lblSelection receives the following values Amount: txtAmount - Size: ddlSizes.SelectedValue.
<asp:Repeater ID="rptListOfArticles" runat="server" DataSourceID="objdsArticleList">
<asp:DropDownList ID="ddlSizes" runat="server" AutoPostBack="True" DataSourceID="objdsSizes" DataTextField="SizeName" DataValueField="SizeID" OnSelectedIndexChanged="ddlSizes_SelectedIndexChanged" />
<asp:Button ID="btnSelect" runat="server" Text="Select" OnClick="btnSelect_OnClick" />
<asp:Label ID="lblSelection" runat="server" Text=""></asp:Label>
In the aspx.vb page I can only select this and my controls like ddlSizes and btnSelect aren't recognized.
Protected Sub rptListOfArticles_ItemCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.RepeaterCommandEventArgs) Handles rptListOfArticles.ItemCommand
End Sub
Any help towards a solution would be great!
What you need to do is use the FindControl method to find the specific control in the selected repeater Item.
so an example would be (within the ItemCommand method)
Dim lblSelection as Label = CType(e.Item.FindControl("lblSelection"), Label)
lblSelection.Text = "Your Text"
Edit **
To Answer your questions in the comments:
Yes to access the SelectedValue of the ddlSize DropDown you will need to create this:
Dim ddlSize As DropDownList = Ctype(e.Item.FindControl("ddlSize"), DropDownList)
The Repeater will know when to call this method when any Buttons are Clicked within the Repeater. Add a CommandName to your buttons so that you can then control what happens in the ItemCommand method.
e.g.
<asp:Button id="btnDoSomething" runat="server" text="Run ItemCommand" CommandName="Command1" />
In the ItemCommand use the code:
If e.CommandName = "Command1" Then
' run your code
End If
You can handle the event of dropdownlist in ItemCommand Event. Event bubbling concept comes here actually the child control bubble the evenet up to its parent i.e repeater control so you can handle it in parent control event eventually
for more details HERE you will have indepth insight of all events of repeater

How do you expose a Panel as a property in a User Control?

I have a user control with a panel on it:
CustomControl.ascx
<%# Control Language="vb" CodeBehind="CustomControl.ascx.vb" %>
<asp:Panel ID="myPanel" runat="server"></asp:Panel>
I'd lke to expose that panel as a property that I can use at design time.
CustomControl.ascx.vb
<ParseChildren(True), PersistChildren(False)> _
Partial Public Class CustomControl
Inherits System.Web.UI.UserControl
#Region "Members and Properties"
<PersistenceMode(PersistenceMode.InnerProperty)> _
Public Property SomePanel() As Panel
Get
Return myPanel
End Get
Set(ByVal value As Panel)
myPanel= value
End Set
End Property
#End Region
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Response.Write(myPanel.HasControls.ToString())
End Sub
End Class
And then bring the control onto a page like so:
<ucl:CustomControl runat="server">
<SomePanel>
<asp:Label ID="lblText" AssociatedControlID="txtBox" runat="server"></asp:Label>
<asp:TextBox id="txtBox" runat="server"></asp:TextBox>
</SomePanel>
</ucl:CustomControl>
When I run the page, HasControls is true but nothing is rendered. What am I doing wrong?
You could achieve a similar effect by designing your user control as a template control. It's not that hard to set up, if you choose to go the template route.
Check out this brief tutorial to determine if control templates are suitable for you:
http://msdn.microsoft.com/en-us/library/36574bf6.aspx

Problem finding web control inside of Gridview TemplateField

Okay, so I'm having issues getting the value of a DropDownList that's inside of a TemplateField when updating my GridView. Originally I was using the RowCommand event to check the command name and then performing the appropriate task (update/delete), but I had problems with the event firing twice, so I switched it out for separate events (RowUpdating, RowDeleting). After doing this, FindControl is returning null every time. Just FYI, the gridview is inside of an UpdatePanel that has an AsyncPostBackTriggers for RowEditing, RowUpdating and RowDeleting events.
Here's my TemplateField inside of the GridView:
<asp:TemplateField HeaderText="Type">
<ItemTemplate>
<asp:Label
ID="lblMedTypeEdit"
Text='<%# Bind("medDesc") %>'
runat="server">
</asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:DropDownList
ID="ddlMedTypeEdit"
DataSourceID="srcMedTypes"
SelectedValue='<%# Bind("medtype") %>'
runat="server"
DataTextField="medDesc"
DataValueField="medCode">
</asp:DropDownList>
</EditItemTemplate>
</asp:TemplateField>
Here is the code I'm using inside of
Protected Sub gvCurrentMeds_RowUpdating(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewUpdateEventArgs) Handles gvCurrentMeds.RowUpdating
Dim intRowIndex As Integer = e.RowIndex
Dim ddlMedType As DropDownList = CType(Me.gvCurrentMeds.Rows(intRowIndex).Cells(1).FindControl("ddlMedTypeEdit"),DropDownList)
End Sub
I also tried using a recursive function to find the control (below), but it is still returning back null.
Public Function FindControlRecursive(ByVal root As Control, ByVal id As String) As Control
If root.ID = id Then
Return root
End If
For Each c As Control In root.Controls
Dim t As Control = FindControlRecursive(c, id)
If Not t Is Nothing Then
Return t
End If
Next
Return Nothing
End Function
If you just want to know what the new value of the dropdown is, this is already provided for you in the NewValues property of the GridViewUpdateEventArgs object passed to the event handler.
In your example, e.NewValues["medtype"] should be the updated value.
You've already specified <%# Bind(...) %> on the dropdown, so ASP.NET will do the work of finding the controls and getting the new values for you - you don't have to plumb the control hierarchy yourself.

Resources