Beware of 3rd Party RAD controls


Recently I have been involved in a discussion about 3’rd party rapid application development tools. The users wanted to know about Telerik controls.

Telerik are very new to the Windows Forms game as they have always been web giants. For a recent application, I needed a grid that displays progress bars/department progress as an order goes through various departments. Only problem is with all the main vendors they have heavily modified their grids to cater for 10 000 different situations. The net result, is that you have 10 000 options to learn, to fully utilise their grid. Personally I found that the DevExpess grid for instance, is optimised for databinding, and does not have an unbound mode (after a month of fiddling about with it). For all the others I needed to owner draw the progress bars, which I may as well have done with the standard datagrid view. I have now done this, and optimsed it though, getting rid of the flicker when painting.
The feature I do miss is grouping, and this is what most people that buy RAD components go for, i.e. getting their app to look like Outlook. I will be modifying this grid and adding a Linq data source. All in all, it will take me less time to do this, than learn third party vendor solutions, and improve my development skills. You automatically, in fact exponentially raise the complexity level when you use third party suites, when a lot of the time, not being lazy and working a little harder results in attaining what you wanted without the huge complexity overhead.

2 years down the line, you have to maintain the application (I want to move to WPF), you then need developers that are trained in whatever suite you used and that really does add to the costs. The only third party thing I will purchase will be a calendar/scheduler because I really haven’t time to update the open source ones and I need something that looks good.
You can say what you want about Krypton, but this I have found to be highly customisable with things like button specs. It is far, far, far more flexible than some of the main vendors, and I have tried them all.

One of the main complaints I receive from customers, is when using solutions like RedPraire. The main complaint is, that you are tied into their specific implementation for your business, i.e. you work around the system and not the other way around. This is no different with software from 3rd party vendors. Your are tied to their specific implementation of for example how a datagrid should work. Try 2 different vendors and get 2 completely different grids and abstractions. Just like windows forms the drag and drop experience is quick (dragging components onto the form), then the real challenge begins in learning the various abstractions.

Use third party components, if you have a substantial budget, and have 4-5 years programming experience. Without that, you will never fully utilise what’s on offer, and never know how .NET really works, because you are shielded from using delegates and interfaces.

Linq to SQL Compact Edition (CE)


I got asked about doing this recently, and needed somewhere to point the individual to.

Presently, unfortunately, Linq to SQL Compact Edition is unsupported. Luckily though, it is quite easy to still perform Linq queries against SQL compact using the command line utility SqlMetal. SQL Compact Edition is very handy for single user applications or demos where you want to retain a very small application imprint, but not lose functionality. All that is required is that you have the object relational mapping (ORM) file that contains the Linq to SQL classes. This in Visual Studio is the .dbml file that is generated when you elect LinqToSQLClasses in the data menu.

Open up the Visual Studio command prompt by going to

You should have the following;

C:\Program Files\Microsoft Visual Studio 9.0\VC>

Enter ‘SqlMetal’ in the command prompt and take time to explore all the options available to you.

I simply want to create a .dbml file from my database which I have in my c:\ drive. You will want to point this to wherever your .sdf file is.

Enter the following path into the Visual Studio command prompt

SqlMetal /dbml:c:\Users\MyName\Documents\Northwind.dbml "C:\Users\MyName\Documents\Visual Studio 2008\Projects\Windows Forms\Code\Northwind\Northwind Database\Northwind.sdf"

Where the above is the format; SqlMetal /dbml:northwind.dbml northwind.sdf

Note that in vista you must specify the path through the ‘Users folder’. Failure to do this will result in a file access error.

As you can see my .dbml file was copied to my documents folder. I then copied this into my project. .To access the file I reference it in the constructor of the form thus;

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        NorthwindDataContext northwindDataContext;

        public Form1()
        {
            InitializeComponent();

            this.northwindDataContext = new NorthwindDataContext(Properties.Settings.Default.NorthwindConnectionString);
        }
    }
}

The Death of Windows Forms?


