Learning Cobol Round #1

My mum learnt COBOL and FORTRAN when she was in university back in the 60s. Although I have used FORTRAN77 in a professional capacity, I still haven’t had the opportunity to try COBOL.

Since being retro is the harbinger of cool, I’ll spend the next few articles blogging about my experience working with COBOL.

Visual Cobol

There is a free non-commercial use license granted by Visual Cobol. This is sufficient for my learning purposes.

In terms of resources, Teach yourself COBOL is 21 days seems to be a good starting point.

The download is a little tricky. After receiving the confirmation email, I was presented with a screen but the download link wasn’t apparent. It’s tucked under the Software/Licenses tab (see red arrow). The download was 417MB, and I was a little concerned I’ll not have much space left on my SSD, which is burgeoning with several virtual machines. However, the promise of the familiarity of Visual Studio and having access to the .NET framework beckons me to try it out.

In comparison, the OPENCOBOL 1.1 source download is 1 Mb. That’s very inviting, although I don’t really like the idea of building GNU autoconf project on Windows.  There’s never a nice ending.  I found prebuilt-binaries for OPENCOBOL on Windows, and given the download size of 7.3 Mb,  I downloaded it as well.

Upon creating the first COBOL project with Visual Studio, I was prompted for a license key. It wasn’t immediately apparent, but all I had to do was to provide the email address I had used to register with Microfocus, and that activated my free copy automatically.

Running Hello World from a Visual Cobol Console project was simple enough.

       identification division.
       program-id. Program1.

       environment division.
       configuration section.

       data division.
       working-storage section.

       procedure division.

       PROGRAM-BEGIN.      
       DISPLAY "Hello World".
       PROGRAM-DONE.
       
       end program Program1.

OpenCobol

OpenCobol was straightforward. Unzip the 64bit binaries to C:\OpenCobol, and run vcvars64.bat to set up the path to Visual C (OpenCobol translates COBOL to C and then uses the platform compiler to build executables). The command below builds hello.exe

cobc -x hello.cob

Project scope

In terms of project, I’d like to try my standard project, involving authorization, data validation and persistence (both NoSQL and SQL). I’m mindful that my projects will be un-COBOL-like, but that can be refined with time.

Next article – Round #2

Working with 4D database via ODBC

There are some peculiarities when working with 4D databases and .NET

Date time 0/00/0 12:00

0/00/0 12:00 is valid in ODBC, but not valid in .NET.
Recommendation – wrap all date calls with a CAST
e.g.
SELECT CAST(BIRTHDAY AS VARCHAR) AS BIRTHDAY

alternatively, use a CASE statement to convert this call to something palatable to 4D e.g.

CASE CAST(LASTSEENDATE AS VARCHAR) WHEN '0/00/0 12:00:00' THEN CAST('1/1/1970' AS TIMESTAMP) ELSE LASTSEENDATE END AS LASTSEENDATE

Other alternatives simply don’t work. e.g. ... THEN NULL ELSE ... and NULLIF()

Business Forms in Silverlight Part 2

(this is a continuation of Part 1)

From the previous post:

Basic DataForm experience

Basic DataForm experience

The first problem is the OrderDate is unintialized and renders as 0/00/0000.

The first thought is to change the OrderDate from DateTime to Nullable<DateTime>. This will require either the database schema be changed, or a second viewmodel created. Changing the database schema just to support a user-interface tweak is obviously out of the question. However, writing a viewmodel and copying all the properties over breaks a rule of “DRY” (Don’t Repeat Yourself).

Luckily, XAML binding supports the notion of binding converters. This lets us transforms inputs from one type to another.

public class NullValueConverter : IValueConverter
{

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is DateTime && targetType == typeof(Nullable<DateTime>))
        {
            if ((DateTime)value == DateTime.MinValue)
            {
                return null;
            }
        }
        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value;
    }
}

Applying the converter to the date picker, we get reasonably good results. For example, after entering a date and then clearing it, we get a validation error showing (see picture below). Furthermore, hitting cancel restores the control back to default value.

