Blog

posts

WinForm DualList Component

0 Comments
By Fons Sonnemans, 01-mrt-2002

Download DualList.zip

Introduction

This article demonstrates the use of the DualList component in a Microsoft .NET WinForm application. It doesn't explain how the component was written, you can figure that out by examining the C# source code (see download).

Problem Description

In many of my applications there are dialogs in which you have two listboxes and some buttons to move (or copy) item(s) from one listbox to the other. This seems very easy to implement, but it isn't. You have to implement a lot of features:

  • Actions: Move Selected, Copy Selected, Move All, Copy All
  • DoubleClick support, inclusive (re)setting the Default button
  • Select next item
  • Enable and disable buttons
  • MultiSelect support

You don't want to program this in every form which has 2 listboxes and some move or copy buttons. This would lead to lots of (duplicate) code which is very difficult to maintain. A generic (reusable) solution is required.


Class vs. Control vs. Component

There are three possible solutions: a class, a (composite) control and a component.

Class
Within your form you create an instances of this class and initialize it with an 'action' (move or copy and selected or all), 2 listboxes and 1 button. You need an instance for each button on your form. The class handles all events of the controls (e.g. Button.Click, ListBox.DoubleClick) and executes the requested action. The solution works fine but is not user-friendly. You have to do everything from code, you can not use the designer.

Composite control
This composite control would hold the 2 listboxes and 8 buttons. One button for each action in each direction. The user (programmer) can set the properties and handle events easily using the designer. It has the disadvantage that it is not very flexible. The layout of the composite controls will need lot's of special properties which not contribute to the problem description (low cohesion).

Component
The component is a "best of both worlds" solution. You can set it's properties using the designer and doesn't need any layout properties because it doesn't contain any controls.

DualList Component

The DualList component takes care of all the features mentioned in the problem domain. You can place it on the form as a sort of "invisible control". Next you set its behavior properties: Action, Button, ListBoxFrom and ListBoxTo. Optionally you can set the DoubleClickSupport and EnableDisableSupport properties.

The DualList handles all events of the controls (e.g. Button.Click, ListBox.DoubleClick) and executes the requested action.

+DualList : Component
{Implements: IComponent, IDisposable}
 
 DualList(in container : IContainer)
 DualList()
 CopyAll() : Void
 CopySelected() : Void
 MoveAll() : Void
 MoveSelected() : Void
 Action : DualListAction
 Button : Button
 DoubleClickSupport : Boolean
 AutoDisableButton : Boolean
 ListBoxFrom : ListBox
 ListBoxTo : ListBox
 AfterAction : AfterActionHandler
 BeforeAction : BeforeActionHandler

Usage

The following steps explain how you can use the DualList component in your WinForm projects.

Step1 - Download the Zip file and extract it.
Download DualList.zip and extract it to you local harddrive. This version was compiled using the final version of Microsoft .NET Framework SDK. The C# source of the DualList component is included.

Step2 - Design the Form
Create a form, place 2 listboxes and the required buttons on the form. The example only uses an Add and Remove button. These buttons move the selected items between the listboxes. Add some items to the listboxes.

You can off course set the Sorted property of the listboxes to True.

Step3 - Add the DualList component to the Toolbox
Right-click the Toolbox and select 'Customize Toolbox...'Select the '.NET Framework Components' Tab and click the 'Browse' button.

Open the 'ReflectionITWinFormComponents.dll' in the DualList\ComponentLibrary\Bin\Debug folder. The 'DualList' is checked and will be visible in the Toolbox. Click OK.

Step4 - Add a DualList to the form and set its properties
Drag two DualList components on your form.

Set the properties for both components

Step5 - Run the application

DualList events

The DualList component has 2 events. The BeforeAction event can be used to Cancel the action or to change the moved/copied Item. The AfterAction event can be used to process your changes (e.g. write them to your database, select the moved/copied item).

private void dualListAdd_AfterAction ( object sender , DualListActionEventArgs e)
{
    listAssigned.SelectedIndex = e.Index;
}

privatevoid dualListDelete_AfterAction(objectsender, DualListActionEventArgs e)
{
    listAvailable.SelectedIndex = e.Index;
}

Conclusion

The DualList Component is an easy solution for a difficult feature. It takes care of all logic needed to move and or copy items from one ListBox to another. It demonstrates the possibilities of .NET components. A very new, powerful feature of the .NET framework.

You can off course extend the class with Drag-and-drop support. That would really complete it. I might do it myself in the near future. Check this site for updates.

Any suggestions and feedback for improving this article is most welcome. Send your suggestions and feedback to Fons.Sonnemans@reflectionit.nl