I have been engineering software for about 4 years now. For the most part I have used Windows Forms and ASP.NET (the latter being my focus hitherto).

Presently, I have a little sideline project, that may or may not be remunerative. This ‘sideline’ will be a smart client. The principal requirements for this project are two fold.

  1. A Microsoft Outlook type interface, with a grid control that has grouping.
  2. A grid control that is similar to uTorrent, Free Download Manager or FlashGet. This grid will have an array or progress bars.

Because this project, which I’ll code name “Chronicle” is not commissioned, its is best met with free tools. At present it is in three incarnations.

  1. Using free components from http://www.componentfactory.com/. I have used just the free toolkit from here
  2. Using the exceptionally good components from Devexpress
  3. Using Windows Presentation Foundation

So far the need for the project to be free has ruled out Devexpress components because they are

  1. Very expensive
  2. Add additional layers of complexity to the project. Just try to get you head around the Xtragrid, their version of the data grid view. This is not a pleasant experience, and comes at the expense of a few months to master.

The two left, are the Windows forms application with Krypton, or WPF.

I was asked this question in for forum a while ago;

What drives change in your organisation? Technology or Business requirement?

I have since struggled to answer it. Business requirement tells me that winforms is the way to go, but WPF makes things so much easier. Trying to embed controls like progress bars into data grid views requires some tricky code.

To get a faithful Outlook UI in winforms, there is the Joe Stegman sample titled Building Outlook UI in 100 lines of code with Winforms (link to the video on channel 9).

This is probably the canonical example for doing this type of thing in winforms. Only problem is that there is no grouping in the datagrid, that has been heavily modified. In WPF you just set a few properties to a Listview control.

To get a faithful Outlook UI in WPF, there is this example. Both examples lack the WOW and exact finish that Devexpress or Infragistics components have. But they teach you the principles, you can iron out your business logic, then either be creative or purchase presentation layer components.

In WPF you can add any control into any control, a huge obstacle to my project in windows forms.

In WPF to enable spell checking you do this;

<TextBox SpellCheck.IsEnabled=”True” />

In windows forms you either go with Netspell (4 years old) or this, which does not work on my PC because I’m using office 12. More tweaks required there then.

I put this question to some of the finest minds around here.

Calling another forms method/function


Frequently when writing winforms applications, one needs to call a method/function in another form. This is very handy for instance, if you want to refresh the other form after changing values in a database.

After trying to solve this using delegates, I came across this eloquent solution.

Create two Winforms, F1 and F2 with a button in each.

In Form 1

using System;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        public void MyMessage()
        {
            MessageBox.Show("Hello from Form 1");
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Form2 form2 = new Form2(this);
            form2.ShowDialog(this);
        }
    }
}

In Form 2

using System;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form2 : Form
    {
        Form1 form1;

        public Form2(Form1 form1)
        {
            InitializeComponent();
            this.form1 = form1;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            this.form1.MyMessage();
        }
    }
}

 

The instance of form 1 is passed to the second form using the this keyword. Ultimately what is passed is just a reference (pointer) to the form object.

User Control Closing Event


It is a common requirement when using User Controls to detect that the Parent Form or main form is closing.

Presently, I am working on a distributed smart client application that is full of user controls. Most, if not all of these user controls will be getting data by calling a Windows Communication Foundation service (A good tutorial on WCF is available in an earlier blog post here).

When you instantiate a Service Reference client object, it is imperative that you call client.Close() to free up any resources when the control is closed. As there is no FormClosing event in a winforms UserControl, you will need to override the ParentForm.FormClosing event. In this example I have a windows form with a user control on it. When you close the form the event in the user control is raised.

Note: Visual basic example is below

C#

using System.Windows.Forms;

 

namespace UserControlClosingEvent

{

    public partial class UserControl1 : UserControl

    {

        public UserControl1()

        {

            InitializeComponent();

        }

 

        protected override void OnCreateControl()

        {

            base.OnCreateControl();

            this.ParentForm.FormClosing += new FormClosingEventHandler(ParentForm_FormClosing);

        }

 

