An Original Idea

because all great software begins with an original idea

Archive for the 'VB.Net' Category


Twittering using the Compact Framework

Posted by anoriginalidea on May 19, 2008

 image

My twitter updates are done using a variety of code.  At the moment I use the Curl command line  in conjunction with SlickRun.  In the past I did this with Outlook (see the article Twittering from Outlook Using VBA).  In the past I’ve found this pretty easy to do using the Twitter Api.

 

I also like to do updates from my Pocket PC, but am not keen on SMS charges.  The solution of course is to create my own client, which I’ll be posting about shortly.

For my client program I intend to use TwitterLib library.  Sadly this does not work for the compact framework unaltered.  I am currently working on porting it to the compact framework.

 

In the interim I want to share with you a simple code sample for submitting tweets to Twitter. 

The example is simple enough to be used by people who want to do HTTP posts to similar services.

 

    Dim lsParams As String = “status=” & Uri.EscapeDataString(tweetText)

    Dim loRequest As HttpWebRequest = CType(HttpWebRequest.Create(”http://twitter.com/statuses/update.xml”), HttpWebRequest)
           With loRequest
               .Proxy = System.Net.GlobalProxySelection.GetEmptyWebProxy()

               .Timeout = 10000
               .AllowAutoRedirect = True
               .AllowWriteStreamBuffering = True

               .Method = “POST”

               .ContentType = “application/x-www-form-urlencoded”
               .ContentLength = Len(lsParams)

               Dim loCred As New System.Net.NetworkCredential(”someusername”, “somepassword”)
               .Credentials = loCred

               ‘ Write the request paramater
               Dim stOut As New StreamWriter(.GetRequestStream(), System.Text.Encoding.ASCII)
               stOut.Write(lsParams)
               stOut.Flush()
               stOut.Close()

               Dim loResp = .GetResponse
               With loResp

                   .Close()
               End With

           End With

 

The most important difference with the full .net framework is the “GetEmptyWebProxy” and “AllowWriteStreamBuffering” lines.  It won’t work without it.


Share this post :

Posted in .net Framework, Pocket PC Development, VB.Net | Tagged: , , , , | No Comments »

Easy InkCanvas in Winforms for capturing signatures

Posted by anoriginalidea on April 18, 2008

image

In WPF there’s an interesting control called “InkCanvas” that can be used to capture signatures and the like in Tablet PC applications.

Recently I created a prototype for a windows forms application.  I did consider using WPF, but the overhead seemed unnecessary considering the simplicity of the requirement.

I am aware there’s a specific SDK for Tablet PC that provides winforms controls for the requirement, but I thought it might be fun to create my own.  As it turns out, it was pretty easy.

The requirement was to have a signature panel which could be used to collect a bitmap that would be attached to an entity to act as an authorisation.

Signature Panel

In the prototype I decided to create the signature panel as a standalone usercontrol called it, strangely enough “SignaturePanel”.

It uses Mousedown and MouseUp events to determine stylus pressure and mousemove for drawing.  Like the WPF control it keeps a collection of strokes internally.

Unlike the wpf control, I just decided to expose a “SignatureImage” property to allow a developer to retrieve a bitmap.  This is rendered from the strokes in realtime.

I assume it works for the Tablet PC, but I don’t know for sure.

Write your signature here

An additional feature of this control is a label which tells the user the last time the signature was last updated.  I thought the user may find this helpful.

If the user hasn’t written anything then it just reads “Write your signature here”.

The user control consists of a picturebox called “inkPanel” and a button for resetting the content:

 

What the control looks like in design time

Here’s the code:

 

Public Class SignaturePanel

    Private moCurrentWriting As New List(Of Point)
    Private moRememberInk As New List(Of List(Of Point))
    Private mbPenDown As Boolean = False
    Private Sub inkPanel_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles inkPanel.MouseDown
        mbPenDown = True
    End Sub

    Private Sub inkPanel_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles inkPanel.MouseMove
        If mbPenDown Then
            moCurrentWriting.Add(e.Location)
            mdLastSignatureUpdate = Now
            Me.Refresh()
        End If
    End Sub

    Private Sub inkPanel_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles inkPanel.MouseUp
        If moCurrentWriting.Count > 2 Then
            moRememberInk.Add(moCurrentWriting)
        End If

        moCurrentWriting = New List(Of Point)
        mbPenDown = False
    End Sub

    Private Sub inkPanel_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles inkPanel.Paint

        mRenderSignature(e.Graphics)

        Dim lsText As String = “”
        If Not Me.DesignMode Then
            If mdLastSignatureUpdate.HasValue Then
                lsText = “Signature last updated ” & Me.LastSignatureUpdate.ToLongTimeString
            End If
            e.Graphics.DrawString(lsText, Me.Font, Brushes.Black, 5, inkPanel.Height - 20)
        Else
            lsText = “… Write your signature here …”

            e.Graphics.DrawString(lsText, Me.Font, Brushes.Black, (inkPanel.Width / 2) - (e.Graphics.MeasureString(lsText, Me.Font).Width / 2), (inkPanel.Height / 2) - (e.Graphics.MeasureString(lsText, Me.Font).Height / 2))
        End If
    End Sub
    Private Sub mRenderSignature(ByVal g As Graphics)
        Using loPen As New Pen(Color.Black)
            loPen.Width = 2
            For Each loLines As List(Of Point) In moRememberInk
                g.DrawLines(loPen, loLines.ToArray)
            Next
            If moCurrentWriting.Count > 1 Then
                g.DrawLines(loPen, moCurrentWriting.ToArray)
            End If
        End Using
    End Sub
    Private Sub cmdClearInk_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdClearInk.Click
        moRememberInk.Clear()
        inkPanel.Refresh()
    End Sub
    Private mdLastSignatureUpdate As Nullable(Of Date) = Nothing
    <System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)> _
    Public Property LastSignatureUpdate() As Date
        Get
            Return mdLastSignatureUpdate
        End Get
        Set(ByVal value As Date)
            mdLastSignatureUpdate = value
        End Set
    End Property

    <System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)> _
    Public ReadOnly Property SignatureImage() As Image
        Get
            Dim loBitmap As New Bitmap(Me.Width, Me.Height)
            Using loGfx As Graphics = Graphics.FromImage(loBitmap)
                mRenderSignature(loGfx)
            End Using

            Return loBitmap
        End Get
    End Property