READ MORE

ASP.NET RollOver Images

0 Comments
By Fons Sonnemans, 01-jan-2002

By Inge Schepers, Fons Sonnemans (Februari 2002)

Download RollOverImageDemo.zip

Introduction

A RollOver image is an image that changes its picture when the mouse moves over it.

Example:      Move your mouse over the image!

There are many ways to implement this. One easy way of doing this is creating a helper class called 'RollOverImageManager'. This helper class does two things: add the 'onMouseOver' and 'onMouseOut' attributes to the image; add a javascript which preloads the 'MouseOver' images.


using System;
using System.Collections;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Text;

namespace RollOverImageDemo
{
    /// <summary>
    /// Utility class for an ASP.NET page that preloads images that
    /// are used for mouseovers.
    ///
    /// Be sure to notice that this code is provided as a technology sample,
    /// 'as is' and no warranties are made by the authors.
    ///
    /// For questions and comments: i.j.m.c.schepers@wxs.nl,
    ///                             Fons.Sonnemans@reflectionit.nl
    ///
    /// </summary>
    public class RollOverImageManager
    {
        private ArrayList mImages;

        public RollOverImageManager()
        {
            mImages=new ArrayList();
        }

        publicvoid AddImage(stringimageURL)
        {
            mImages.Add(imageURL);
        }

        publicvoid InitializeImage(Image control, stringimageURLMouseOver)
        {
            InitializeImage(control,imageURLMouseOver,control.ImageUrl);
        }

        publicvoid InitializeImage(Image control,
                                    stringimageURLMouseOver,
                                    stringimageURLMouseOut)
        {
            AddImage(imageURLMouseOver);

            AddAttribute(control.Attributes,"onMouseOut",imageURLMouseOut);
            AddAttribute(control.Attributes,"onMouseOver",imageURLMouseOver);

        }

        publicvoid InitializeImage(HtmlImage control, stringimageURLMouseOver)
        {
            InitializeImage(control,imageURLMouseOver,control.Src);
            }

        publicvoid InitializeImage(HtmlImage control,
                                    stringimageURLMouseOver,
                                    stringimageURLMouseOut)
        {
            AddImage(imageURLMouseOver);

            AddAttribute(control.Attributes,"onMouseOut",imageURLMouseOut);
            AddAttribute(control.Attributes,"onMouseOver",imageURLMouseOver);

        }

        publicvoid AddAttribute(AttributeCollection a,
                                 stringeventName,
                                 stringimageUrl)
        {
            try
            {
                a.Remove(eventName);
            }
            finally
            {
                a.Add(eventName,"this.src='" +imageUrl+"'");
            }
        }

        /// <summary>
        /// Preload the images
        /// </summary>
        publicvoid LoadImages(Page webPage)
        {
            // Create JavaScript
            StringBuilder buildString=new StringBuilder();
            buildString.Append("\n<SCRIPT LANGUAGE='JavaScript'>\n");
            buildString.Append("<!--\n");
            buildString.Append("var aImages = new Array();\n");
            for(int i =0; i < mImages.Count; i++)
            {
                buildString.Append("aImages[" +
                    i +"] = new Image();\n");
                buildString.Append("aImages[" +
                    i +"].src = '"+
                    mImages[i].ToString()+"';\n");
            }
            buildString.Append("//-->\n");
            buildString.Append("</script>\n");

            // Register Client Script
            if(webPage== null)
            {
                thrownew ArgumentException(
                    "The Page object is invalid.");
            }
            if(webPage.Request.Browser.JavaScript == true)
            {
                webPage.RegisterClientScriptBlock("ImageLoader",
                    buildString.ToString());
            }
        }

    }
}
The InitalizeImage() methods adds the 'onMouseOver' and 'onMouseOut' attributes to the control. The images 'onMouseOver' imageUrl is added to an ArrayList. This ArrayList is used by the LoadImages() method to generate a JavaScript which loads these images. This is done to prevent the extra load of the image the moment you move the mouse over it.

Usage

You use the RollOverImageManager in the Page_Load event of your web page. You create an instance of the class. Initialize the Image controls with the images and call the LoadImage() method.

privatevoid Page_Load(object sender, System.EventArgs e)
{
    // Create the Manager
    RollOverImageManager m =new RollOverImageManager();

    // Intialize the Image Controls
    m.InitializeImage(ImageButton1,"print2.gif");
    m.InitializeImage(Image1,"print2.gif");

    // Load the Images (generate the JavaScript)
    m.LoadImages(this);
}
WebForm1.aspx.cs

