On class level declare the following vars in your Activity:

private int mYear;
private int mMonth;
private int mDay;
private int mHour;
private int mMinute;
private Calendar c;
private Context ctx = this;

In the OnCreate, initialize them:

mYear= Calendar.getInstance().get(Calendar.YEAR);
mMonth=Calendar.getInstance().get(Calendar.MONTH)+1;
mDay=Calendar.getInstance().get(Calendar.DAY_OF_MONTH) ;
mHour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY) ;
mMinute = Calendar.getInstance().get(Calendar.MINUTE);

To get the Date Picker, call the following function:

private void show_Datepicker() {
  c = Calendar.getInstance();
  int mYearParam = mYear;
  int mMonthParam = mMonth-1;
  int mDayParam = mDay;

  DatePickerDialog datePickerDialog = new DatePickerDialog(ctx,
    new DatePickerDialog.OnDateSetListener() {

    @Override
    public void onDateSet(DatePicker view, int year,
      int monthOfYear, int dayOfMonth) {
        mMonth = monthOfYear + 1;
        mYear=year;
        mDay=dayOfMonth;
      }
    }, mYearParam, mMonthParam, mDayParam);
  
  datePickerDialog.show();
}

This will give you the date picker pop-up.

To get a Time Picker, call the following function:

private void show_Timepicker() {

  TimePickerDialog timePickerDialog = new TimePickerDialog(ctx,
  new TimePickerDialog.OnTimeSetListener() {

  @Override
  public void onTimeSet(TimePicker view, int pHour,
    int pMinute) {

      mHour = pHour;
      mMinute = pMinute;
    }
  }, mHour, mMinute, true);

  timePickerDialog.show();
}

That will give you the time picker pop-up.

When developing games for mobile devices the first challenge you will encounter is the difference in screen resolutions. You will want to use the full screen on your device, while maintaining correct aspect ratios.

There are many ways to solve this, in this blog post I will present a simple one. One that works for games that do not use views. One that does not go into depth on camera views etc.

First let’s look at what happens when you set your game to Full Screen.

Gamemaker will size the width and height of your room to match the width and height of your device.

If, for example, your device has a resolution of 1440×900 (like the Samsung Galaxy Tab A 2016), Gamemaker will stretch/shrink the width and height of your room to match this. When you want to get the screen width and height in Gamemaker, it will return the device width and height: 1440×900. This will always be the case, no matter what size your room is, and no matter how you try to retrieve is. So:

display_get_gui_width() will return 1440
display_get_gui_height(
) will return 900

And also:

display_get_width() will return 1440
display_get_height() will return 900

When designing your game, you will have to choose a resolution to work with. E.g. 900 x 600. To do so, make your room dimensions 900 x 600.

Now what happens? The width of the device is divided into 900 pixels, the height of the device is divided into 600 pixels. Even when your device has a completely different resolution. With our example of a device with a resolution of 1440 x 900 that means:

The width of 900 in GameMaker = 1440 in reality. So one (1) pixel in gamemaker = 1.6 pixels on your device horizontally.

The height of 600 in GameMaker = 900 in reality, so one pixel in gamemaker = 1.5 pixels on your device vertically.

If you have a sprite of a perfect square of 100×100, that square will look perfect on a device with the same (900×600) resolution. In our example device it will have the following dimensions:

width: 100×1.6 = 160
height: 100×1.5 = 150

So the prefect square wil be 160 x 150 on your device: it is no longer a perfect square, it is a rectangle.

a square will be resized to a rectangle

How to solve this?

In your code you must apply a correction factor. To find that factor, you need to know the difference between the horizontal and vertical ratios.

In our example the horizontal ratio is 1.6, the vertical is 1.5.

You will want to multiply the height of your objects in such way that the 1.5 becomes 1.6.

To get this factor, use the following formula:

designWidth = 900; (your design width and height)
designHeight = 600;

factor_height =
(display_get_width()/designWidth) /  (display_get_height()/designHeigh
t);

So factor_height will be (1440/900) / (900/600) = 1.067

To make your square perfect again, you will need to multiply the height by 1.067. You can do this by setting the image_yscale property.

The way I do this: at the start of the game I calculate the height_factor.

Next, I make a parent object that sets the image_yscale to this factor. All objects in the game inherit from this parent object.

A new game build in GameMaker Studio 2

Square This! is both relaxing as well as challenging. There is no time pressure. You can sit back, relax, and solve the puzzles. The game has many levels. Solving a puzzle unlocks a new one. The goal is to swap tiles in a logical order. To unlock a new level the puzzle needs to be solved in a maximum number of turns. Enjoy tapping tiles, enjoy solving the puzzles, enjoy playing this game!