End Class

 

If anyone’s interested in a standalone sample project, post the request to this blog and I’ll see what I can do.

Possible Uses

It may be interesting to use this code as:

  • Signature recognition
  • “Mud map” style sketching for business applications
  • A basis for a drawing program ;)

Of course, if you’re using WPF, use InkPanel.  But if you don’t want the overhead, maybe this will be the foundation of a lightweight solution.

 


Share this post :

Posted in .net Framework, VB.Net, Windows Forms | Tagged: , , | 5 Comments »

Give the "Gift of Text" by sending an SMS with VB.NET and Skype

Posted by anoriginalidea on February 26, 2008

image

Never underestimate the value (to some) of sending someone a note.  In my case, a note to my beloved is an excellent way of ensuring a happier homecoming.

Each note has to have an appropriately original sentiment, and be sent in a timely fashion.  Sometimes circumstances do not permit time for the creative effort required.   (Although I’ve heard that Generation Y can shoot of a text message faster than I just wrote the word faster…)

So why not queue up some appropriate messages and let my computer send one a day at the appropriate time?  Yes I’m sure you can think of plenty, but this is just an intro to a code sample….

So to send an SMS, all you need to do is install Skype and get a reference to the COM type library:

image

 

After this, the following code sample should be enough to get you in trouble:

 

Public Sub SendSMS(ByVal strNumber As String, ByVal strBody As String)
    Dim loSkype As New SKYPE4COMLib.Skype
    Dim loSmsMessage As SKYPE4COMLib.SmsMessage

    loSmsMessage = loSkype.CreateSms(SKYPE4COMLib.TSmsMessageType.smsMessageTypeOutgoing, strNumber)
    loSmsMessage.Body = strBody
    loSmsMessage.Send()
    Trace.WriteLine(loSmsMessage.Status.ToString)

    loSmsMessage = Nothing
    loSkype = Nothing

End Sub

 

Have fun!

Links

Original VBA post by Conrad Sharry


Share this post :

Posted in .net Framework, VB.Net | Tagged: , , , , | No Comments »

Getting the SMTP Email Address of an Exchange Sender of a MailItem from Outlook in VB.NET VSTO

Posted by anoriginalidea on January 11, 2008

 image

Sometimes the easiest things in software development are the hardest things.  Particularly when it comes to VSTO development.

The Problem