<%@ Page language="c#" Codebehind="WebForm1.aspx.cs"
AutoEventWireup="false" Inherits="RollOverImageDemo.WebForm2"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
    <HEAD>
        <metaname="GENERATOR" Content="Microsoft Visual Studio 7.0">
        <metaname="CODE_LANGUAGE" Content="C#">
    </HEAD>
    <body>
        <formid="WebForm1"method="post"runat="server">
            <asp:ImageButton id="ImageButton1"runat="server" ImageUrl="help.gif">
            </asp:ImageButton>
            <asp:Image id="Image1"runat="server" ImageUrl="help.gif">
            </asp:Image>
        </form>
    </body>
</HTML>
WebForm1.aspx

Conclusion

The RollOverImageManager is a simple helper class which lets you implement RollOver images easily. We have also experimented with an other solution. In the solution we subclassed the Image control and added an extra ImageUrlMouseOver property. This property was used to generate the OnMouseOver event. We did not use subclassing because it would lead to a lot of duplicate code unless delegation was used. Using a combination of subclassing and delegation would also take away from the simplicity of the solution, which is why we decided not to use it.

Tags: Web, ASP.NET

READ MORE

ASP.NET NumberBox Control

0 Comments
By Fons Sonnemans, 01-jan-2002

By Fons Sonnemans

Number: Download NumberBoxDemo.zip

The NumberBox control is an ASP.NET control, which lets the user only input numerical values. The base class of NumberBox class is the TextBox class. It uses JavaScript to validate the KeyPress event. An extra RegularExpresionValidator can be used to validate the control.

Special public properties:

  • AllowNegatives
  • DecimalPlaces
  • DecimalSymbol
  • Text
  • Value
  • ValidationRegularExpression

Demo

Number:     

Sample Project

NumberBox Class

using System;
using System.Web.UI;
using System.ComponentModel;
using System.Web.UI.WebControls;
using System.Text;
using System.Text.RegularExpressions;