“Square This!” is now available on Google Play.

Get it on Google Play

Google Play and the Google Play logo are trademarks of Google LLC.

Code snippet for saving a key-value pair in gamemaker. Data is saved in the file data.dat. Works for all platforms.

Saving:

mKey="myKey";
mValue="myValue";
mMap = ds_map_secure_load("data.dat");
if (mMap==-1){
   mMap=ds_map_create();
} 

if (!ds_map_exists(mMap, mKey)){
   // add the key-value 
   ds_map_add(mMap, mKey, mValue);
} else {
   // replace the value for the key
   ds_map_replace(mMap, mKey, mValue);
}

ds_map_secure_save(mMap, "data.dat");
ds_map_destroy(mMap);

Loading:

mKey="myKey";
mValue="default value";

mMap = ds_map_secure_load("data.dat"); 
if (mMap==-1){
mMap=ds_map_create();
}
if (ds_map_exists(mMap, key)){ mValue=ds_map_find_value(mMap, key); } ds_map_destroy(mMap);

With this workout timer app you can make a serie/sequence of timers that are executed one after the other. Every timer has its own time and its own alarm sound. You can make unlimited sequences, and every sequence can have an unlimited amount of timers.
This app is ideal for workouts, but can also be used for other things. E.g. Yoga, Reiki, and also as a timer for homework / study, coaching sessions, and many many more.

Get it on Google Play

Google Play and the Google Play logo are trademarks of Google LLC.

Context _ctx = this;
AlertDialog.Builder mBuilder = new AlertDialog.Builder(_ctx);
mBuilder.setMessage("[The message you want to show]");
mBuilder.setCancelable(false);
mBuilder.setPositiveButton("[Button caption for Yes]",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
// Do what is needed if user selects Yes
}
});
mBuilder.setNegativeButton("Button Title for No]",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
// users selected No
}
});

AlertDialog mAlertDialog = mBuilder.create();
mAlertDialog.show();



<?php 

function GetDbConnection(){ 

  $servername = "localhost"; 
  $username = "user"; 
  $password = "password"; 
  $dbname = "myDB"; 
  $conn = new mysqli($servername, $username, $password, $dbname); 
  if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
  } 
  return $conn;
}

function ListAllFromQuery($conn,$sql){
      
  $mArr = array();
  $result = $conn->query($sql);
  if ($result->num_rows > 0) {
    while($row = $result->fetch_assoc()) {
      array_push($mArr, $row);
    }
  }
  return $mArr;
}


$conn = GetDbConnection();
$list =ListAllFromQuery($conn,"SELECT * FROM tblUser ORDER BY id;");
$output="";

for($i = 0; $i < count($list); $i++) { 
  $currentUser= $list[$i]; 
  foreach($currentUser as $key => $key_value) {
    $output.= $key . " = " . $key_value;
    $output.= "<br>";
  }
  $output.= "<hr>";
}

$conn->close();

echo $output;

?>



#!/usr/bin/perl

# PERL5 CODE SNIPPET
# Get the full HTML of an url and strip all urls in it

use strict;
use warnings;
use LWP::Simple;

# The array that will hold all found urls
my @urls = ();

# the url to scan
my $url = 'http://www.devjockeys.com';

# get the content
my $content = get $url;
die "Couldn't get $url" unless defined $content;

#convert to lowercase
$content = lc($content);

# replace all " to '
$content =~ s/\"/\'/ig;

# search for  "a href" tags and strip the urls.
while (index($content, "<a href") != -1) {

   my $i = index($content, "<a href");

   my $tmp = substr($content, $i );
   $content = substr($content, $i + 1 );

   my $t = index($tmp,">");
   
   if (index(substr($tmp,0, $t+1),"http") != -1){
      my $tmp2 = substr($tmp,0, $t+1);
      
      my $c1 = index($tmp2,"\'");
      $tmp2 = substr($tmp2,$c1+1);
      
      $c1 = index($tmp2,"\'");
      $tmp2 = substr($tmp2,0,$c1);
      # add the url to the array
      push @urls, $tmp2;  
   }
}

# do what ever you like with the found url's. E.g. print them to your console.
foreach(@urls){
    print "$_\n";
}