You’d think that programmatically retrieving the sender’s SMTP email address from an email item in Outlook would be easy wouldn’t you?  It isn’t.

The “Address” property of the MailItem object is supposed to return the email address.   And it does if your email comes from an internet sender, such as a friendly Nigerian businessman.  If the email sender a user of Microsoft Exchange, you get a wierd X400 formatted email address.  Not very handy if you want the SMTP email address.

If you search for this information you’ll find solutions that usually involve obsolete components (CDO 1.21 - Unsupported by Microsoft) or 3rd party dlls (such as the excellent “Outlook Redemption”).   See the links section at the bottom of this article for a list of the good articles that discuss these techniques.

If you want your application to “remain pure” .NET however, there is no “cut and dried” solution.

The Solution

After much experimentation and agony my colleague Puji Arsana and myself have devised a solution that uses pure VSTO and VB.Net, without any 3rd party dependencies.

It seems to me that many people have already created this solution (and published parts of this), but so far noone has published a complete solution before.

So without further ado, here’s the VB.NET code to allow you to extract the SMTP email address, regardless of whether it’s an exchange or internet email.

Private Function GetSMTPEmailAddress(mailItem As MailItem) As String

    If mailItem.SenderAddressType = “EX” Then
         Return GetEmailAddressForExchangeServer(loItem.Name)
    Else
         Return mailItem.Address
    End If

End Function

Private Function GetEmailAddressForExchangeServer(ByVal emailName As String) As String
        Dim loDummyMsg As MailItem = moMailItem.Application.CreateItem(OlItemType.olMailItem)
        Dim loAddress As Recipient = loDummyMsg.Recipients.Add(emailName)

        loAddress.Resolve()
        Dim lsSmtpAddress As String = GetMAPIProperty(loAddress.AddressEntry.MAPIOBJECT, PR_SMTP_ADDRESS)
        Return lsSmtpAddress

End Function

#Region “MAPI Interface ID’S”
    ‘ The Interface ID’s are used to retrieve the specific MAPI Interfaces from the IUnknown Object
    Private Const IID_IMAPISession As String = “00020300-0000-0000-C000-000000000046″
    Private Const IID_IMAPIProp As String = “00020303-0000-0000-C000-000000000046″
    Private Const IID_IMAPITable As String = “00020301-0000-0000-C000-000000000046″
    Private Const IID_IMAPIMsgStore As String = “00020306-0000-0000-C000-000000000046″
    Private Const IID_IMAPIFolder As String = “0002030C-0000-0000-C000-000000000046″
    Private Const IID_IMAPISpoolerService As String = “0002031E-0000-0000-C000-000000000046″
    Private Const IID_IMAPIStatus As String = “0002031E-0000-0000-C000-000000000046″
    Private Const IID_IMessage As String = “00020307-0000-0000-C000-000000000046″
    Private Const IID_IAddrBook As String = “00020309-0000-0000-C000-000000000046″
    Private Const IID_IProfSect As String = “00020304-0000-0000-C000-000000000046″
    Private Const IID_IMAPIContainer As String = “0002030B-0000-0000-C000-000000000046″
    Private Const IID_IABContainer As String = “0002030D-0000-0000-C000-000000000046″
    Private Const IID_IMsgServiceAdmin As String = “0002031D-0000-0000-C000-000000000046″
    Private Const IID_IProfAdmin As String = “0002031C-0000-0000-C000-000000000046″
    Private Const IID_IMailUser As String = “0002030A-0000-0000-C000-000000000046″
    Private Const IID_IDistList As String = “0002030E-0000-0000-C000-000000000046″
    Private Const IID_IAttachment As String = “00020308-0000-0000-C000-000000000046″
    Private Const IID_IMAPIControl As String = “0002031B-0000-0000-C000-000000000046″
    Private Const IID_IMAPILogonRemote As String = “00020346-0000-0000-C000-000000000046″
    Private Const IID_IMAPIForm As String = “00020327-0000-0000-C000-000000000046″
#End Region

#Region “MAPI Properties”

    ‘ MAPI Properties
    Public Const PR_TRANSPORT_MESSAGE_HEADERS As UInteger = 8192030
    Public Const PR_BODY As UInteger = 268435486
    Public Const PR_BODY_HTML As UInteger = 269680670
    Public Const PR_HTML As UInteger = 269680898
    Public Const PR_DISPLAY_NAME As UInteger = 805371934
    Public Const PR_SUBJECT As UInteger = 3604510
    Public Const PR_EMAIL_ADDRESS As UInteger = 805503006
    ‘public const uint PR_NEG_EMAIL_ADDRESS = -2146496482;
    Public Const PR_SMTP_ADDRESS As UInteger = 972947486
    Public Const PR_ADDRTYPE As UInteger = 805437470