namespace NumberBoxDemo
{
    /// <summary>
    /// Number Box ASP.NET control
    ///
    /// Created by Fons Sonnemans, Reflection IT
    ///
    /// Be sure to notice that this code is provided as a technology sample
    /// and 'as is', no warranties are made by the author.
    ///
    /// For questions and comments: Fons.Sonnemans@reflectionit.nl
    ///
    /// </summary>
    [
    ToolboxData("<{0}:NumberBox runat=server></{0}:NumberBox>"),
    DefaultProperty("DecimalPlaces")
    ]
    publicclass NumberBox : TextBox
    {

        privateintmDecimalPlaces=0;
        privatecharmDecimalSymbol='.';
        privateboolmAllowNegatives=true;

        /// <summary>
        /// Gets or sets the number of decimals for the number box.
        /// </summary>
        [
        Bindable(true),
        Category("Appearance"),
        DefaultValue(0),
        Description("Indicates the number of decimal places to display.")
        ]
        publicvirtualint DecimalPlaces
        {
            get{return mDecimalPlaces;}
            set{mDecimalPlaces=value;}
        }

        /// <summary>
        /// Gets or sets the digit grouping symbol for the number box.
        /// </summary>
        [
        Bindable(true),
        Category("Appearance"),
        DefaultValue("."),
        Description("The digit grouping symbol.")
        ]
        publicvirtualchar DecimalSymbol
        {
            get{return mDecimalSymbol;}
            set{mDecimalSymbol=value;}
        }

        /// <summary>
        /// Gets or sets wheter negative numbers are allowed in the number box.
        /// </summary>
        [
        Bindable(true),
        Category("Appearance"),
        DefaultValue(true),
        Description("True when negative values are allowed")
        ]
        publicvirtualbool AllowNegatives
        {
            get{return mAllowNegatives;}
            set{mAllowNegatives=value;}
        }

        /// <summary>
        /// Gets or sets the value of the number box.
        /// </summary>
        publicvirtualdouble Value
        {
            get
            {
                try
                {
                    return ParseStringToDouble(this.Text);
                }
                catch(FormatException e)
                {
                    thrownew
                    InvalidOperationException("NumberBox does nog contain a valid Number.");
                }
                catch(Exception e)
                {
                    throw e;
                }

            }
            set
            {
                if((value < 0)&!AllowNegatives)
                    thrownew
                    ArgumentOutOfRangeException("
                    Only positivevaluesareallowedforthis NumberBox");

                //base.Text = value.ToString(this.Format);
                base.Text =value.ToString(GetFormat()).Replace(".", DecimalSymbol.ToString());
            }
        }

        /// <summary>
        /// Gets or sets the text content of the number box.
        /// </summary>
        overridepublicstring Text
        {
            get
            {
                returnbase.Text;
            }
            set
            {
                try{
                    this.Value = ParseStringToDouble(value);
                }catch (FormatException e) {
                    base.Text =value;
                }
                catch(Exception e)
                {
                    throw e;
                }
            }
        }


        /// <summary>
        ///    Add a JavaScript to the Page and call it from the onKeyPress event
        /// </summary>
        /// <param name="e"></param>
        overrideprotectedvoid OnPreRender(EventArgs e) {

            if(this.Page.Request.Browser.JavaScript ==true)
            {
                // Build JavaScript        
                StringBuilder s =new StringBuilder();
                s.Append("\n<script type='text/javascript' language='JavaScript'>\n");
                s.Append("<!--\n");
                s.Append("    function NumberBoxKeyPress(event, dp, dc, n) {\n");
                s.Append("         var myString = new String(event.srcElement.value);\n");
                s.Append("         var pntPos = myString.indexOf(String.fromCharCode(dc));\n");
                s.Append("         var keyChar = window.event.keyCode;\n");
                s.Append("     if ((keyChar < 48) || (keyChar > 57)) {\n");
                s.Append("         if (keyChar == dc) {\n");
                s.Append("             if ((pntPos != -1) || (dp < 1)) {\n");
                s.Append("                 return false;\n");
                s.Append("             }\n");
                s.Append("         } else \n");
                s.Append("if (((keyChar == 45) && (!n || myString.length != 0)) || (keyChar != 45)) \n");
                s.Append("             return false;\n");
                s.Append("     }\n");
                s.Append("     return true;\n");
                s.Append("    }\n");
                s.Append("// -->\n");
                s.Append("</script>\n");

                // Add the Script to the Page
                this.Page.RegisterClientScriptBlock("NumberBoxKeyPress", s.ToString());

                // Add KeyPress Event
                try{
                    this.Attributes.Remove("onKeyPress");
                }finally {
                    this.Attributes.Add("onKeyPress","return NumberBoxKeyPress(event, "
                                        + DecimalPlaces.ToString() +", "
                                        +((int)DecimalSymbol).ToString()+", "
                                        + AllowNegatives.ToString().ToLower() +")");
                }
            }
        }

        /// <summary>
        /// Returns the RegularExpression string which can be used for validating
        /// using a RegularExpressionValidator.
        /// </summary>
        virtualpublicstring ValidationRegularExpression
        {
            get
            {
                StringBuilder regexp= new StringBuilder();

                if(AllowNegatives)
                    regexp.Append("([-]|[0-9])");

                regexp.Append("[0-9]*");

                if(DecimalPlaces > 0)
                {
                    regexp.Append("([");
                    regexp.Append(DecimalSymbol);
                    regexp.Append("]|[0-9]){0,1}[0-9]{0,");
                    regexp.Append(DecimalPlaces.ToString());
                    regexp.Append("}$");
                }

                returnregexp.ToString();
            }
        }

        /// <summary>
        /// Parse a String to a Double
        /// </summary>
        /// <param name="s">string to be parsed to a double</param>
        /// <returns>double value</returns>
        virtualprotecteddouble ParseStringToDouble(string s)
        {
            s = s.Replace(DecimalSymbol.ToString(),".");
            returndouble.Parse(s);
        }

        /// <summary>
        /// Returns the FormatString used to display the value in the number box
        /// </summary>
        /// <returns>Format string</returns>
        virtualprotectedstring GetFormat()
        {
            StringBuilder f =new StringBuilder();
            f.Append("0");
            if(DecimalPlaces > 0)
            {
                f.Append(".");
                f.Append('0', DecimalPlaces);
            }

            return f.ToString();
        }

    }
}

Validation

You can use a normal RegularExpressionValidator control to validate the NumberBox. Invalid nummers are then rejected without causing a roundtrip to the server. Invalid numbers can still be entered using the clipboard Paste option. I don't know how to avoid this.

You can use the NumberBox.ValidationRegularExpression property to set the RegularExpressionValidator.ValidationRegularExpression property to the correct RegularExpression.