using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        
        static void Main(string[] args)
        {
            CallWithAsync();
            Console.WriteLine("Press any key to quit.");
            Console.ReadKey();
          
        }

        // common method
        private static string GetData(string actionName)
        {
            // Do your heavy work here. E.g. fetch data from a database.
            Thread.Sleep(3000);
            return string.Format("Action {0} finished. The time is {1}.", actionName, DateTime.Now.TimeOfDay);
        }
       


        // WRAPPER for async methods: these will make "GetData" asynchronous.

        private static Task<string> GetDataAsync(string name){
            // wrap the GetData method in a Task:
            return Task.Run<string>(() =>
            {
                return GetData(name);
            });

        }

        private async static void CallWithAsync()
        {
            // Call the async method and wait for its result
            string result = await GetDataAsync("Custom Action Name");
            Console.WriteLine(result);
            
        }
    }
}

Want to generate a HTML table in Javascript? This is how you do that:


<!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8">
 <title>Javascript tables</title>
 </head>
 <body>

<h1>Javascript generated table</h1>

<table id='mTable' border='1' cellspacing='0' cellpadding='8'></table>

<script>

var tabel = document.getElementById("mTable");
var rowOne = tabel.insertRow(0);
var rowOneColumns = [];
rowOneColumns[0] = rowOne.insertCell(0);
rowOneColumns[1] = rowOne.insertCell(1);
rowOneColumns[2] = rowOne.insertCell(2);

var rowTwo = tabel.insertRow(1);
var rowTwoColumns = [];
rowTwoColumns[0] = rowTwo.insertCell(0);
rowTwoColumns[1] = rowTwo.insertCell(1);
rowTwoColumns[2] = rowTwo.insertCell(2);

rowOneColumns[0].innerHTML = "Row One, First Cell"; 
rowOneColumns[1].innerHTML = "Row One, Second Cell"; 
rowOneColumns[2].innerHTML = "Row One, Third Cell"; 
rowTwoColumns[0].innerHTML = "Row Two, First Cell"; 
rowTwoColumns[1].innerHTML = "Row Two, Second Cell"; 
rowTwoColumns[2].innerHTML = "Row Two, Third Cell";

</script>
 </body>
 </html>

Another App updated to the newest iOS version!
Project Time Log has been rebuilt in Swift, with updated API’s for DropBox and SQLite. After five years (first version in 2012!) still up and running!

Project Time Log in the AppStore

The goal of Project Time Log is to keep track of time you’ve spent on projects. There are three main actions:

1. Add one or more projects;
2. Start the timer for the project you start working on. Stop the timer when you stop working. You can repeat this as often as you wish;
3. View the log to learn how much time you’ve spent on your projects (per timer, per day and in total).

In addition to these actions you can:
– change project properties any time;
– make changes to your logs or add/delete logs manually: this comes in handy when you forgot to stop or start the timer;
– use the build-in notification system to alert you when a certain amount of time has been exceeded.
– export your logs for use in an external spreadsheet.
– backup and restore your data.

Project Time Log has been designed to be intuitively simple. The best way to get to know it is by testing and trying. There is a predefined ‘test project’ which you can use for that purpose. When finished testing you can delete it without any consequences.

A powerful feature of Project Time Log is that once you’ve started a timer, it will simply keep on counting until you stop it, even when your device is completely switched off.

Best solution for using SQLite in your Swift project is SQLite Swift. It works perfect and comes with very good documentation.

A problem I was facing was converting a field value to an integer.

In short, this was the problematic code:


let db = try Connection(databasePath)
let stmt = try db.prepare("SELECT someId, someCount, someName FROM someTable")
        
for row in stmt {
    print("row[1] = \(String(describing: row[1]))")
    // ... I need row[1] as Integer!
}

I needed to convert row[1] to an Integer.
I tried many solution, found on multiple forums, none of them really worked.
Finally I came up with this:


let db = try Connection(databasePath)
let stmt = try db.prepare("SELECT someId, someCount, someName FROM someTable")
        
for row in stmt {
    let optionalCount : Int64 = Optional(row[1]) as! Int64
    let lCount = Int(optionalCount)
    // Now I have an integer!

 }

Happy Coding!

The fastest way of coding is doing a lot of copy-paste. I know, you shouldn’t. But most of us do … so lets be honest about that 🙂

Following some copy-paste-ready Swift code for sending e-mails form your iOS app.



//  MailerViewController.swift

import UIKit

import MessageUI