#End Region

#Region “structure and variables “
    Private Structure SPropValue
        Public ulPropTag As UInteger
        Public dwAlignPad As UInteger
        Public Value As Long
    End Structure

    ‘ return codes
    Private Const S_OK As Integer = 0
#End Region

#Region “MAPI Functions”

    <DllImport(”MAPI32.DLL”, CharSet:=CharSet.Ansi, EntryPoint:=”HrGetOneProp@12″)> _
    Private Shared Sub HrGetOneProp(ByVal pmp As IntPtr, ByVal ulPropTag As UInteger, ByRef ppProp As IntPtr)
    End Sub

    <DllImport(”MAPI32.DLL”, CharSet:=CharSet.Ansi, EntryPoint:=”HrSetOneProp@8″)> _
    Private Shared Sub HrSetOneProp(ByVal pmp As IntPtr, ByVal pprop As IntPtr)
    End Sub

    <DllImport(”MAPI32.DLL”, CharSet:=CharSet.Ansi, EntryPoint:=”MAPIFreeBuffer@4″)> _
    Private Shared Sub MAPIFreeBuffer(ByVal lpBuffer As IntPtr)
    End Sub

    <DllImport(”MAPI32.DLL”, CharSet:=CharSet.Ansi)> _
    Private Shared Function MAPIInitialize(ByVal lpMapiInit As IntPtr) As Integer
    End Function

    <DllImport(”MAPI32.DLL”, CharSet:=CharSet.Ansi)> _
    Private Shared Sub MAPIUninitialize()
    End Sub

    ”’ <summary>
    ”’ Get a property from a passed MAPI object
    ”’ </summary>
    ”’ <param name=”oMAPIObject”></param>
    ”’ <param name=”uiPropertyTag”></param>
    ”’ <returns></returns>
    Private Shared Function GetMAPIProperty(ByVal oMAPIObject As Object, ByVal uiPropertyTag As UInteger) As String

        If oMAPIObject.Equals(Nothing) Then
            ‘No MAPI Object
            Return “”
        End If

        Dim sProperty As String = “”
        Dim pPropValue As IntPtr = IntPtr.Zero

        Dim IUnknown As IntPtr = IntPtr.Zero
        Dim IMAPIProperty As IntPtr = IntPtr.Zero

        Try

            ‘ initialize MAPI
            MAPIInitialize(IntPtr.Zero)

            ‘ get the unknown object.
            IUnknown = Marshal.GetIUnknownForObject(oMAPIObject)

            ‘get the property
            Dim guidIMAPIProp As New Guid(IID_IMAPIProp)
            If Marshal.QueryInterface(IUnknown, guidIMAPIProp, IMAPIProperty) <> S_OK Then
                ‘Failed to get IMAPIProperty
                Return “”
            End If

            Try

                ‘ get the field from the MAPI Property
                HrGetOneProp(IMAPIProperty, uiPropertyTag, pPropValue)
                ‘ Is the property actually there?
                If pPropValue = IntPtr.Zero Then
                    Return “”
                End If
                ‘ Get the value back
                Dim propValue As SPropValue = DirectCast(Marshal.PtrToStructure(pPropValue, GetType(SPropValue)), SPropValue)
                ‘ convert to string

                sProperty = Marshal.PtrToStringAnsi(New IntPtr(propValue.Value))
            Catch ex As System.Exception
                Throw ex
            End Try
        Finally
            ‘ CLEAN UP
            If pPropValue <> IntPtr.Zero Then
                MAPIFreeBuffer(pPropValue)
            End If

            If IMAPIProperty <> IntPtr.Zero Then
                Marshal.Release(IMAPIProperty)
            End If
            If IUnknown <> IntPtr.Zero Then
                Marshal.Release(IUnknown)
            End If

            MAPIUninitialize()
        End Try

        Return sProperty
    End Function
#End Region

How it Works

If the email is from exchange it translates the  email address into a “Recipient” object. 

Recipient objects expose “AddressEntry” objects, which in turn can be utilised by “ExtendedMAPI”.