        private voidPage_Load(objectsender, System.EventArgs e)
        { 
            if(!IsPostBack)
            {
                valOne.ValidationExpression=numOne.ValidationRegularExpression;
                valTwo.ValidationExpression=numTwo.ValidationRegularExpression;
            }
        }


 

WebForm1.aspx

<%@ Page language="c#" Codebehind="WebForm1.aspx.cs" AutoEventWireup="false"
Inherits="NumberBoxDemo.WebForm1"%>
<%@ Register TagPrefix="rit" Namespace="NumberBoxDemo" Assembly="NumberBoxDemo"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
    <HEAD>
        <metacontent="Microsoft Visual Studio 7.0"name="GENERATOR">
        <metacontent="C#"name="CODE_LANGUAGE">
        <metacontent="JavaScript (ECMAScript)"name="vs_defaultClientScript">
        <metacontent="http://schemas.microsoft.com/intellisense/ie5"name="vs_targetSchema">
    </HEAD>
    <body style="FONT-FAMILY: Verdana">
        <formid="Form1"method="post"runat="server">
            <H2>
                NumberBox Demo Page
            </H2>
            <P>
                <TABLE cellSpacing="1"cellPadding="1"width="100%"border="0">
                    <TR>
                        <TD style="WIDTH: 300px">
                            Numberbox1:
                        </TD>
                        <TD>
                            <rit:numberboxid="numOne"runat="server" DecimalSymbol=","
                             MaxLength="8" DecimalPlaces="2">
                                32,46
                            </rit:numberbox>
                        </TD>
                        <TD>
                            <asp:regularexpressionvalidatorid="valOne"runat="server"
                            ControlToValidate="numOne">
                            Invalid Number</asp:regularexpressionvalidator>
                        </TD>
                    </TR>
                    <TR>
                        <TD style="WIDTH: 300px"vAlign="top">
                            <FONT size="1">(Double, 2decimals,','&nbsp;DecimalSymbol)</FONT>
                        </TD>
                        <TD>
                        </TD>
                        <TD>
                        </TD>
                    </TR>
                    <TR>
                        <TD style="WIDTH: 300px">
                            &nbsp;
                        </TD>
                        <TD>
                        </TD>
                        <TD>
                        </TD>
                    </TR>
                    <TR>
                        <TD style="WIDTH: 300px">
                            Numberbox2:
                        </TD>
                        <TD>
                            <rit:numberboxid="numTwo"runat="server" MaxLength="8"
                             DecimalSymbol="." AllowNegatives="False">
                            </rit:numberbox>
                        </TD>
                        <TD>
                            <asp:RegularExpressionValidator id="valTwo"runat="server"
                            ControlToValidate="numTwo">
                            Invalid Number</asp:RegularExpressionValidator>
                        </TD>
                    </TR>
                    <TR>
                        <TD style="WIDTH: 300px"vAlign="top">
                            <FONT size="1">(Poisitive Integer)</FONT>
                        </TD>
                        <TD>
                        </TD>
                        <TD>
                        </TD>
                    </TR>
                    <TR>
                        <TD style="WIDTH: 300px">
                        </TD>
                        <TD>
                        </TD>
                        <TD>
                        </TD>
                    </TR>
                </TABLE>
            </P>
            <P>
            </P>
            <P>
                <asp:buttonid="btnSubmit"runat="server" Text="Submit"></asp:button>
            </P>
            <P>
                <asp:PlaceHolder id="PlaceHolder1"runat="server"></asp:PlaceHolder>
            </P>
            <P>
            </P>
        </form>
    </body>
</HTML>

WebForm1.aspx.cs

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

namespace NumberBoxDemo
{
    /// <summary>
    /// Summary description for WebForm1.
    /// </summary>
    public class WebForm1: System.Web.UI.Page
    {
        protected NumberBoxDemo.NumberBox numOne;
        protected System.Web.UI.WebControls.RegularExpressionValidator valOne;
        protected NumberBoxDemo.NumberBox numTwo;
        protected System.Web.UI.WebControls.RegularExpressionValidator valTwo;
        protected System.Web.UI.WebControls.PlaceHolder PlaceHolder1;
        protected System.Web.UI.WebControls.Button btnSubmit;

        public WebForm1()
        {
            Page.Init +=new System.EventHandler(Page_Init);
        }

        privatevoid Page_Load(objectsender, System.EventArgs e)
        {
            // Put user code to initialize the page here

            if(!IsPostBack)
            {
                valOne.ValidationExpression =numOne.ValidationRegularExpression;
                valTwo.ValidationExpression =numTwo.ValidationRegularExpression;
            }
        }

        privatevoid Page_Init(objectsender, EventArgs e)
        {
            //
            // CODEGEN: This call is required by the ASP.NET Web Form Designer.
            //
            InitializeComponent();
        }

        #region Web Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        privatevoid InitializeComponent()
        {
            this.btnSubmit.Click += new System.EventHandler(this.btnSubmit_Click);
            this.Load +=new System.EventHandler(this.Page_Load);

        }
        #endregion