class MailerViewController: UIViewController, MFMailComposeViewControllerDelegate {

override func viewDidLoad() {

super.viewDidLoad()

let mSubject = "The subject of the e-mail"

let mBody = "Hi! This is an e-mail. Please se the attached file."

let mRecipients = ["info@devjockeys.com", "martin@devjockeys.com", "some_recipient@some_email.com"]

let mAttachment = "Some content".data(using: String.Encoding.utf8, allowLossyConversion: false)!

let mAttachmentName = "attachment_filename.txt"

doEmail(subject: mSubject, body: mBody, recipients: mRecipients, attachment: mAttachment, attachmentName: mAttachmentName)

}

func doEmail(subject: String, body: String, recipients: Array, attachment: Data, attachmentName: String ) {

if MFMailComposeViewController.canSendMail() {

let mailer = MFMailComposeViewController()

mailer.mailComposeDelegate = self

// the subject
mailer.setSubject(subject)

// the recepients: an Array of Strings
mailer.setToRecipients(recipients)

// make an attachment. You can attach anything, as long as it is a "Data?" object
mailer.addAttachmentData(attachment, mimeType: "application/octet-stream", fileName: attachmentName)

// the message body
mailer.setMessageBody(body, isHTML: false)

// present the mailer
self.present(mailer, animated: true, completion: nil)

}

else

{

let alert = UIAlertController(title: "Mail Error", message: "Your device has not been configured to send e-mails", preferredStyle: .alert)

let okAction = UIAlertAction(title: "Ok", style: .default, handler: nil)

alert.addAction(okAction)

self.present(alert,animated: true,completion: nil)

}
}

// mailer delegate

func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {

var  message = ""

switch (result)

{

case .cancelled: message = "You cancelled the operation and no e-mail message was sent."
case .saved: message = "You saved the e-mail message in the drafts folder."
case .sent: message = "Mail send: e-mail message sent successfully."
case .failed: message = "Mail failed: the e-mail message was not sent. Please check your e-mail settings."

}

let alert = UIAlertController(title: "Mailer", message: message, preferredStyle: .alert)
let okAction = UIAlertAction(title: "Ok", style: .default, handler: nil)
alert.addAction(okAction)

self.present(alert,animated: true,completion: nil)

// Remove the mail view
self.dismiss(animated: true, completion: nil)

}

}

 

This code sample demonstrates how you can reorder an array.

A possible scenario is when you have multiple-choise questions that you want to present in a different order every time they are shown.

var arrUniqueNumbers = [1,2,3,4]        
print("Array before shuffle: \(arrUniqueNumbers)")    
let count = arrUniqueNumbers.count
for i in 0..<count{
            let n = Int(arc4random_uniform(UInt32(count-i)))+i            
            (arrUniqueNumbers[i], arrUniqueNumbers[n]) = 
                              (arrUniqueNumbers[n], arrUniqueNumbers[i])
           }
print("Array after shuffle: \(arrUniqueNumbers)")

 

Learn to recognize intervals, train your ears.
With this solfege – ear training app you have the tool to train your musical hearing. With four different levels this app has been developed for everyone that wants to train intervals: from beginners to professional musicians.

Solfege Intervals

Solfege Intervals


Solfege Intervals

Solfege Intervals


Solfege Intervals

Solfege Intervals

Get it on Google Play

Google Play and the Google Play logo are trademarks of Google LLC.

Reading data from a database using a DataReader is fast and easy. If something goes wrong, mostly that has to do with null values.
To prevent that, you can extend the DataReader class with some handy methods.

The example below uses the MySqlClient, however, you can use the same methods for SQL and OleDb.
Also, the example only shows methods for integers and strings. Of course you can write similar methods for all data types.


using System;

namespace Utilities
{
    public static class Extentions
    {

        public static int SafeGetInteger(this MySql.Data.MySqlClient.MySqlDataReader reader, string colName)
        {
            int result = 0;
            if (reader[colName]!= null)
            {
                string tmp = reader[colName].ToString();
                if (int.TryParse(tmp, out result))
                {
                    return result;
                }
                else
                {
                    return 0;
                }
            }
            else
            {
                return 0;
            }
            
        }

        public static string SafeGetString(this MySql.Data.MySqlClient.MySqlDataReader reader, string colName)
        {
            if (reader[colName] != null)
                return reader[colName].ToString();
            else
                return string.Empty;
        }
    }
}

How Was Your Mood?

Everybody experiences moodswings in some way or another, it is a natural thing. There can be a lot of reasons for wanting to get an insight in your moodswings, from simply being interested to being diagnosed bipolar.

DevJockeys developed the iOS app ‘How was your mood’. It is a friendly app, which helps you to document your mood swings on a daily basis,
by asking you a simple question: how was your mood today?
Because it is so important to know if your mood change was a reaction to events, or seemed to have no reason at all,
the app enables you to make notes, which you can easily access in the graph. Intuitive and simple!

INSTRUCTIONS

*start screen:

  • pan or tap to set your daily mood
  • select “date” to fill in moods for other (past) dates
  • after setting your mood, select “note” to make some notes for this day
  • tap on “overview” to show the graph
  • tap on “settings” to open the settings view

