views:

70

answers:

3

Hi all,

I'm looking for some guidance here.

On my site I put things in Web user controls. For example, I will have a NewsItem Control, an Article Control, a ContactForm control.

These will appear in various places on my site.

What I'm looking for is a way for these controls to pass messages up to the Page that they exist on.

I don't want to tightly couple them, so I think I will have to do this with Events/Delegates. I'm a little unclear as to how I would implement this, though.

A couple of examples:

1

A contact form is submitted. After it's submitted, instead of replacing itself with a "Your mail has been sent" which limits the placement of that message, I'd like to just notify the page that the control is on with a Status message and perhaps a suggested behaviour. So, a message would include the text to render as well as an enum like DisplayAs.Popup or DisplayAs.Success

2

An Article Control queries the database for an Article object. Database returns an Exception. Custom Exception is passed to the page along with the DisplayAs.Error enum. The page handles this error and displays it wherever the errors go.

I'm trying to accomplish something similar to the ValidationSummary Control, except that I want the page to be able to display the messages as the enum feels fit.

Again, I don't want to tightly bind or rely a control existing on the Page. I want the controls to raise these events, but the page can ignore them if it wants.

Am I going about this the right way?

I'd love a code sample just to get me started.

I know this is a more involved question, so I'll wait longer before voting/choosing the answers.

+2  A: 

The following is assuming you know that your controls are all placed on a page of type App.YourPage

Here's a quick message box that I place onto the MasterPage or Page and just call from any page or control. (Sorry its in VB.net not c#)

You can extend out AddMessage to log and do other transaction based action (I pulled out our controller logic from it)

from any control:

CType(Page, App.YourPage).messageBox.AddMessage(
         ctrlMessageBox.MessageTypes.InfoMessage
          ,"Updated Successfully")

Control:

    Public Class ctrlMessageBox
        Inherits System.Web.UI.UserControl

        'List of types that a message could be
        Enum MessageTypes
            InfoMessage
            ErrorMessage
            WarningMessage
        End Enum

#Region "[Message] inner class for structered message object"
        Public Class Message
            Private _messageText As String
            Private _messageType As MessageTypes
            Public Property MessageText() As String
                Get
                    Return _messageText
                End Get
                Set(ByVal value As String)
                    _messageText = value
                End Set
            End Property
            Public Property MessageType() As MessageTypes
                Get
                    Return _messageType
                End Get
                Set(ByVal value As MessageTypes)
                    _messageType = value
                End Set
            End Property

        End Class
#End Region

        'storage of all message objects
        Private _messages As New List(Of Message)

        'Creates a Message object and adds it to the collection
        Public Sub addMessage(ByVal MessageType As MessageTypes, ByVal MessageText As String)
            Page.Trace.Warn(Me.GetType.Name, String.Format("addMessage({0},{1})", MessageType.ToString, MessageText))
            Dim msg As New Message
            msg.MessageText = MessageText
            msg.MessageType = MessageType
            _messages.Add(msg)
        End Sub

        Protected Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreRender
            ' Page.Trace.Warn(Me.GetType.Name, String.Format("Page_PreRender(_messages.Count={0})", _messages.Count))

        End Sub
        Public Overrides Sub RenderControl(ByVal writer As System.Web.UI.HtmlTextWriter)
            Page.Trace.Warn(Me.GetType.Name, String.Format("ctrlMessageBox.RenderControl(_messages.Count={0})", _messages.Count))
            'draws the message box on the page with all messages

            If _messages.Count = 0 Then Return
            Dim sbHTML As New StringBuilder
            sbHTML.Append("<div id='MessageBox'>")

            For Each msg As Message In _messages
                sbHTML.AppendFormat("<p><img src='{0}'> {1}</p>", getImage(msg.MessageType), msg.MessageText)
            Next

            sbHTML.Append("</div>")

            writer.Write(sbHTML.ToString)

            'dim ctrlLiteral As New Literal()
            'ctrlLiteral.Text = sbHTML.ToString
            'Me.Controls.Add(ctrlLiteral)
        End Sub

        'returns a specific image based on the message type
        Protected Function getImage(ByVal type As MessageTypes) As String
            Select Case type
                Case MessageTypes.ErrorMessage
                    Return Page.ResolveUrl("~/images/icons/error.gif")
                Case MessageTypes.InfoMessage
                    Return Page.ResolveUrl("~/images/icons/icon-status-info.gif")
                Case MessageTypes.WarningMessage
                    Return Page.ResolveUrl("~/images/icons/icon-exclaim.gif")
                Case Else
                    Return ""
            End Select
        End Function
    End Class
Glennular
+2  A: 

You can bubble up the event occurs in child to parent page. Parent page can register that event and utilizes it (if it is useful).

Parent ASPX

<uc1:ChildControl runat="server" ID="cc1" OnSomeEvent="cc1_SomeEvent" />

Parent c#

protected void cc1_SomeEvent(object sender, EventArgs e)
{
    // Handler event
}

Child C#

public event EventHandler OnSomeEvent;

protected void ErrorOccurInControl()
{
     if (this.OnSomeEvent != null)
     {
          this.OnSomeEvent(this, new EventArgs());
     }
}

protected override void OnLoad(EventArgs e)
{
     ErrorOccurInControl();
}
winmyan
Yes... I think this is close to what I'm looking for. Some stuff to digest this weekend.
Atømix
+1  A: 

The data annotation validators are really good for this type of thing. Typically they are used within ASP.NET MVC, but they work just fine in WebForms. You can use the built-in validators or create your own custom ones that do more complex validations.

This example is in VB.NET, but it shouldn't be hard for you to see the value:

http://adventuresdotnet.blogspot.com/2009/08/aspnet-webforms-validation-with-data.html

http://blogs.microsoft.co.il/blogs/gilf/archive/2010/04/08/building-asp-net-validator-using-data-annotations.aspx

Nissan Fan
Thanks for the link! I'm definitely going to look into it. It wasn't the direction I was thinking but it looks very promising!
Atømix