        privatevoidbtnSubmit_Click(object sender, System.EventArgs e)
        {
            numTwo.Value = new Random().NextDouble()*1000;

            this.PlaceHolder1.Controls.Clear();
            this.PlaceHolder1.Controls.Add(new LiteralControl(
             "Numberbox1.Value = "
             +numOne.Value.ToString()+"<br>"));
            this.PlaceHolder1.Controls.Add(new LiteralControl(
             "Numberbox1.Text = "
             +numOne.Text +"<br>"));
            this.PlaceHolder1.Controls.Add(new LiteralControl(
             "Numberbox1.ValidationRegularExpression = "
             +numOne.ValidationRegularExpression +"<br>"));
        }

    }
}

Any suggestions and feedback for improving this article is most welcome. Send your suggestions and feedback to Fons.Sonnemans@reflectionit.nl


Tags: Web, ASP.NET

READ MORE

Create Property Macro for VS.NET 2002 & 2003

0 Comments
By Fons Sonnemans, 01-jan-2002

By Fons Sonnemans

Download LocalizedText.zip

The CreateProperty macro is simple Visual Studio.Net (Final) macro which can be used to generate the code for a 'private Field and a public Property Get/Set method'.

Example:

1. Unzip the ReflectionIT macro.zip
 
2.  Start Visual Studio.Net.
 
3.  Open the Macro Explorer (Alt-F8)
 
4.  Right-click on the Macros, and select 'Load Macro Project...'
 
 
5.  Select the (unzipped) 'ReflectionIT.vsmacros' file and select 'Open'. 
6. Open a CodeWindow and add a public, private or protected field.

Example:

7. Select the text you just have entered and run the 'CreateProperty' macro

8. Your text is automatically replaced by a private field and an public property

Any suggestions and feedback for improving this article is most welcome. Send your suggestions and feedback to Fons.Sonnemans@reflectionit.nl


READ MORE

Stock Sample Web Service

0 Comments
By Fons Sonnemans, 01-jan-2002

By Fons Sonnemans

Download StockServices.zip

The Stock Sample Web Service uses the Html2Xml service to retrieve the Finance page of Yahoo. It then searches the Xml, using an XPath expression, for the current value and returns it. Hopefully Yahoo never changes their HTML structure.

VB.NET Source Code

Imports System.Web.Services
Imports System.Xml
Imports Html2XmlService <_o3a_p> 

Namespace ReflectionIT.WebServices.StockServices <_o3a_p />

<WebService(Namespace:="http://www.reflectionit.nl/webservices/", Description:="StockServices created by Reflection IT.")> _
Public Class StockServices <_o3a_p> 

Inherits System.Web.Services.WebService <_o3a_p> 

Public Sub New()
   MyBase.New()
   'This call is required by the Web Services Designer.
   InitializeComponent()
   'Add your own initialization code after the InitializeComponent() call 
End Sub <_o3a_p />

'Required by the Web Services Designer
Private components As System.ComponentModel.Container <_o3a_p> 

'NOTE: The following procedure is required by the Web Services Designer
'It can be modified using the Web Services Designer.
'Do not modify it using the code editor. <_o3a_p />

<System.Diagnostics.DebuggerStepThrough()>_
Private Sub InitializeComponent()
   components = New System.ComponentModel.Container()
End Sub <_o3a_p />

Protected Overloads Overrides Sub Dispose(ByVal disposing AsBoolean)
   'CODEGEN: This procedure is required by the Web Services Designer
  
'Do not modify it using the code editor.
End Sub <_o3a_p />

<WebMethod(Description:="Get the Yahoo stock quote.")> _
Public Function GetStockQuote(ByVal symbol AsString) AsDouble <_o3a_p />

   ' Build the Url
   Dim url AsString = "http://finance.yahoo.com/q?s=" + symbol + "&d=v1" <_o3a_p />

   ' Get the XmlDocument using the Html2Xml WebServices
  
Dim xml As XmlDocument = New XmlDocument()
  
xml.LoadXml(New Html2XmlService.Html2XmlServices().Url2XmlString(url)) <_o3a_p />

   ' Find the Nodes using a XPath expression
   Dim l As XmlNodeList = xml.SelectNodes("/html/body/center/table/tr/td/table/tr/td/b") <_o3a_p />