*settings

  • enable or disable autocorrection while editing notes
  • enable or disable daily notifications. When switched on, tap the “edit” button to set a notification time. The app will remind you to fill in your mood at the time you set here daily

*Overview / Graph

  • swipe left or right to scroll the graph
  • use the “+” and “-” buttons to change the year
  • tap on a date point to view or edit notes

You can find “How Was Your Mood” in Apple’s App Store.

Get it on Google Play

Google Play and the Google Play logo are trademarks of Google LLC.

Introduction

Polymorphism and inheritance tend to be heavy subjects for people that start to find their way in Object Oriented Programming. There are many, many tutorials and blogposts about this subject. Most of them have one thing in common: they use “what if”, “imagine that”, or “you work for a major company with a customer database” scenarios, or they use simplified models that you will probably never use in real-life – e.g. examples with animals, cats and dogs.

In this post I am going to describe a real-life usable example on how to implement inheritance and polymorphism. When you go through this post, you will have basic understanding of the concept. And you will have some code that you can easily reuse in your own development projects.

What are we building?

We will build a simple file browser. The application mainly uses the System.IO.FileInfo and System.IO.DirectoryInfo objects. The idea is as followed:

We will show a filebrowser list on screen. This list contains direcories and files. When an item in that list is selected, information about that item is shown. The clue here is that when that item is a directory, it will show different information then when it is a file. Also, when you double click an item, the action taken will depend on the type of item: if it is a directory, that directory will open in the list. If it is a file, nothing will happen (feel free to take action there as well.)

So, in the list we have a collection of an object that can act as a file or as a directory: that’s polymorphism. We’ll get this working by first building a base class, and inherit two derived classes from that base class. Let’s get started!

1. Setup the GUI

We are going to use a standard WPF project for this. Open Visual Studio and start a new C# WPF Project. Call it “FileBrowser”. On the mainwindow, place the following:

  • A Label at the top left. Name it lblCurrentDirectory
  • A Listbox at the left, just below the label. Name it FileListBox
  • A Textbox at the right. Name it txtDetails

We will give the Lisbox a template, so we can show more than just a single value. As you can see in the XAML below, in the listbox, one label is bound to a “DisplayType” field, another one is bound to a “Name” field.

Also in the listbox, two events are added: SelectionChanged and MouseDoubleClick. When entering them, make sure the handler methods are created in the code-behind (MainWindow.xaml.cs) as well.

The XAML should look something like this:


<Window x:Class="FileBrowser.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:FileBrowser"
        mc:Ignorable="d"
        Title="MainWindow" Height="550" Width="525">
    <Grid>
        <ListBox x:Name="fileListBox" HorizontalAlignment="Left" Height="459" Margin="10,52,0,0" VerticalAlignment="Top" Width="240" BorderBrush="#FF002698" SelectionChanged="fileListBox_SelectionChanged" MouseDoubleClick="fileListBox_MouseDoubleClick">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Label Content="{Binding DisplayType}"/>
                        <Label Content=" - "/>
                        <Label Content="{Binding Name}"/>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <TextBox x:Name="txtDetails" HorizontalAlignment="Left" Height="501" Margin="269,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="240" Background="#FFD0FFD5"/>
        <Label x:Name="lblCurrentDir" Content="" HorizontalAlignment="Left" Margin="10,11,0,0" VerticalAlignment="Top" Width="240"/>
    </Grid>
</Window>


2. Create the Base Class

The base class will be the parent of two other classes: the class that represents a file and the class that represents a directory.

In your project, add a new class named “FSBaseObject”. Code the class as in the code below:


using System;

namespace FileBrowser
{
    public abstract class FSBaseObject
    {
        public string Name { get; set; }
        public string Path { get; set; }
 
        public virtual string DisplayType { get {return "";}}

        public abstract string Details();

    }
}

As you can see, here we have the Name and DisplayType fields that we bound in the XAML. Further, the class is declared as abstract. This means that it is not possible to instantiate this class. If you want to use it, you have to use it via a derived class.

The properties Name and Path are straight forward. I have decided to make the property DisplayType a read/only virtual one, meaning that you can not set its value dynamically, and that you can override it (however, you do not have to. If you do not override it, it will retun an empty string).

The method Details() is abstract, meaning you have to override it in your derived classes.

This way, all derived classes will “share” the properties Name and Path. They can implement the property DisplayType, and they all have their “own” method Details.

3. Create the Derived Classes

We will create two derived classes: one for handling files, one for handling directories. Let’s start with the one for files. Create a new class, call it FSFileObject. Code is as below:

using System;
using System.Text;
using System.IO;