The code then uses ExtendedMAPI which can “see” the property where the normal Outlook API cant.

Links

See http://www.outlookcode.com/d/code/getsenderaddy.htm#redemption and http://www.cdolive.com/cdo5.htm#EMailAddressOfSender for Redemption and CDO examples and http://groups.google.com/group/microsoft.public.outlook.program_vba/browse_frm/thread/4d4d5fece24a2a7/ad2fcbb691d5bf18 for a discussion of the property to use with Cached Exchange Mode in Outlook 2003 or later.


Share this post :

Posted in .net Framework, Outlook, VB.Net, VSTO | Tagged: , , , , | 12 Comments »

Getting a Screenshot with VB.NET on the Compact Framework 2.0

Posted by anoriginalidea on January 3, 2008

 

image

I believe that “thumbnail” images of data in applications is a powerful way of giving an overview to a user.

One sort of application that uses this technique is the “Flip 3D” functionality of Vista.

The code sample below provides a routine that “grabs” a rectangle of the currently displayed screen.  Just like it’s desktop equivalent, it can only take screenshots of the visible screen, not graphics that are off-screen. (Anyone know how to do that? Please let me know!)

Here’s the code:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    picScreenshot.Image = GetControlBitmap(Me.CreateGraphics, Me.SomeControl.Bounds)
End Sub
Const SRCCOPY As Integer = &HCC0020
Public Declare Function BitBlt Lib “coredll.dll” (ByVal hdc As IntPtr, ByVal nXDest As Integer, ByVal nYDest As Integer, ByVal nWidth As Integer, ByVal nHeight As Integer, ByVal hdcSrc As IntPtr, ByVal nXSrc As Integer, ByVal nYSrc As Integer, ByVal dwRop As Integer) As Boolean

Private Function GetControlBitmap(ByVal gx As Graphics, ByVal rect As Rectangle) As Bitmap

    ‘ Create the bitmap to output
    Dim loBitmap As Bitmap = New Bitmap(rect.Width, rect.Height)

    ‘ Create compatible graphics
    Dim loCompGraphics As Graphics = Graphics.FromImage(loBitmap)

    ‘ Blit the image data
    BitBlt(loCompGraphics.GetHdc(), 0, 0, rect.Width, rect.Height, gx.GetHdc(), rect.Left, rect.Top, SRCCOPY)

    ‘ Cleanup
    loCompGraphics.Dispose()
    Return loBitmap
End Function

The function “GetControlBitmap” will get a bitmap of a control or any rectangle passed into it.

Links


Share this post :

Posted in .net Framework, Pocket PC Development, VB.Net | Tagged: , , , , | 2 Comments »

Disabling the context menu in the .Net CF WebBrowser Control

Posted by anoriginalidea on December 31, 2007

image

Although initially impressive, the WebBrowser control in the .NET Compact Framework 2.0 lacks the ability to be customised in a few important areas. An obvious one that people are asking about seems to be the ability to remove the default context menu.

None of the obvious solutions , such as setting the ContextMenu property to null seem to work.

The Problem
The internal PIE control that the WebBrowser control wraps has a COM property to disable it, but this is not exposed.

So how can we set the property?

The .NET CF 2.0 provides the answer. It introduced some new features that allows straight forward interaction with COM objects and controls.

Doing this with the WebBrowser control involves sending a special windows message (DTM_BROWSERDISPATCH) to the windows handle of the control to retrieve a pointer to the IDispatch interface, converted into an object (using the GetObjectForIUnknown call) , which is then cast to a marked up interface with the appropriate identifiers. These are found webvw.h which is part of the Compact Framework SDK.

This technique will only work for Windows Mobile (not Smartphone) based devices. For my own projects I use a compiler directive to screen avoid the COM calls on the Smartphone platform.

The Solution

I have cut down the solution to it’s bare essentials and encapsulated it in the class WebBrowserContactMenu. You should be able to reuse this class, unaltered in your own project.

Warning: Currently this solution WILL ONLY WORK FOR Windows Mobile 2003!   It is supposed to work for WM5 and above also (it all seems correct) but for some reason the SendMessage to DTM_BROWSERDISPATCH is not working at all.   I have researched the problem but as yet cannot find a workaround.  I will update this article if I do.  Any suggestions are welcome.