        void ParentForm_FormClosing(object sender, FormClosingEventArgs e)

        {

            if (MessageBox.Show("Would you like to close the parent form?", "Close parent form?",

                MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)

            {

                e.Cancel = true;

            }

        }

    }

}

 

Visual Basic

Public Class UserControl1

 

    Protected Overloads Overrides Sub OnCreateControl()

        MyBase.OnCreateControl()

        AddHandler Me.ParentForm.FormClosing, AddressOf ParentForm_FormClosing

    End Sub

 

    Private Sub ParentForm_FormClosing(ByVal sender As Object, ByVal e As FormClosingEventArgs)

        If MessageBox.Show("Would you like to close the parent form?", "Close parent form?", _

                           MessageBoxButtons.YesNo, MessageBoxIcon.Question) = DialogResult.No Then

            e.Cancel = True

        End If

    End Sub

 

 

End Class

You can then call the client.Close() (or whatever action you desire) instead of MessageBox.Show() in ParentForm_FormClosing event

Progress Bar Delegate


When I wrote my first commercial application – a program that split XML files – I first created a class called SplitXML that split the file, but I needed to update a Progress Bar control with how much of the file had been split on the form that instantiated the SplitXML class. The following is a generic example of how you achieve this using delegates.

Note: This tutorial is available in both C# and Visual Basic

First create a DoWork Class

Visual Basic

Public Delegate Sub ProgressBarHandler(ByVal min As Integer, ByVal max As Integer, ByVal value As Integer)

 

Public Class DoWork

 

    Public Event ReportProgress As ProgressBarHandler

 

 

    Public Sub DoTheWork()

 

        Dim min As Integer = 0

        Dim max As Integer = 10

 

        For value As Integer = 0 To max – 1

 

            ‘ Simulates a long running process like splitting a file,

            ‘ or getting data from a web service call, by stopping for

            ‘ 1 second (1000 milliseconds) in the loop

 

            RaiseEvent ReportProgress(min, max, value)

            System.Threading.Thread.Sleep(1000)

        Next

 

    End Sub

End Class

C#

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace ProgressBarDelegate

{

    public delegate void ProgressBarHandler(int min, int max, int value);

 

    public class DoWork

    {

        public event ProgressBarHandler ReportProgress;

 

        public void DoTheWork()

        {

            int min = 0;

            int max = 10;

 

            for (int value = 0; value < max; value++)

            {

                // Simulates a long running process like splitting a file,

                // or getting data from a web service call, by stopping for

                // 1 second (1000 milliseconds) in the loop

 

                ReportProgress(min, max, value);

                System.Threading.Thread.Sleep(1000);

 

            }

        }

 

    }

}

In the MainForm drag a button and a progress bar on the form

Form1

Click the button to add an event handler, and add the following code

Visual Basic

Public Class Form1

 

    Private Sub button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles button1.Click

        Dim doWork As New DoWork()

        AddHandler doWork.ReportProgress, AddressOf doWork_ProgressBarProgress

        doWork.DoTheWork()

    End Sub

 

    Private Sub doWork_ProgressBarProgress(ByVal min As Integer, ByVal max As Integer, ByVal value As Integer)

        progressBar1.Minimum = min

        progressBar1.Maximum = max

        progressBar1.Value = value + 1

 

    End Sub

End Class

C#

using System;

using System.Windows.Forms;

 

namespace ProgressBarDelegate

{

    public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

        }

 

        private void button1_Click(object sender, EventArgs e)

        {

            DoWork doWork = new DoWork();

            doWork.ReportProgress += new ProgressBarHandler(doWork_ProgressBarProgress);

            doWork.DoTheWork();

        }

 

        void doWork_ProgressBarProgress(int min, int max, int value)

        {

            progressBar1.Minimum = min;

            progressBar1.Maximum = max;

            progressBar1.Value = value + 1;

 

        }

    }

}

This is quite a common requirement when programming i.e. letting an Form know the progress of a method in an instantiated class. Subsequent need of this functionality has resulted in my implementing this the correct "Windows" way:

Sometimes you need to pass more than one value or reference in the delegate. As a best practice the signature of a delegate is always;

Visual Basic

Public Delegate Sub SomeHandler(ByVal sender As Object, ByVal e As SomeEventArgs)

 

C#

 public delegate void SomeHandler(object sender, SomeEventArgs e);

This means that if you need to pass more than one value (like the first example), this best practice is not adhered to. There is an eloquent way to do this though. I have two classes in the example.

First create a custom EventArgs class that takes two values (you can modify this to take any number of parameters your require)

Visual Basic

   Public Class ProgressBarProgressEventArgs

        Inherits System.EventArgs

        Private m_maximum As Integer

        Private m_stage As Integer

 

        Public Property Maximum() As Integer

            Get

                Return m_maximum

            End Get

            Set(ByVal value As Integer)

                m_maximum = value

            End Set

        End Property

        Public Property Stage() As Integer

            Get

                Return m_stage

            End Get

            Set(ByVal value As Integer)

                m_stage = value

            End Set

        End Property

    End Class

 

C#

 public class ProgressBarProgressEventArgs : System.EventArgs

    {

        private int maximum;

        private int stage;

 

        public int Maximum

        {

            get { return maximum; }

            set { maximum = value; }

        }

        public int Stage

        {

            get { return stage; }

            set { stage = value; }

        }     

    }

Secondly create the DoWork class where the actual works takes place. This could be the splitting of an XML file, a production line in a factory or whatever.

Visual Basic

    Public Delegate Sub ProgressBarHandler(ByVal sender As Object, ByVal e As ProgressBarProgressEventArgs)

 

    Public Class DoWork

        Public Event ReportProgress As ProgressBarHandler

 

        Public Sub DoTheWork()

            For stage As Integer = 1 To 5

 

                OnStageCompleted(stage, 5)

                System.Threading.Thread.Sleep(1000)

            Next

        End Sub

 

        Private Sub OnStageCompleted(ByVal stage As Integer, ByVal max As Integer)

            Dim args As New ProgressBarProgressEventArgs()

            args.Stage = stage

            args.Maximum = max

        RaiseEvent ReportProgress(Me, args)

        End Sub

    End Class

 

C#

 public delegate void ProgressBarHandler(object sender, ProgressBarProgressEventArgs e);

 

    public class DoWork

    {

        public event ProgressBarHandler ReportProgress;

 

        public void DoTheWork()

        {

            for (int stage = 1; stage < 6; stage++)

            {

 

                OnStageCompleted(stage, 5);

                System.Threading.Thread.Sleep(1000);

            }

        }

 

        private void OnStageCompleted(int stage, int max)

        {

            ProgressBarProgressEventArgs args = new ProgressBarProgressEventArgs();

            args.Stage = stage;

            args.Maximum = max;

            ReportProgress(this, args);

        }

 

    }

Finally in the Mainform

Visual Basic

Public Class Form1

 

    Private Sub button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles button1.Click

        Dim doWork As New DoWork()

        AddHandler doWork.ReportProgress, AddressOf doWork_ReportProgress

        doWork.DoTheWork()

    End Sub

 

    Private Sub doWork_ReportProgress(ByVal sender As Object, ByVal e As ProgressBarProgressEventArgs)

        progressBar1.Maximum = e.Maximum

        progressBar1.Value = e.Stage

    End Sub

 

 

End Class

C#

using System;

using System.Windows.Forms;

 

namespace ProgressBarDelegate

{

    public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

        }

 

        private void button1_Click(object sender, EventArgs e)

        {

            DoWork doWork = new DoWork();

            doWork.ReportProgress += new ProgressBarHandler(doWork_ReportProgress);

            doWork.DoTheWork();

        }

 

        void doWork_ReportProgress(object sender, ProgressBarProgressEventArgs e)

        {

            progressBar1.Maximum = e.Maximum;

            progressBar1.Value = e.Stage;

        }

 

    }

}

Try debugging this and you should see that this is much more "sensible", although the first example is much easier to understand. This is the preferred way of declaring delegates.