namespace FileBrowser
{
    public class FSFileObject : FSBaseObject
    {
        public FileInfo mFile { get; set; }
        public string FileSize{
            get {
                if (mFile != null)
                {
                    if (mFile.Length < 1024)
                    {
                        return string.Format("{0} B", mFile.Length);
                    } else if  (mFile.Length < 1024 * 1024)
                        {
                        return string.Format("{0:0.00} KB", (double)mFile.Length/1024);
                        }
                        else
                        {
                        return string.Format("{0:0.00} MB", (double)mFile.Length / (1024*1024));
                    }
                }
                else
                {
                    return "";
                }
            }
        }

        public override string DisplayType
        {
            get
            {
                return "File";
            }
        }

        public FSFileObject(string path)
        {
            this.Path = path;

            if (File.Exists(path))
            {
                mFile = new FileInfo(path);
                Name = mFile.Name;
            }
        }

        public override string Details()
        {
            StringBuilder sb = new StringBuilder();
            
            sb.AppendLine("Type:  file");
            sb.AppendLine("Name: " + Name);
            sb.AppendLine("Size: " + FileSize);
            
            return sb.ToString();
        }
    }
}

Line 7 shows how to declare this class as being inherited from our base class.

At line 9 we declare a property of type FileInfo. This is a System.IO object that handles file information and maipulation.

At line 10 I’ve added a property FileSize that shows the size of the file as Bytes, Kilobytes or Megabytes, depending on its size. This is just for fun.

Line 33 shows the overriden property DisplayType. This Readonly property simply returns “File”.

Line 41 show an overloaded constructor. This constructor is called when you instantiate the class with the “new” keyword, and provide a string as parameter. In code that would look like (example):


FSFileObject obj = new FSFileObject("C:\\temp\text.txt");

When instantiating the class like this, the property mFile is instantiated as well, containing information about the text.txt file.

Line 52 shows the overriden method Details. When called, this method will return some text that describes the file.

In as similar way, we’ll create a class for directories. Add a new class file to your project, and call it “FSDirectoryObject”. Code is as below:


using System;
using System.Text;
using System.IO;

namespace FileBrowser
{
    class FSDirectoryObject:FSBaseObject
    {
        public DirectoryInfo mDirectory { get; set; }

        public override string DisplayType
        {
            get
            {
                return "Directory";
            }
        }

        public FSDirectoryObject(string path)
        {
            this.Path = path;
            if (Directory.Exists(path))
            {
                mDirectory = new DirectoryInfo(path);
                Name = mDirectory.Name;
            }
        }

        public override string Details()
        {
            StringBuilder sb = new StringBuilder();

            sb.AppendLine("Type:  directory");
            sb.AppendLine("Name: " + Name);
            return sb.ToString();
        }
    }
}

As you can see, this class looks a lot like the FSFileObject. However, it is slighty different.

Next, we’ll actually start using these classes by adding code to MainWindow.xaml.cs.

4. MainWindow.xaml.cs

This is where it al happens. Let’s start with the code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;

namespace FileBrowser
{
    /// 

    /// Interaction logic for MainWindow.xaml
    /// 
public partial class MainWindow : Window {
 private List lst; 
public MainWindow() { 
InitializeComponent(); 
lst = new List(); 
fillBox("c:\\"); 
} 
private void fillBox(string mainPath) { 
lst.Clear(); 
fileListBox.ItemsSource = null; 
lblCurrentDir.Content = mainPath;
 DirectoryInfo parentInfo = Directory.GetParent(mainPath); 
if (parentInfo != null) { 
FSDirectoryObject dirParent = new FSDirectoryObject(parentInfo.FullName); 
dirParent.Name = ".."; 
lst.Add(dirParent);
 } 
string[] dirs = Directory.GetDirectories(mainPath); 
string[] files = Directory.GetFiles(mainPath); 
foreach (string s in dirs) { 
FSDirectoryObject dir = new FSDirectoryObject(s); 
lst.Add(dir); 
} 
foreach (string s in files) {
 FSFileObject file = new FSFileObject(s); 
lst.Add(file); 
} 
fileListBox.ItemsSource = lst; 
fileListBox.SelectedIndex = 0;
 } 
private void fileListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { 
if (fileListBox.SelectedItem != null) { 
txtDetails.Text = ((FSBaseObject)fileListBox.SelectedItem).Details(); 
} 
} 
private void fileListBox_MouseDoubleClick(object sender, MouseButtonEventArgs e) { 
if (fileListBox.SelectedItem != null) {
 var d = fileListBox.SelectedItem as FSDirectoryObject;
 if (d != null) { 
fillBox(d.Path);
 } 
}
 }
 }
 }