Imports System.Runtime.InteropServices
Imports System.Runtime.CompilerServices
Public Class WebBrowserContextMenu
Private moWebBrowser As WebBrowser
Public Sub New(ByVal control As WebBrowser)
moWebBrowser = control
End Sub
Const WM_USER As Integer = &H400
Const DTM_BROWSERDISPATCH As Integer = (WM_USER + 124)
Declare Function SendMessageLongRef Lib “Coredll” Alias “SendMessageW” (ByVal HWND As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, ByRef lParam As Integer) As Integer
Public Property Enabled() As Boolean
Get
Return mGetBrowserInterface.ContextMenuEnabled
End Get
Set(ByVal value As Boolean)
mGetBrowserInterface.ContextMenuEnabled = value
End Set
End Property

Private Function mGetBrowserInterface() As IBrowserBareEssentials

Dim liPtr As Integer = 0
SendMessageLongRef(moWebBrowser.Handle.ToInt32, DTM_BROWSERDISPATCH, 0, liPtr)

Return CType(System.Runtime.InteropServices.Marshal.GetObjectForIUnknown(CType(liPtr, IntPtr)), IBrowserBareEssentials)

End Function

<ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIDispatch), Guid(”698E3FC9-70C3-11D0-81E8-00A0C90AD20A”)> _
Public Interface IBrowserBareEssentials

<DispId(185)> Property ContextMenuEnabled() As Boolean
End Interface
End Class

In the example project, a simple WebBrowser application hosts this class, instantiating it and using radio buttons to toggle the button. Here’s what the form code looks like:

Public Class Form1
Private moContextMenu As WebBrowserContextMenu
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
WebBrowser1.Navigate(New Uri(txtUrl.Text))
moContextMenu = New WebBrowserContextMenu(WebBrowser1)
End Sub
Private Sub cmdGo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdGo.Click
WebBrowser1.Navigate(New Uri(txtUrl.Text))
End Sub
Private Sub optEnabled_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles optEnabled.Click
moContextMenu.Enabled = optEnabled.Checked
End Sub
Private Sub optDisabled_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles optDisabled.Click
moContextMenu.Enabled = optEnabled.Checked
End Sub

End Class

Download the sample project. (14K)

Conclusion

The purpose of this article was to provide a direct solution to the context menu problem. I have by no means an exhaustive description of using COM with WebBrowser, but this may help as an introduction. At a future date I will share other uses for this technique.

Share this post :

kick it on DotNetKicks.com

Posted in .net Framework, Pocket PC Development, VB.Net | Tagged: , , , | 4 Comments »

Weird Science - Defining Winforms in XAML

Posted by anoriginalidea on December 13, 2007

image

I like to think of XAML as an “object instantiation script”.  According the to the main books on the subject it should be possible to utilise XAML to create any kind of .net object. 

Practical examples include WWF (Windows Workflow Foundation) , which allows the storage of definition in XAML, which is nothing to do WPF.  WPF (Windows Presentation Foundation) was the original reason XAML was created, but XAML was designed to be independent.

So I was thinking, why not see if I can define a traditional “Winform” in XAML.    Why would I want to?   I thought it might be fun.   As it turns out, it may actually be useful in some scenarios.  (With a great stretch of the imagination)

So does it work?  Oh yes it works and it works well.   “Well” means that VS2008 provides full intellisense for tags within the Xaml designer, as well as “code behind”.  Now that, my friends, is cool.  Imagine being able to create form layouts using XML tags instead of that oh-so-last year winforms designer!  The result is surprisingly WPF like, which I find intriguing.

To create the example below, I created a WPF project, then removed the default WPF “Window1.xaml” and replaced it with my own “Form1.xaml”:

<Form Name=”Form1″ x:Class=”Form1″  Text=”Hello” 
    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
    xmlns=”clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms”
        >
    <Form.Controls>
        <FlowLayoutPanel>
            <FlowLayoutPanel.Controls>
                <TextBox Name=”txtName” x:Name=”txtName” />
                <Button Name=”cmdSayHello” Text=”Say Hello” Click=”Button_Click” /> 
            </FlowLayoutPanel.Controls>
        </FlowLayoutPanel>
    </Form.Controls>
</Form>

Please note that features such as code behind (partial classes), event hooks and most things in the “x” namespace work fine.

Creating XAML from an existing Winform

For even more fun and games, you can feed a running instance of a Winform into XAML Writer and get XAML source.  Sadly winforms incorporates read-only properties, so without massaging the Xml you’re not going to be able to clone a Winform using XAML serialization just yet.