   ' Validate and return value
   If (l.Count <> 2) Then
      Throw New Exception("symbol not found.")
   End If
   Return Double.Parse(l(1).InnerXml) <_o3a_p />

End If <_o3a_p />

End Function <_o3a_p />

End Class <_o3a_p />

End Namespace

Any suggestions and feedback for improving this article is most welcome. Send your suggestions and feedback to Fons.Sonnemans@reflectionit.nl


Tags: Web, XML, ASP.NET

READ MORE

Visual Basic 6.0 Procedure Sort Add-In

0 Comments
By Fons Sonnemans, 01-jan-2002

By Fons Sonnemans

Download ProcedureSort.zip

The Procedures Sort Add-In is a great add-in for those who like well-organized code. You can use it to sort your procedures in the active CodeWindow alphabetically. It preserve all you procedure attributes, which you normally loose when you do it manually. Event-handlers and Interface-implementations will be placed at the end of your code.


Install & Usage:

1. Unzip the ProcedureSort.zip
 
2.  Register the ProcedureSort.dll you just unzipped using Regsvr32.exe.
 
3.  Start Visual Basic 6.0.
 
4.  Select menu 'Add-Ins', 'Add-in Manager...'.
 
 
5.  You see now an extra button in your Standard toolbar.

6. Open a CodeWindow. 

Example:

7. Click on the new 'Sort Procedures' toolbar button. All procedures will be sorted alphabetically. 

8. You can set the following options (Menu 'Add-Ins', 'Procedure Sort Options...'):
- Show Constructor and Destructor at top 
- Case Sensitive
- Number of empty lines between procedures


READ MORE

MS Outlook 2000 and MS Agent

0 Comments
By Fons Sonnemans, 01-jan-2002

By Fons Sonnemans

Download OutlookAgent.zip

You can use Microsoft Agent in Outlook 2000 to read your incoming mail.

Requirements:

  • Microsoft Outlook 2000
  • Microsoft Agent
  • Microsoft Agent Characters
  • Lernout & Hauspie TruVoice Text-to-Speech (TTS) Engine

For more information about installing MS Agent software have a look at: http://www.msagentring.org/setup.htm


10 Steps:

1.Install the requirements.
 
2. Download this Zipfile and Unzip the CAgent.cls file to a folder (c:\temp).
 
3. Select in 'Outlook 2000' the menu option 'Tools', 'Macro', 'Visual Basic Editor???' or press 'Alt-F11'.
 
4. Select in the 'Microsoft Visual Basic' editor menu 'Tools', 'References???'.
  
 
5. Check the checkboxes in front off 'Microsoft Agent Control 2.0' and 'Microsoft Scripting Runtime'.
 
6. Open the 'File' menu and select the option 'Import File???'.

 
7.Select the CAgent.cls file and select Open.

 
The project explorer should look like:

 
8.Add the following code to the (existing) ThisOutlookSession.

 
9. Save the project by clicking the 'Save' button in the toolbar.

 
10.Close de 'Microsoft Visual Basic' Editor.
MS Agent will now read your incoming e-mails. You can easily test it by sending a mail to yourself.


Tags: VB

READ MORE

Html2Xml Web Service

0 Comments
By Fons Sonnemans, 01-jan-2002

By Fons Sonnemans

Introduction

As you probably know, HTML is a "markup language" that uses "tags" (such as and <br> and <p>) to mark up text for formatting. The Extensible Markup Language (XML) is the universal format for structured documents and data on the Web.

Both HTML and XML use <, >, and & to create element and attribute structures. While HTML browsers accept or ignore mangled markup language, XML parsers and applications built on those parsers are less forgiving

The Html2Xml webservice takes an Html text and converts it into an Xml text. Some corrections are done to the Html to make it well-formed Xml.

You can use this webservice to screen scrape a web page and convert it to Xml. The Xml can then be used for further processing.

The Html2Xml is also registered in the UDDI registry.


Operations

The following operations are supported. For a formal definition, please review the Service Description.