Let’s look what’s happening here.

At line 24 we add a List of type FSBaseObject. That is a list that can be filled with instances of our base object. Wait, that base class was declared abstract, so we can’t make any instances, right? Correct. However, this is a post about polymorphism.. we can add instances of FSFileObject and FSDirectoryObject. In fact, we could add instances of any object, as long as it inhertis from FSBaseObject. Read on.

At line 32 we call a method and pass it the path to the root directory. This method starts at line 36. First, let’s jump to line 51.

Here we use the static build-in System.IO class Directory. It gives us a quick wat to retreive all sub-directories and files in a given directory. We fill two string arrays with the path to all sub-driectories and files within the root path that we defined in line 32 (c:\). Next we iterate through these arrays. First to create an instance of FSDirectoryObject for every subdirectory we have found, next we create an instance of FSFileDirectory for every file we have found. Every instance is added to the list from line 24.

The result is a list of type FSBaseObject, that is filled with instances of FSDirectoryObject and FSFileObject.

The code at line 42 to 49 adds another FSDirectoryObject, which point to the parent directory of directory that is currently shown.

When an item in the list is selected, the SelectionChanged handler at line 72 is called. It first converts the selected list item to an instance of FSBaseObject, next it calls the Details method. And that is where the magic starts! We take a FSBaseObject, but when we call the Details method, that method is invoked at the instance of the inherited class, which can be a FSDirectoryObject or FSFileDirectoryObject.

When you doubleclick an item in the list, the MouseDoubleClick event handler is called. At line 84 this method tries to cast the selected item as a FSDirectoryObject. If the selected item is not a FSDirectoryObject, but a FSFileObect, the cast will return null. No action taken then. However, if the selected item is a FSDirectoryObject, the path of that directory is used to refill the listbox.

The result? A simple file browser that uses inheritance and polymorphism to handle both files and directories!

The .NET framework makes multi-threading as easy as opening a can of peanut butter. Let’s make a small project to demonstrate.

Create a new C# WPF project in Visual Studio, and name it anything you like.

Drag a label and textbox on the mainwindow. Name the label “lblTime”.

Your XAML should looke something like below:


<Window x:Class="Butter.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Label x:Name="lblTime" Content="Label" HorizontalAlignment="Center" Margin="10,10,0,0" VerticalAlignment="Top"  Width="497"/>
        <TextBox x:Name="txtText" HorizontalAlignment="Left" Height="232" Margin="15,77,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="492"/>
    </Grid>
</Window>

Enter the following code in MainWindow.xaml.cs:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Butter
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            
            getTime();
        }
   
        private async void getTime(){
            
            Task task = Task.Run<string>(() => {

                System.Threading.Thread.Sleep(1000);
                return DateTime.Now.ToString();

            });

            lblTime.Content = await task;
            getTime();

        }
    }
}

Run the program. What happens? The time is displayed and updated every second. In the meanwhile you can type text in the textbox without being disturbed.

By making the method getTime async, it runs in another thread than the User Interface. Let’s analyse what’s happening in that method.

An async method needs a Task. We make one that returns a string. We invoke it with a lambda (the ()=>{} thing).

The task sleeps for a second and returns the current time.

Next, we tell the content property of the label to await the task.

What happens there? Well, the code in this method stops. Anything after the await will not be executed until the task is ready and returns a value.

In the meanwhile your program continues working. You achieved that by making the method async.

When ready, the task returns a string. The label content has been waiting for that string, and only when that string is received by the label, the rest of the code in the method is executed.

And te rest of the code… invokes the method again.

C# is a strongly typed language. When building your project, the compiler will check if the types you are using are valid. If you enter something like

int i = “Hello there”;

your code will not compile. i should be an integer value, the compiler sees that and refuses to continue.

There are however situations where you do not want the compiler to do these checks. Reason is that you simply do not know the exact type. This is somewhat common when you work with COM objects.

In that case you will want to tell the compiler to just pass the given value (or invoke the given method), and leave it to the runtime to decide if it is ok or not. You achieve this by using the keword “dynamic”.

When automating Excel, you’ll work with a com object. The dynamic type is the Excel Worksheet. Let’s start with the code, and after that analyze what is happening.

To be able to run the code, you’ll need to add a Microsoft.Office.Interop.Excel reference to your project. You can find it under “COM”, simply search for “Excel”.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Office = Microsoft.Office.Interop;


