BusinessRx Community

Dedicated to the advancement of software, technology and the people who devote their lives to it.

Welcome to BusinessRx Community Sign in | Join | Help
in Search

BusinessRx Reading List

These blog entries are written by industry experts and leaders. We consider this content to be a good read for any software developer or web technologist.

Browse by Tags

All Tags » asp.net controls   (RSS)
Sorry, but there are no more tags available to filter with.

  • partial nested classes

    "Partial classes" is on of the new features of v2 that, while I totally get why Microsoft wanted to add it, I didn't really see any use of them beyond the vstudio code gen world.
    "Nested classes" was one of the features of v1 that, while I completely understood the theoretical point of them, I had a HECK of a time coming up with any possible senario where it would actually be useful and the Right Decision.

    And now, within the last week, I've ran across 2 instances where the combination of both of these features made the project better and more managable.

    I'll only talk about one of them because only one is my code :)

    I'm working on a control on v2 to get a feel for various new technologies we get to play with, like callbacks and new designer possibilities. One such new designer feature is the Smart Tags that pop open next to controls which give you quick access to various actions on the control. I'm using the smart tag to let you show or hide areas of the control, so you can see them as you set the various styles.

    Implementing these smart tag actions isn't quite as simple as it could be for the simple cases, but I can see that it's quite powerful. So, getting back on topic, the implementation requires a custom Designer for the control, an ActionList class which handles the selection of the smart tag actions, and a TypeConverter class that supplies the list of actions shown in the smart tag. Neither the ActionList nor the TypeConverter class are useful outside of the Designer and the ActionList needs to access members of the Designer which really should be private. Therefore, they are both prime candidates for being nested classes.

    However, having three classes in one code file can get tedioius with the scrolling and such. And that is where partial classes come in. Before partial classes I would have just set them as internal to avoid the problem, but that is more exposure than they require. So with partial classes, I put each nested class in its own file, with the parents' "partial class" declaration becoming an extended namespace of sorts.

    So with the combination of these two features, I now have the classes having the least amount of exposure they require while still getting all the file management features I would normally have with seperate internal classes.

    So ya, call me a convert.
    Share this post: Email it! | bookmark it! | digg it! | reddit!
  • yay @ atlas

    The cat's out of the bag about Atlas. AJAX may actually get productive soon. Not to dismiss the other frameworks in place at all. ( AJAX.net has some great ideas there ) It's just easier to incorporate a library into custom controls when it's already baked into the system.

    Boy, I would _kill_ to be on the team working on that.

    Share this post: Email it! | bookmark it! | digg it! | reddit!
  • Event handler declarations in the tag are the right thing

    Teemu brought up the current event declaration behavior today, and even pointed to a bug report about it.

    I'm going to take the opposite stance. putting the onclick="whatever" attribute on the tag is the best solution to a complicated problem. Now, if the problem were limited to the points that Teemu addresses, then yes, it looks like it should changable based on the current dev model. However, the thing that makes this problem more complicated is that not every control is at the top level of your page. Asp.net uses a hierarchal declaration system with containers and child controls. One by-product of this system is that not all design-time-selectable controls on your page have references at the page level, or even refer to a single instance of a control ( in the case of a databound template declaration ).

    So, if you drag a button onto your form, and double click it to add a hook to the Click event, there are 2 or 3 basic choices ( depending on language ( VB has the Handles thing going on ))... add the glue to the tag, or add it in some initialization code block. Some want to use the code block because they don't like their UI declration to know the name of the handler function of the event.

    However, the hole there is that if you now move that button from the top level of the page's heirarchy, into a INamingContainer like a Repeater's ItemTemplate, then the instance referenced in the initialization-block doesn't exist. ( VB's Handles doodad breaks here too )

    So how should the designer attach to events in child controls if there is no top level instance to code against, nor any guarentee that the child control will exist at any given initialization time ( or be instantiated at all during that request for that matter )? To me, it seems it can't ensure correctness with any way but declarative. Which follows to the next point... Should it really use two completely different hookup mechanisms for top-level and child controls? I assert that it shouldn't as that would lead to some nitemare maintainability problems. ( "I know that it's hooked up somewhere, where did that code block go now?" ) Therefore... the tag declaration is the correct place for the designer to hook up event handlers.

    Share this post: Email it! | bookmark it! | digg it! | reddit!
  • Composite controls that do their own databinding

    Most databound controls are written from the perspective that they will be databound to something, but the control writer doesn’t know what that would be. It is assumed that the control’s container will set the datasource and databind it. Therefore the same container knows about and handles the datasource, databinding, viewstate usages, event handling, etc. This works great.

    But then application developers come along and want self contained controls, like, say… A composite control which contains a DropDownList that always contains items databound from a database, and a button that performs magic on those items. The app developer of course calls on his local control guru to make him this control.

    This gives us 3 different people with 3 very different perspectives. There is the app developer, the custom control developer, and the asp.net team control developer who made the DropDownList control. The asp.net team guy does the Right Thing in exposing a DataSource property which DataBind uses, and an EnableViewState property which says whether or not the items created should be serialized to ViewState. He’s thinking, “If a consumer of my control does want to use viewstate, they can just bind on every request.” This is a reasonable position. Then on the other end we have the app developer who is using the custom control. He had the custom control made exactly BECAUSE he doesn’t want to think about datasources and databinding and such. However, the trickiness presents itself because he does still want to be in control of ViewState usage. Maybe some specific page is hit so often that ViewState should be disabled to save on bandwidth. “My custom control should just get the data every hit, I can cache at the data-access level to make up for it.” This is also a reasonable position.

    So now the custom control developer is in a bit of a pickle. The break in the chain is that the lower levels assume that one person would be both databinding and deciding on ViewState policy. That isn’t the case here.

    Ignoring the ViewState issue for a second, the straightforward solution to this is that the composite control does a “if not postback then databind” thing during Load, and override its DataBind method to databind its child DropDownList to the database. But then what happens if the app developer sets EnableViewState to false? Obviously the control is broken. So the control dev needs to databind during load in both first-request and disabled-viewstate states. This mostly solves the problem; however there is one last problem that I just don’t see a good solution to. Think of the case where an app dev sets the EnableViewState property to false during PreRender. In this case the Load-time DataBind never runs on subsequent requests even though there won’t be ViewState to load and thus the control is broken. Now don’t think that I imagine this is a common scenario, but it’s unfortunate. The only thing I can think is that you’d have to push the responsibility of DataBind() onto the app dev in this case. It’s not something I particularly like, because I think the app dev shouldn’t have to worry about the datasources of controls contained by it’s composite control children. However, it’s the best I’ve come up with so far.

    Any other ideas?

    Share this post: Email it! | bookmark it! | digg it! | reddit!
  • The Death of DynamicImage

    Of all the features cut from asp.net v2, the only one that I'm really going to miss is the loss of DyanmicImage and the Image Generation Service.  Not so much because it's a little harder to do dynamic images in my app without them, but because it's much harder to do dynamic images in my 3rd party server controls without them. The fact that you will be able progmatticly register custom IHttpHandlers in web.config mitigates the situation a bit, but not enough.
    Share this post: Email it! | bookmark it! | digg it! | reddit!
  • MetaBuilders and Telligent

    It's not often that a contractor says, "wow, I’m so incredibly happy about my latest client", but I see myself in that position. And seeing that I have a voice, I just need to tell y’all.

    I recently signed up to help out Telligent with their Community Server: Forums project.

    I can’t express how big the smile on my face was when I started working with Rob, Jason, Scott, and Terry Denham.

    You know, when I started MetaBuilders as a business, I had plans that that selling server control products would be my main business, but the bottom line has lead me to selling my services as an asp.net/control guru, helping others get their business done. It’s worked out pretty well for me, but I’ve never been more excited about work than I am right now.

    You’ll have to excuse me for the complete lack of useful technical information in this post… I know that’s what regular readers are used to seeing… but this is really such a high point in my recent history that I really need to publish it.

    Share this post: Email it! | bookmark it! | digg it! | reddit!
  • Web Control Developer Macro Goodness

    I've had these control dev macros sitting around for a while, and I thought I'd share them finally. First I looked for a wiki I could post them to, but I was surprised to not find one for vstudio addins/macros/whatnot. The closest I found was the gotdotnet developer powertoy site, but the whole submission/wait-for-approval thing just bores me. So, I decided to post the macro file here. I hope you find them useful:

    Imports EnvDTE
    Imports System
    Imports System.Diagnostics
    Imports System.IO
    Imports System.Text
    
    Public Module CodeGen
    
        ' Creates A Public Style Property
        ' Write the following line into the code area:
        ' <StyleType> <PropertyName>
        ' Select the text, run this macro
        Public Sub CreateStyleProperty()
            CheckLanguage()
            Dim ts As TextSelection = DTE.ActiveDocument.Selection
            Dim selection As String = ts.Text.Replace(vbTab, " ").Trim(" ")
            Dim words() As String = selection.Split(" ")
            If words.Length <> 2 Then
                Return
            End If
            Dim typeName As String = words(0)
            Dim propertyName As String = words(1)
            Dim memberName As String = "_" & propertyName.Substring(0, 1).ToLower() & propertyName.Substring(1)
            Dim code As New StringBuilder
            Dim codeWriter As New StringWriter(code)
            Try
                codeWriter.WriteLine("[")
                codeWriter.WriteLine("Category( ""Style"" ),")
                codeWriter.WriteLine("Description( """" ),")
                codeWriter.WriteLine("DefaultValue( null ),")
                codeWriter.WriteLine("DesignerSerializationVisibility(DesignerSerializationVisibility.Content),")
                codeWriter.WriteLine("PersistenceMode(PersistenceMode.InnerProperty),")
                codeWriter.WriteLine("]")
                codeWriter.WriteLine("public {0} {1} {{", typeName, propertyName)
                codeWriter.WriteLine("get {")
                codeWriter.WriteLine("if ( {0} == null ) {{", memberName)
                codeWriter.WriteLine("{0} = new {1}();", memberName, typeName)
                codeWriter.WriteLine("if ( IsTrackingViewState ) {")
                codeWriter.WriteLine("((IStateManager){0}).TrackViewState();", memberName)
                codeWriter.WriteLine("}")
                codeWriter.WriteLine("}")
                codeWriter.WriteLine("return {0};", memberName)
                codeWriter.WriteLine("}")
                codeWriter.WriteLine("}")
                codeWriter.WriteLine("private {0} {1};", typeName, memberName)
                codeWriter.Flush()
            Finally
                If Not codeWriter Is Nothing Then
                    DirectCast(codeWriter, IDisposable).Dispose()
                End If
            End Try
            ReplaceCode(code.ToString(), "CreateStyleProperty" & propertyName)
        End Sub
    
        ' Creates a Public ITemplate Property
        ' Write the following line into the code area:
        ' <PropertyName> [<TemplateContainerType>]
        ' Select the text, run this macro
        Public Sub CreateTemplateProperty()
            CheckLanguage()
            Dim ts As TextSelection = DTE.ActiveDocument.Selection
            Dim selection As String = ts.Text.Replace(vbTab, " ").Trim(" ")
            Dim words() As String = selection.Split(" ")
            If 1 > words.Length OrElse words.Length > 2 Then
                Return
            End If
            Dim propertyName As String = words(0)
            Dim templateContainer As String = ""
            If words.Length = 2 Then
                templateContainer = words(1)
            End If
            Dim memberName As String = "_" & propertyName.Substring(0, 1).ToLower() & propertyName.Substring(1)
            Dim code As New StringBuilder
            Dim codeWriter As New StringWriter(code)
            Try
                codeWriter.WriteLine("[")
                codeWriter.WriteLine("Browsable( false ),")
                codeWriter.WriteLine("DefaultValue( null ),")
                codeWriter.WriteLine("Description( """" ),")
                codeWriter.WriteLine("PersistenceMode(PersistenceMode.InnerProperty),")
                If templateContainer <> "" Then
                    codeWriter.WriteLine("TemplateContainer( typeof( {0} ) ),", templateContainer)
                End If
                codeWriter.WriteLine("]")
                codeWriter.WriteLine("public ITemplate {0} {{", propertyName)
                codeWriter.WriteLine("get {")
                codeWriter.WriteLine("return {0};", memberName)
                codeWriter.WriteLine("}")
                codeWriter.WriteLine("set {")
                codeWriter.WriteLine("{0} = value;", memberName)
                codeWriter.WriteLine("ChildControlsCreated = false;")
                codeWriter.WriteLine("}")
                codeWriter.WriteLine("}")
                codeWriter.WriteLine("private ITemplate {0};", memberName)
                codeWriter.Flush()
            Finally
                If Not codeWriter Is Nothing Then
                    DirectCast(codeWriter, IDisposable).Dispose()
                End If
            End Try
            ReplaceCode(code.ToString(), "CreateStyleProperty" & propertyName)
        End Sub
    
        ' Creates A Public ViewState-Backed Property
        ' Write the following line into the code area:
        ' <PropertyType> <PropertyName> = <DefaultValue>;
        ' Select the text, run this macro
        Public Sub CreateViewStateProperty()
            CheckLanguage()
    
            Dim ts As TextSelection = DTE.ActiveDocument.Selection
            Dim selection As String = ts.Text.Replace(vbTab, " ").Trim(" ")
            Dim words() As String = selection.Split(" ")
            If words.Length < 3 Then
                Return
            End If
    
            Dim typeName As String
            Dim propertyName As String
            Dim defaultValue As String
            typeName = words(0)
            propertyName = words(1)
            defaultValue = selection.Substring(selection.IndexOf("=") + 2)
            defaultValue = defaultValue.Substring(0, defaultValue.Length - 1)
            Dim code As New StringBuilder
            Dim codeWriter As New StringWriter(code)
            Try
                codeWriter.WriteLine("[")
                codeWriter.WriteLine("Bindable(true),")
                codeWriter.WriteLine("Category( """" ),")
                codeWriter.WriteLine("Description( """" ),")
                codeWriter.WriteLine("DefaultValue( {0} ),", defaultValue)
                codeWriter.WriteLine("]")
                codeWriter.WriteLine("public virtual " & typeName & " " & propertyName & " {")
                codeWriter.WriteLine("get {")
                codeWriter.WriteLine("Object state = ViewState[""{0}""];", propertyName)
                codeWriter.WriteLine("if ( state != null ) {")
                codeWriter.WriteLine("return ({0})state;", typeName)
                codeWriter.WriteLine("}")
                codeWriter.WriteLine("return {0};", defaultValue)
                codeWriter.WriteLine("}")
                codeWriter.WriteLine("set {")
                codeWriter.WriteLine("ViewState[""{0}""] = value;", propertyName)
                codeWriter.WriteLine("}")
                codeWriter.WriteLine("}")
                codeWriter.Flush()
            Finally
                If Not codeWriter Is Nothing Then
                    DirectCast(codeWriter, IDisposable).Dispose()
                End If
            End Try
            ReplaceCode(code.ToString(), "CreateViewStateProperty" & propertyName)
        End Sub
    
        ' Creates A Public Event and Protected OnEvent Method
        ' Write the following line into the code area:
        ' <EventName> [<DelegateType> <EventArgsType>]
        ' Select the text, run this macro
        Public Sub CreateEvent()
            CheckLanguage()
            Dim ts As TextSelection = DTE.ActiveDocument.Selection
            Dim selection As String = ts.Text.Replace(vbTab, " ").Trim(" ")
            Dim words() As String = selection.Split(" ")
            If words.Length <> 1 AndAlso words.Length <> 3 Then
                Return
            End If
            Dim eventName As String = words(0)
            Dim delegateTypeName As String = "EventHandler"
            Dim eventArgsTypeName As String = "EventArgs"
            If words.Length = 3 Then
                delegateTypeName = words(1)
                eventArgsTypeName = words(2)
            End If
    
            Dim raiserName As String = "On" & eventName
            Dim eventObjectName As String = "event" & eventName
            Dim code As New StringBuilder
            Dim codeWriter As New StringWriter(code)
            Try
                codeWriter.WriteLine("#region {0} Event", eventName)
                codeWriter.WriteLine()
                codeWriter.WriteLine("public event {0} {1} {{", delegateTypeName, eventName)
                codeWriter.WriteLine("add {")
                codeWriter.WriteLine("Events.AddHandler( {0}, value );", eventObjectName)
                codeWriter.WriteLine("}")
                codeWriter.WriteLine("remove {")
                codeWriter.WriteLine("Events.RemoveHandler( {0}, value );", eventObjectName)
                codeWriter.WriteLine("}")
                codeWriter.WriteLine("}")
                codeWriter.WriteLine()
                codeWriter.WriteLine("protected void {0}( {1} e ) {{", raiserName, eventArgsTypeName)
                codeWriter.WriteLine("{0} handler = Events[ {1} ] as {0};", delegateTypeName, eventObjectName)
                codeWriter.WriteLine("if ( handler != null ) {")
                codeWriter.WriteLine("handler( this, e );")
                codeWriter.WriteLine("}")
                codeWriter.WriteLine("}")
                codeWriter.WriteLine()
                codeWriter.WriteLine("private static readonly Object {0} = new Object();", eventObjectName)
                codeWriter.WriteLine()
                codeWriter.WriteLine("#endregion")
                codeWriter.Flush()
            Finally
                If Not codeWriter Is Nothing Then
                    DirectCast(codeWriter, IDisposable).Dispose()
                End If
            End Try
            ReplaceCode(code.ToString(), "CreateEvent" & eventName)
        End Sub
    
        ' Surrounds the selected code with a try/catch/finally block
        Public Sub InsertTryCatchFinally()
            Dim endCode As New StringBuilder
            Dim writer As New StringWriter(endCode)
            Try
                writer.WriteLine("")
                writer.WriteLine("} catch( Exception ex ) {")
                writer.WriteLine("")
                writer.WriteLine("} finally {")
                writer.WriteLine("")
                writer.WriteLine("}")
                writer.Flush()
            Finally
                If Not writer Is Nothing Then
                    DirectCast(writer, IDisposable).Dispose()
                End If
            End Try
            SurroundSelectionWithCode("try {" & Environment.NewLine, endCode.ToString(), "InsertTryCatchFinally")
        End Sub
    
        ' Replaces the selected code with the given new code
        Private Sub ReplaceCode(ByVal newCode As String, ByVal undoContextName As String)
            Dim selection As TextSelection = DTE.ActiveDocument.Selection
            Dim undoContextOpened As Boolean = False
            Try
                If Not DTE.UndoContext.IsOpen Then
                    Call DTE.UndoContext.Open(undoContextName, False)
                    undoContextOpened = True
                End If
                ' Replace the text and SmartFormat it
                selection.Delete()
                selection.Insert(newCode, vsInsertFlags.vsInsertFlagsInsertAtStart)
                selection.TopPoint.CreateEditPoint.SmartFormat(selection.BottomPoint)
            Catch ex As Exception
                MsgBox("Unable To Perform Code Alteration:" & Environment.NewLine & ex.Message, MsgBoxStyle.OKOnly, "Problem Running Macro")
            Finally
                If undoContextOpened Then
                    Call DTE.UndoContext.Close()
                End If
            End Try
        End Sub
    
        ' Surrounds the selected code with the given prefix and suffix code
        Private Sub SurroundSelectionWithCode(ByVal startCode As String, ByVal endCode As String, ByVal undoContextName As String)
            Dim selection As TextSelection = DTE.ActiveDocument.Selection
            Dim undoContextOpened As Boolean = False
            Try
                If Not DTE.UndoContext.IsOpen Then
                    Call DTE.UndoContext.Open(undoContextName, False)
                    undoContextOpened = True
                End If
                Dim tp As EditPoint = selection.TopPoint.CreateEditPoint()
                selection.TopPoint.CreateEditPoint().Insert(startCode)
                Dim bp As EditPoint = selection.BottomPoint.CreateEditPoint()
                bp.Insert(endCode)
                tp.SmartFormat(bp)
            Catch ex As Exception
                MsgBox("Unable To Perform Code Alteration:" & Environment.NewLine & ex.Message, MsgBoxStyle.OKOnly, "Problem Running Macro")
            Finally
                If undoContextOpened Then
                    Call DTE.UndoContext.Close()
                End If
            End Try
        End Sub
    
        ' Ensures that the macro is modifying only c# documents
        Private Sub CheckLanguage()
            If DTE.ActiveDocument.Language <> "CSharp" Then
                Throw New System.Exception("This Macro only works on C# code")
            End If
        End Sub
    End Module
    
    Share this post: Email it! | bookmark it! | digg it! | reddit!
  • Firefox nonbug that caused me some grief today

    I ran into a rather unfortunate issue today with a server control that I thought would probably be good to talk about. The issue is created by non-bugs that come together to make a bug.

    • Firefox persists the values of form fields when the user refreshes the page.
    • Firefox does not persist any script objects applied to the document or the window
    • Complex server controls will commonly use script objects for the lifetime of the page, and use hidden inputs to round trip values from server to client to server.

    So this is the result of these 3 items...

    • A user with firefox hits your page with your control on it the first time...
    • Your initialization script runs, and all script objects and hidden inputs are in the initialized state.
    • The user plays with the page a bit, and your control changes its state, changing object properties and hidden input values.
    • The user hits refresh in their browser. Firefox nullifies all script objects, but retains the values of the hidden inputs.
    • Your control's initialization runs again, but now the script objects are created with hidden input state that is not the original.

    Now, as you can imagine, this has a very high possibility of completely borking your control. Now, before I get flames, let me restate that I don't consider this a bug in Firefox. It's just a behavior that I hadn't planned for. However, ultimately, it has a way of changing my methods for roundtripping values between client and server.

    For now, my best solution is to include any "initial" values in the RegisterArrayDeclaration call for the control, while previously i would normally only put them in the hidden input.

    Share this post: Email it! | bookmark it! | digg it! | reddit!
  • Materials from my usergroup presentation

    It's taken me a while to remember to do this...
    I gave a presentation on monday to the denver .net user group on developing asp.net server controls and i'm positing the presentation materials on for those that want it. So anyway, grab the powerpoint and code from my presentation if you want it.

    Share this post: Email it! | bookmark it! | digg it! | reddit!
Powered by Community Server, by Telligent Systems
'