dataform2

This done, we are ready to tackle our next problem.

Aside

Here’s a sample of how converters are applied.

<sdk:DataForm>
  <sdk:DataForm.Resources>
    <local:NullValueConverter x:Key="NullValueConverter" />
  </sdk:DataForm.Resources>
  <sdk:DataField Label="Order Date">
    <sdk:DatePicker SelectedDate="{Binding OrderDate, Converter={StaticResource NullValueConverter}}" />
  </sdk:DataField>
</sdk:DataForm>

Fool-Proof Business Forms in Silverlight Part I

Silverlight DataForms makes it quick and easy to get started with database applications. However, it has some downsides. The default isn’t particularly customizable, and to do anything more takes a great deal more effort.

Take the following example:

        internal sealed class OrderMetadata
        {

            // Metadata classes are not meant to be instantiated.
            private OrderMetadata()
            {
            }

            [Display(Name = "Order date", GroupName = "Order", Order = 1)]
            public DateTime OrderDate { get; set; }

            [Range(0, 100.0, ErrorMessage = "Please enter more than $0.00")]
            [Display(Name = "Total Amount", GroupName = "Order", Order = 2)]
            public decimal Amount { get; set; }

            [Display(Name = "Purchase Order No", GroupName = "Order", Order = 3)]
            public string PurchaseOrder { get; set; }

            [Display(Name = "Customer Name", GroupName = "Customer", Order = 1)]
            public Customer Customer { get; set; }

            [Display(Name = "Is Delivered", GroupName = "Customer", Order = 2)]
            public byte[] IsDelivered { get; set; }

            [ScaffoldColumn(false)]
            public int CustomerId { get; set; }

            [ScaffoldColumn(false)]
            public int OrderId { get; set; }
            
            public float Weight { get; set; }

            [UIHint("Image", "SL", "ScannedFilename")]
            public Byte[] ScannedImage { get; set; }

            [ScaffoldColumn(false)]
            public String ScannedFilename { get; set; }
        }

This generates a data form that gets us pretty close. See the picture below.

dataform1

However, there are several issues:

  1. The Order date is very ugly. It should have default to a null value
  2. The Customer field should have been bound to a combo box or something more custom
  3. The Total Amount validation message could not be customized. It reports “Input is not in the correct format”. Ideally, the message should be customizable and localizable.
  4. CustomerId and OrderId should be hidden
  5. Scanned file name and Scanned image should be combined into a single image control, showing the image, the file name, and provide a method to replace the image.

Over the next few posts, I’ll discuss how to overcome these problems using a custom view model and avoid unnecessary code duplication.

Syncfusion’s latest datagrid

I’ve been looking forward to Syncfusion’s latest release of their Silverlight components (and it’s out today). In particular, their new SfDataGrid datagrid is reaching maturity so I decided to take it out for a quick spin, and verdict is out. Two thumbs up. Well done. Their API is intuitive and much improved from their original DataGrid. It is different, so don’t expect to be able to port over existing code easily, but there is considerably less code to port.

We’ll start off with a simple model

namespace SyncfusionGridDemo.ViewModels
{
    using System.ComponentModel.DataAnnotations;

    public class Customer
    {
        [Display(Name="Full Name")]
        [Required(ErrorMessage="{0} is required")]
        public string FullName { get; set; }

        [Range(18, 80)]
        public int Age { get; set; }
    }
}

As you can see there is not much to it, and we’ll create a viewmodel and host a collection of Customers.

namespace SyncfusionGridDemo.ViewModels
{
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Collections.Specialized;

    public class MainPageViewModel
    {
        private IList<Customer> _addedCustomers = new List<Customer>();
        private IList<Customer> _deletedCustomers = new List<Customer>();

        public MainPageViewModel()
        {
            Customers = new ObservableCollection<Customer>(new[]
            {
                new Customer { FullName = "Marcus Aurelius", Age=30 },
                new Customer { FullName = "Dana Fausbinder", Age=3 },
                new Customer { FullName = "Tomoko Cressida McManus", Age=54 },
            });
            Customers.CollectionChanged += Customers_CollectionChanged;
        }