namespace AutoExcel
{
    class Program
    {
        static void Main(string[] args)
        {

            // Generate some testdata
            Dictionary<string,int[]> dict = new Dictionary<string,int[]>();
            for (int i = 1; i <=500; i+=1) {
                dict.Add("Number " + i.ToString(),new int[5] { 100+i, 200+i, 300+i, 400+i, 500+i });
            }

            // Create the Excel Sheet
            var excelApp = new Office.Excel.Application();
            excelApp.Visible = true;
            excelApp.Workbooks.Add();

            // dynamic: types will not be checked at compile time
            dynamic workSheet = excelApp.ActiveSheet;
            
            try
            {
                // Generate the header
                workSheet.Cells[1, "A"] = "MY AUTOMATED EXCELSHEET";
                workSheet.Cells[2, "A"] = "Demonstrating Excel Automation";
                workSheet.Cells[4, "A"] = "FIELD NAME";
                workSheet.Cells[4, "B"] = "VALUE #1";
                workSheet.Cells[4, "C"] = "VALUE #2";
                workSheet.Cells[4, "D"] = "VALUE #3";
                workSheet.Cells[4, "E"] = "VALUE #4";
                workSheet.Cells[4, "F"] = "VALUE #5";


                // generate the value fields
                int row = 5;

                foreach (KeyValuePair<string, int[]> val in dict)
                {
                    workSheet.Cells[row, "A"] = val.Key;
                    workSheet.Cells[row, "B"] = val.Value[0];
                    workSheet.Cells[row, "C"] = val.Value[1];
                    workSheet.Cells[row, "D"] = val.Value[2];
                    workSheet.Cells[row, "E"] = val.Value[3];
                    workSheet.Cells[row, "F"] = val.Value[4];

                    row += 1;
                }
                
                //  AutoSize the columns
                for (int i = 1; i <= 5; i++)
                {
                    workSheet.Columns[i].AutoFit();
                }

                // Some layout:

                // Font type
                workSheet.Range(workSheet.Cells(1, 1), workSheet.Cells(row, 6)).Font.Name = "Arial";
                workSheet.Range(workSheet.Cells(1, 1), workSheet.Cells(1, 1)).Font.Size = 16;
                workSheet.Range(workSheet.Cells(2, 1), workSheet.Cells(row, 6)).Font.Size = 8;
                // Bold text:
                workSheet.Rows(4).Font.Bold = true;


                // Freeze the header
                workSheet.Application.ActiveWindow.SplitRow = 4;
                workSheet.Application.ActiveWindow.FreezePanes = true;

                
                // Select the first cell
                workSheet.Cells(1, 1).Select();
                
            }
            catch (Exception ex)
            {
                Console.WriteLine("Excel reported the following Error:");
                Console.WriteLine(ex.Message);
            }
            finally
            {
                // Release the com object
                System.Runtime.InteropServices.Marshal.ReleaseComObject(excelApp);
            }
            Console.WriteLine("Ready.");
            Console.Read();
        }   
    }
}

Let’s start with line 6. I included the Microsoft.Office.Interop and named it “Office”. You do not have to do this, but I found that it makes my life easier.

Line 16-20. We are making a program that generates an Excelsheet. That makes more sense with some data to show. These lines simply generate some numbers.

line 23-25 initialise the Excelapplication, and..

line 28 declares a worksheet as dynamic. This means that whatever you tell the worksheet to do, the compiler accepts it.

Line 30 to 87 take care of filling the worksheet. Note that when you enter this code, Visual Studio will not warn you if you make any typo’s.

Before explaining the “finally” block, let’s do an experiment.

Run the program. It should show an Excelsheet with some mark-up.

Now add the following line of code at line 65.

workSheet.PlayTheGuitarAsIfYourLifeDependsOnIt();

You can be pretty sure this method is not known by the worksheet. However, you can still compile and run the program. Only at runtime, an exception is thrown.

Finally, the finally block.

Com objects are not managed. It is so called unmanaged code.

Normally, when you exit an application, references to all objects are cleaned-up automatically. That is .. all managed references. Com objects are not managed, and will not be cleaned up.

You can see this happen by commenting out line 91 and start the program, close it, and repeat that several times. Close all Excel sheets. Now look in your task manager. You’ll see that a lot of “Excels” are still running in the background. The only way to end those is by ending the processes using task manager.

What happened? In your code you create Excel Com objects. Those objects generated Excelsheets. You can close the Excelsheets, but not the com objects. When you close the program, the .NET Garbage Collector cleans-up all managed objects … and because the dynamic workSheet object is not managed, it is not cleaned up by the Garbage Collector.

Imagine what happens if you generate 200 Excelsheets automatically…

Fortunately there is a way to clean up those com objects, as demonstrated in line 91. Make sure that code is always executed. The finally-block is the best place to do that.