Introduction

You know how in facebook , when you click Add as Friend, this popup appears

fbRequest.jpg

once you click Send Request, the Add as Friend changes to Friend Request Sent

without refreshing the page, how to do this is in .Net ?

Dissection

we'll place the popup in a User Control

User Control

A modal pop containing whatever bussines we want to handle.

For sake of demonstration, let the popup display a calendar, and return the Selected Date into the source pages's Textbox.

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="CalendarControl.ascx.cs"
    Inherits="CalendarControl" %>
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp" %>
<link href="Styles/Control.css" rel="stylesheet" type="text/css" />
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
    <ContentTemplate>
        <asp:Panel ID="Panel1" runat="server" BackColor="White" Style="display: none">
            <asp:Calendar ID="Calendar1" runat="server" OnSelectionChanged="Calendar1_SelectionChanged"
                OnVisibleMonthChanged="Calendar1_VisibleMonthChanged"></asp:Calendar>
            <asp:ImageButton ID="btnClose" runat="server" ImageUrl="~/Images/fancy_close.png"
                class="fancybox-close" OnClick="btnCloseMsg_Click" />
        </asp:Panel>
        <asp:ModalPopupExtender ID="Panel1_ModalPopupExtender" runat="server" BackgroundCssClass="overlay_style"
            DropShadow="true" DynamicServicePath="" Enabled="True" PopupControlID="Panel1"
             TargetControlID="FakeButton">
        </asp:ModalPopupExtender>
        <asp:Button ID="FakeButton" runat="server" Style="display: none" />
    </ContentTemplate>
</asp:UpdatePanel>

        

Source Page

Just the textbox where we want our result to return to, and a button to display the popup.

SourcePage.jpg

<head runat="server">
    <title>Test</title>
</head>
<body>
    <form runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server">
    </asp:ScriptManager>
    <asp:UpdatePanel ID="UpdatePanel1" runat="server">
        <ContentTemplate>
            <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
            <asp:Button ID="btnGetDate" runat="server" Text="Get Date" OnClick="btnGetDate_Click" />
            <uc1:CalendarControl ID="ucCalendar" runat="server" OnDateSelected="OnDateSelected" />
        </ContentTemplate>
    </asp:UpdatePanel>
    </form>
</body>
</html>

please note that the textbox is contained in an UpdatePanel

Problem

The main issue is: how to make the calling page feel your custom control?
I.e. our control is a calendar, we want the textbox in the source page to see the date we just selected.

I have came across the following solutions:

  1. ASP Server-Side JavaScript-like Calendar PopUp
  2. ASP.NET AJAX Control Toolkit ModalPopupExtender Control in Action

Both are good, but i wanted something simpler, without the fuss of JavaScript or Iframes, so i decided to use a different approach.

Solution


The answer is Event Bubbling

In our User Control

we will need a delegate, and an event based on that delegate.

public delegate void DateSelectedHandler(DateTime dtDateSelected);
public event DateSelectedHandler DateSelected;
        

Note how we gave the delegate an argument of same type as the value we want returned (Datetime).

Then, we created a new event, of same type as the delegate.

Now in Calendar1_SelectionChanged event, lets call the event instance we just created.

        if (DateSelected != null)
            DateSelected(Calendar1.SelectedDate);
        

What we did is simply passing the value to our custom, public event, Now, this event is exposed to our source page.
This is Event Bubbling, events are propagated up the hierarchy (remember bubble sort ? )

User Control Code Behind

using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class CalendarControl : System.Web.UI.UserControl
{
    public delegate void DateSelectedHandler(DateTime dtDateSelected);
    public event DateSelectedHandler DateSelected;

    #region Events
    protected void Calendar1_SelectionChanged(object sender, EventArgs e)
    {
        if (DateSelected != null)
            DateSelected(Calendar1.SelectedDate);
    }
    protected void Calendar1_VisibleMonthChanged(object sender, MonthChangedEventArgs e)
    {
        this.Panel1_ModalPopupExtender.Show();
    }

    protected void btnCloseMsg_Click(object sender, ImageClickEventArgs e)
    {
        Panel1_ModalPopupExtender.Hide();
    }
    #endregion

    #region Methods
    public void Show()
    {
        this.Panel1_ModalPopupExtender.Show();
    }
    #endregion
}
Now all we have to do is exploit our custom made event.

In our Source Page

.aspx

    <uc1:calendarcontrol ondateselected="OnDateSelected" runat="server" id="ucCalendar">
        </uc1:calendarcontrol>
.cs
    protected void OnDateSelected(DateTime dtDateSelected)
    {
        TextBox1.Text = dtDateSelected.ToShortDateString();
    }
        

Source Page Code Behind

using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class Test : System.Web.UI.Page
{
    #region Events
    protected void OnDateSelected(DateTime dtDateSelected)
    {
        TextBox1.Text = dtDateSelected.ToShortDateString();
    }
    protected void btnGetDate_Click(object sender, EventArgs e)
    {
        ucCalendar.Show();
    }
    #endregion
}

Final Tip

If want your control to stay visible on postbacks.(when user changes months for example)

    protected void Calendar1_VisibleMonthChanged(object sender, MonthChangedEventArgs e)
    {
        this.Panel1_ModalPopupExtender.Show();
    }
        

Conclusion

So that’s it, build your user control, handle your business and validation, and in then pass the end result.
With the help of delegates and events, we were able provide a nice solution to an old problem.

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架
新浪微博粉丝精灵,刷粉丝、刷评论、刷转发、企业商家微博营销必备工具"