        void Customers_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    // TODO these will need to be saved to the database
                    _deletedCustomers.RemoveRange((IEnumerable<Customer>)e.NewItems);
                    _addedCustomers.AddRange<Customer>((IEnumerable<Customer>)e.NewItems);
                    break;
                case NotifyCollectionChangedAction.Remove:
                    _addedCustomers.RemoveRange((IEnumerable<Customer>)e.NewItems);
                    _deletedCustomers.AddRange<Customer>((IEnumerable<Customer>)e.NewItems);
                    break;
                case NotifyCollectionChangedAction.Replace:
                    // TODO these will need to be saved to the database
                    _deletedCustomers.RemoveRange((IEnumerable<Customer>)e.OldItems);
                    _addedCustomers.RemoveRange((IEnumerable<Customer>)e.OldItems);
                    _addedCustomers.AddRange<Customer>((IEnumerable<Customer>)e.NewItems);
                    break;

            }

        }

        public ObservableCollection<Customer> Customers { get; set; }
    }

    public static class CollectionExtension
    {
        public static void AddRange<T>(this IList<T> coll, IEnumerable<T> items)
        {
            foreach (var item in items)
            {
                if (!coll.Contains(item))
                    coll.Add(item);
            }
        }

        public static void RemoveRange<T>(this IList<T> coll, IEnumerable<T> items)
        {
            foreach (var item in items)
            {
                if (coll.Contains(item))
                    coll.Remove(item);
            }
        }


    }
}

And now let’s bind to Syncfusion SfDataGrid


        <Grid:SfDataGrid 
            AllowEditing="True" 
            Grid.Row="1" 
            ItemsSource="{Binding Customers}" 
            x:Name="SampleGrid" 
            GridValidationMode="InEdit" 
            AddNewRowPosition="Top"/>

and the result is rather good for so little work.

Some minor criticism

The datagrid is not aware of IEditableObject interface. This interface supports BeginEdit(), EndEdit() and CancelEdit(). This allows the user to revert the record’s changes using the escape key.

Overall, the user experience is much improved. Thanks again for listening to my concerns.

Succeeding with Windows Phone Apps

Take aways:

  1. Add all screenshots
  2. Provide background image – or it will not get featured in the Store
  3. Description is super important especially the first few sentences

Make use of

  1. Live Tiles
  2. Lock Screen
  3. Toast Notification
  4. SkyDrive
  5. Wallet
  6. Caching
  7. Location Services

Live Tiles

  1. 159 x 169
  2. 336 x 336
  3. 691 x 336

There are three type of templates

  1. Flips to the back. So the most important info should be on the front
  2. Cycle template of 9 images – but don’t make user wait.
  3. Iconic template small icons
    1. 110×110 for small
    2. 202 x 202 for Medium.
    3. Wide uses the small icon

Effective Design-Time data with Silverlight

There were quite a few ways one can enable Silverlight design time data binding. Design time data binding provides the GUI designer with some sample values and this is particularly handy when laying out controls in Visual Studio.

Using d:DataContext and d:DesignInstance

<Grid x:Name="LayoutRoot" Background="White"
  d:DataContext="{d:DesignInstance
  Type=local:Customer}">
</Grid>

Note: You can also do this:

<Grid x:Name="LayoutRoot" Background="White"
  d:DataContext="{d:DesignInstance
  Type=local:Customer,
  CreateList=True}">
</Grid>

Using d:DesignData

<StackPanel
  d:DataContext="{d:DesignData
  Source=./DesignData/SampleCustomer.xaml}">

Note: the Build action should be DesignData or DesignDataWithDesignTimeCreatableTypes

Using d:DesignSource (for CollectionViewSource)

If your model binds to a CollectionViewSource, you can set it in conjunction with DesignInstance.

<CollectionViewSource x:Key="CustomerViewSource"
  d:DesignSource="{d:DesignInstance
  local:Customer, CreateList=True}" />