The code would look something like this:

Dim loWinform As Form = Me ‘ Some Winform
Dim lsWinformXaml As String = XamlWriter.Save(loWinForm)
Dim loClonedForm As Form = XamlReader.Load(new XmlTextReader(new StringReader(xaml)))

 

See this Mike Hillberg’s object cloning article for more information.

 

So where from here?

What’s the use of it?  Well for me it proved that Xaml can be used to create any sort of object graph.  

Possible uses for this:

  • Embedding Winforms instantiation code within a WPF XAML document (something I haven’t tried)
  • Streaming Winforms form definitions from a server down to a client (effectively allowing a WebServer to render Winforms just like it renders HTML pages)
  • Providing a good interim step in creating a Winforms to WPF Converter

 

Any Comments?

If you find this topic interesting, ask questions or download a sample project, write some comments on the blog.  If I can see interest in the topic I may develop it further.


Share this post :

kick it on DotNetKicks.com

Posted in .net Framework, Code, Software Development, VB.Net, Windows Forms, Windows Presentation Foundation | Tagged: , , , , , | 2 Comments »

Visual Basic 9 for the Insane - A class with no name - Anonymous Types

Posted by anoriginalidea on December 6, 2007

image

Now we’re starting enter strange territory.  I give you a syntax that allows you to create classes “on the fly” :

Dim loClasslessSmurf = New With {.Name = “Brainy”, .AnnoyingTrait = “Whiny Voice”}

This syntax creates a “temporary” class with the properties you specify.  This is known as an “anonymous type”.  (Or a type with no name)  This is the equivalent of:

Public NotInheritable Class XXXX
  Public Name As String
  Public AnnoyingTrait As String
End Class

These classes do not have methods on them.  They are intended as useful temporary data holders for inline processing.  They were created for the LINQ language feature to allow results to be returned without having to create result container classes.

Differences between Cousins

It appears that the behaviour between VB9 and CSharp3.0 differs when creating an anonymous types.  If you create one in CSharp, the properties are read-only.  If you create them in VB9 the properties are writeable.

Posted in .net Framework, Code, Software Development, VB.Net | No Comments »

Visual Basic 9 for the Insane - Constructors for Free

Posted by anoriginalidea on December 5, 2007

image

There are some activities, such as searching for an attendant at a hardware store, watching television commercials, waiting for a TFS build server to come free or buying a bus ticket, bore me. 

Writing Constructors also bores me to tears.  I know it makes things easier for others that use your classes, but creating then just disrupts my “flow”.  In the world of mocking it’s a good idea to expose your dependencies via alternate constructors, which I do.  A new syntax may free me from this burden.

“Object Intializers” (This is an American product so in this case the “z” spelling) are another name for a feature I call “constructors for free”.

Take a boring class that represents a smurf like this:

Public Class Smurf

  Public AnnoyingTrait As String
  Public Name As String

End Class

If you want to create an instance of this class and want to set some defaults, the usual way of doing this is:

Dim loSmurf As New Smurf
loSmurf.AnnoyingTrait = “Whiny voice and Glasses”
loSmurf.Name = “Brainy”

Three lines of code!  The usual thing to do would be to create a constructor (Public Sub New), but this just moves the 3 lines of code elsewhere.  A far cooler thing to do is to use the new “Object Initializer” syntax:

Dim loSmurf As New Smurf With { .AnnoyingTrait = “Whiny voice”, .Name=”Brainy”}

Cool eh?  Additionally you can include these in array intializers so that you can create arrays with pre-intialized values:

Dim loSmurfs() = New Smurf() { _
     New Smurf With {.AnnoyingTrait = “Whiny voice”, .Name = “Brainy”}, _
     New Smurf With {.AnnoyingTrait = “Unrealistic Beard”, .Name = “Papa”}, _
     New Smurf With {.AnnoyingTrait = “Isn’t a smurf”, .Name = “Dopey”} _
     }

(Because of the “Implicit Types” feature you can also leave out the “New Smurf()” bit if you wanted to)

I pleased to report all this works fine in Compact Framework 2.0 (with VS2008).

Posted in .net Framework, Code, Software Development, VB.Net | No Comments »

Visual Basic 9 for the Insane - The rise and fall of "As" - Implicit Types

Posted by anoriginalidea on December 4, 2007

Posted in .net Framework, Code, Software Development, VB.Net | 1 Comment »