  • HtmlString2XmlNode
    Public: Convert the Html string to an XmlNode.
  • HtmlString2XmlString
    Public: Convert the Html string to an Xml string.
  • Url2XmlNode
    Public: Convert the Html page with the given Url to an XmlNode.
  • Url2XmlString
    Public: Convert the Html page with the given Url to an Xml string.
  • VersionInfo
    Public: Returns the web service name, current version, date and copyright information.
  • ReportStatistics
    Private: Return usage statistics, this operation requires a Key.

Buy the Hmtl2Xml Library

Given the success of the Html2Xml on the web, Reflection IT released the 'Html2Xml Library' product. More info...

Corrections

The Html2Xml webservice corrects the markup so that it matches the observed rendering in popular browsers from Netscape and Microsoft as much as possible. Here are just a few examples of how Html2Xml perfects your HTML for you:

Match the case of the start and end tags
The case of a start and end tags must match. Html2Xml writes all tags in lower case.

HTML Corrected XML
<P>here is a paragraph with a <b>bold</B> word</p>  <p>here is a paragraph with a <b>bold</b> word</p> 

End tags in the wrong order are corrected:
XML does not allow start and end tags to overlap, but enforces a strict hierarchy within the document. Html2Xml corrects this as much as possible.

HTML Corrected XML

<table>
   <tr>
      <td>
          text
       </tr>
   </td>
</table>

<table>
   <tr>
      <td>
          text
       </td>
   </tr>
</table>

Non-empty elements are closed
All elements must be closed, explicitly or implicitly. Many people used the <p> tag to separate paragraphs. The <p> tag is designed to mark the beginning and end of a paragraph. That makes it a "non-empty" tag since it contains the paragraph text. Html2Xml add the end tag to all non-empty tags.

Affected Elements: <basefont>, <body>, <colgroup>, <dd>, <dt>, <head>, <html>, <li>, <p>, <tbody>/<thead>/<tfoot>, <th>/<td>, <tr>.

HTML Corrected XML

<ul>
  <li>
    Bullet 1
  <li>
    Bullet 2
</ul>

<ul>
  <li>
    Bullet 1
  </li>
  <li>
    Bullet 2
  </li>
</ul>

Empty elements are terminated
While end tags may be optional with certain HTML elements, all elements in XML must have an end tag. a <br> tag is "empty" because it never contains anything. Other tags like this are <hr> and <img src="valid.gif"> Html2Xml terminates them by placing a forward slash (/) before the end bracket.

Affected Elements: <area>, <base>, <br>, <col>, <frame>, <hr>, <img>, <input>, <isindex>, <link>, <meta>, <option>, <param>.

HTML Corrected XML

text
<br>
text 

text
<br />
text

Missing quotes around attribute values are added
All attribute values must be quoted, whether or not they contain spaces. Html2Xml inserts quotation marks around all attribute values for you.

HTML Corrected XML
<img src=example.gif width=40 height=30> <img src='example.gif' width='40' height='30' />

Duplicate attributes are removed
An attribute may only be used once within a start tag. Html2Xml removes duplicate attributes for you.

HTML Corrected XML
<img src='example.gif' width='30' width='40' height='30' /> <img src='example.gif' width='30' height='30' />

Minimized attributes (used without a value) get a 'dummy' value
An attribute must have a value. Html2Xml gives attributes that have no values (e.g. nowrap, selected) a 'dummy' value.

HTML Corrected XML
<td align='center' nowrap width='30'> <td align='center' nowrap='value' width='30'>

Script Blocks containing unparseable characters are enclosed in a CDATA section.
Script blocks in HTML can contain unparseable characters, namely < and &. These must be escaped in well-formed HTML by enclosing the script block in a CDATA section.

HTML Corrected XML
<SCRIPT>
// checks a number against 5
function checkFive(n) {
    return n < 5;
}
</SCRIPT>
<SCRIPT><![CDATA[
// checks a number against 5
function checkFive(n) {
    return n < 5;
}
]]></SCRIPT>

Convert built-in characters
You cannot use the characters <, >, or & within the text of your documents. Html2Xml converts them to the Xml built-in character entities. The following characters are converted:

  • &lt; ??? (<)
  • &gt; ??? (>)
  • &amp; ??? (&)
  • &qout; ??? (")
  • &apos;- (')

Nonbreaking spaces (&nbsp;) are converted to &#160;

Development

The Html2Xml webservice is developed using:

  • Microsoft.NET framework 1.1
  • Microsoft Visual Studio.NET 2003
  • C#

Sample 

The Stock Sample Web Service  uses the Html2Xml service to retrieve the Finance page of Yahoo. It then searches the Xml, using an XPath expression, for the current value and returns it.

For more information see: Stock Sample Web Service

Conclusion

The Html2Xml webservice is an easy to use, powerful solution to convert Html to Xml.

Disclaimer

Reflection IT makes these WebServices available for free use without any sort of guarantees or promises of proper operation. Reflection IT cannot guarantee support of any kind to fix bugs or effect modifications based on feedback provided by the users. All that can be said is that these WebServices are being used in The Netherlands and viewers are free to use them.

Reflection IT will in no way be responsible for problems arising out of the use of the WebServices. Using them is at your own risk.



Tags: Web, XML, ASP.NET

READ MORE

All postings/content on this blog are provided "AS IS" with no warranties, and confer no rights. All entries in this blog are my opinion and don't necessarily reflect the opinion of my employer or sponsors. The content on this site is licensed under a Creative Commons Attribution By license.