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.
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
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.
Thought I'd mention this, just because I like the look so much. Somebody snagged the
windows theme from media center edition and it's been posted on winbeta.org. It's basically a lickable version of the standard blue/green xp theme. Very nice.
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.
You know, I'd love to try out the new Beta1 of Visual Web Developer, but I can't. Setup just yells at me and stops.
You see, i had the May CTP installed previously, so I uninstalled it before running the setup. However I get this message from the setup:
---------------------------
Visual Web Developer 2005 Express Edition Beta - English Setup
---------------------------
Setup has detected that previous versions of the following product(s) are currently installed.
Uninstall these applications before continuing with Setup. For more information, see the
readme.htm file. This file can be found at the root of the DVD or CD1, on the Web download site
for the product, or on a network share, depending on how you install the product.
- Visual Studio .NET Prerequisites - English
---------------------------
OK
---------------------------
There is no entry in the "add/remove programs" control panel with this name. So this dialog is not extremely useful to me. As for the readme.htm file, i have no idea where to look for this hypothetical file.
UPDATE
Wally helped my fixed this first problem. However, now it just gets farther before it dies. Now I just says that the download of the "Microsoft .NET Framework 2.0 Beta" component failed. With no reason given. How Useful for me...
After a whole lot of work, MetaBuilders has MultiViewBar available, my first commercial control. And with that, I felt that the first site redesign was in order.
By far, the hardest part of doing this was the business setup stuff. Forms... Accounts... Business Plans... it's a mountain. Anyway, MetaBuilders is now an LLC, and everybody should expect more commercial controls to be availble very soon. The development is so much easier than the business side. :)
So I was messing around with Winamp and this plugin which pops up some toast when the track changes. The latest version will use the windows xp “folder.jpg” feature to show the album art for the track if it can. I thought this was pretty cool, but with so many folders of tracks, it would be way to much work to download the album art for each one.
So, a bit of googling later... and I found that somebody had thought this would be a good idea as well. Str8dog wrote MP3 Album Art Downloader in c# using an Amazon.com webservice to download the images. Just drop it in your main tunes folder, run it (command line), and a few seconds later all (YMMV) your folders will have album art. Sweet.
This is great. Dan Fernandez points to a MSDN article on creating an Outlook addin in c#. Besides the fact that it looked like a good article after scanning it quickly... it’s that you can download the product of the article, which is a clone of the oldskool email client, Pine! Boy, that brings back some bittersweet memories.
More Posts
« Previous page -
Next page »