It’s been a busy term for me at NUA, development of the Nellie’s Nursery and Storehouse Online websites has happened quite rapidly and a lot of work has gone into coding both. This Easter break I had intended to start coding Elebase 4 on Monday 26th March, however I decided to take a weeks’ break from developing Elebase so that I would come to develop Elebase 4 with fresh eyes (and to give something else to think about!) and to give me a chance to try something else!

My experience with C#

Windows 10 Universal Windows Platform app

I haven’t written any kind of app in C# since February 2016 – over two years ago! The last app I wrote in C# was a Windows 10 Universal app for my A level Computer Science coursework. The Windows 10 UWP (‘Universl Windows Platform’) apps can run on any Windows 10 device, be it a Windows 10 desktop or laptop, a Windows 10 mobile phone, an Xbox One, a Surface Hub and even a Raspberry-Pi 3 (so long as the Windows 10 IoT Core operating system is installed on it). Despite the fact that Windows 10 Mobile is now dead and gone, Windows 10 UWP apps still remain a good option for developers interested in coding apps to run on a variety of Windows 10 platforms without the need to code different versions of the apps for the various platforms that Windows 10 can run on – UWP code even remains universal on multiple processor architectures! With UWP, x86, AMD64 and ARM code is all written in the same high-level language with [Visual Studio 2015 or later’s] interpreter translating the code to run on the different processor architectures for you!

I started coding Windows 10 UWP apps in November 2015 after having done a little bit of C# coding for Windows Phone 8.1 using the Microsoft Silverlight framework beforehand. Below is a video I recorded in November 2015 after having started coding a Windows 10 UWP app using C# and Visual Studio 2015 for a couple of hours and expressing my excitement and awe at the versatility of the platform.

The app I wrote in C# UWP was a helpdesk app for my school, designed to allow staff members to report IT problems from any Windows 10 device that the app was installed on. A video demonstration of the app recorded for my A level project back on February 10th 2016 can be seen below.

At the time I really enjoyed coding this as I felt that I was coding an app for a cutting-edge platform, which I was! It’s unfortunate that Microsoft was unable to really make Windows 10 a success on mobile devices in the same way that Windows Phone 8 and 8.1 had been. Had they been able to do so then UWP apps would have been much more common and potentially a lot more exciting.

The code for writing UWP apps was a little different from the C# that I had used previously, but I was able to pick it up quickly. I also had to code the front-end (UI) as well using a language called XAML which is a little like a cross between HTML and CSS given that XAML is a mark-up language but also contains styling properties. XAML is also used to code the front-end of Windows Presentation Foundation (WPF) desktop apps too – more on that later.

Windows Forms and early C# programming

I started learning C# in early 2014 whilst I was in Year 11. At the time I was interested in completing a Microsoft MTA (Microsoft Technology Associate) or MCSD (Microsoft Certified Software Developer) qualification in C# programming which I had the opportunity to do whilst I was studying at Wymondham High. I bought the Microsoft Visual C# 2013 Step-by-Step book which you can see in the feature image of this article at the same kind of time to help teach me C#. Completing the exercises in the book gave me a good grasp on the basics of C# programming. Whilst I did complete the exercises and learn the language, I never actually did either of the Microsoft qualifications. My A level Computer Science course taught me how to code in Python in Year 12 and then of course in Year 13 I used C# to create my final piece. I was also first experimenting with HTML and CSS to code websites at this time too!

The C# 2013 Step-by-Step book was written to go hand-in-hand with Visual Studio 2013 which I had and was the latest version of Visual Studio available when I bought the book. The book focuses mainly on creating Windows Store apps for Windows 8 and 8.1 using C# using the Runtime framework mentioned earlier. The Windows Store App platform is of course obsolete with Windows 10 (it was replaced with Windows 10 UWP apps), but the principles behind the code still remains relevant today and there are plenty of code examples for coding Windows Forms and Windows Presentation Format (WPF) apps for readers who didn’t have Windows 8.1 or Visual Studio 2013 that are also perfectly relevant today for Windows 10 and Visual Studio 2017.

The first C# program I wrote independently was a program to back-up the source code for various websites that I was working on at the time and it did this by copying directories containing the files from one hard drive to another. It featured checking to ensure that the appropriate directories existed and that if they didn’t, the user [myself] would be alerted that the directories didn’t exist and would have the option to be able to create them. It was basic, but an introduction to a lovely programming language and the start of a hobby – and possibly career?

The source code for my very first independently-written C# program displayed in Visual Studio 2013.

When I started A level Graphic Communication in September 2014, I wrote a similar program to back-up my project work which I stored on Adobe Creative Cloud. This program used very similar source code to the Website Backup one I had written months earlier and also featured the ability to set locations as defaults and check that directories exist before copying, but I do recall it also being multi-threaded which was essential for being able to quickly copy large amounts of data. I still have the executable file (but unfortunately not the source code) and the program can be seen running below!

The backup program I wrote in C# to backup my A level Graphic Communication project work.

Come to think of it, I now save all of my university project work in Creative Cloud so I could still use this app to back-up all of my university project work!

Those are a few examples of programs I wrote in C#.

Why look at C# and coding desktop apps again when I do web development at the moment?

Since September 2017 when I began university all of my coding projects have had a strong emphasis on web development, however I feel that it is good to occasionally code for other platforms to broaden subject knowledge and to keep my skills in other languages fresh and up-to-date.

There is such a thing as a full-stack developer who is somebody that can code for desktop, web, mobile and even databases, both front-end (UI) and back-end (mechanics). At the moment I’d say that my speciality is definitely in web development and coding for the web, however before I started university my interest was definitely in desktop and mobile app development with C#. My experience with web design so far has mainly been in front-end design with making things look pretty and display correctly across a range of devices using the likes of CSS and JavaScript. My experience with desktop and mobile app coding has been in the back-end with ensuring that the software works as well as it can, then focusing on designing the front-end using XAML (in the case of UWP and WPF Windows apps). Putting databases aside, if I can combine my front-end and back-end skills on desktop, mobile and web platforms then I am closing to becoming a full-stack developer which could potentially open up more job opportunities for me. It’s always good to have options!

It’s always good to have a variety of languages under your belt too as it can increase the number of projects that you can do – for example I can use HTML, CSS and JavaScript to create websites such as Elebase and Storehouse Online, but I can’t use these languages really to code desktop and mobile apps. However, since I know C#, I can code Windows desktop and mobile apps in that language and even have the ability to port them to other platforms such as macOS.

With it being over two years since I last looked at C#, I thought it would be good to get back into it and give myself a new challenge!

Storehouse Article Creator

Creating and now maintaining the Storehouse website has become a big part of my life. It took my friend Callum Brown and I around two solid days of coding to hand-code 17 articles for Storehouse Online. Even before we had started to code the site, I had envisaged making the process easier by creating some sort of tool (in C#) to ‘inject’ the article content into a HTML file and then somehow be able to save the file and upload it to the server to display online. This never materialised because I simply did not have the time or the completed HTML, CSS and JavaScript code for the Storehouse website to be able to complete this.

Then the Easter holidays and the Storehouse team’s attention turning to Issue 17 happened and the idea was reborn. What if I could make a tool that could run on Windows and macOS desktops that would allow people to quickly and easily create articles for Storehouse Online without them having to write a single line of code? It could be like a text editor and the user could click ‘Save’ and a folder with all of the appropriate files and folders would be generated and could be uploaded to the server for viewing online.

The benefits are obvious:

  • Much-reduced time in creating articles, meaning Storehouse Online can have more articles increasing readership and user engagement.
  • More people can create articles meaning that workloads can be spread across multiple people rather than just those who can code and know the Storebase code.
  • Opens up the possibility of publishing an article to Storehouse Online to more people.

With the Easter break being 3 weeks long and me wanting to spend some of that time relaxing and doing things other than working on Elebase 4, I decided to have a go at making my ‘article creator’ a reality.

Writing Storehouse Article Creator

Writing the software was easier than I had anticipated actually!

How does it work?

The interface of the software works by requesting that the user types in certain bits of information into labelled text boxes, namely:

  • The article title
  • The article author (and whether or not the article is an ‘interview’ piece or not)
  • The location of the hero image (optional)
  • The URL of a YouTube video to use as the hero image (optional)
  • The article content
  • The first name of the author
  • Social media links of the author

The program takes this information to generate all of the appropriate HTML, CSS and JavaScript files needed to create an article page for Storehouse Online. The final result is something that looks like this:

A fully-functioning article with custom images and text! With no code-writing at all! It’s mobile-compatible too because the software also generates the appropriate CSS and JavaScript files to make it mobile responsive. To code this article it could take somebody who is not proficient in coding up to around 30 minutes, but it took a matter of seconds to generate this article using my app.

Essentially, the software takes the information that the user provides and generates a HTML file using this information. When the user clicks on the ‘Generate All’ button it creates a directory called ‘export’ in the same directory that the *.exe file for the Article Creator is located and in there are all of the appropriate HTML, CSS, JavaScript and image files needed to display the article correctly. These files can be uploaded to the Storehouse web server and the article will display correctly online too.

The HTML file is generated by concatenating strings and saving this string as a HTML file. The CSS, JavaScript and image files are not generated by the app, rather they are pre-written and embedded into the app’s source code by importing each file as a Resource into Visual Studio and then telling Visual Studio to handle these Resources as files to embed into the *.exe file of the app when the app is compiled. When the user clicks on ‘Generate All’, these files are copied from the app’s Resources to the appropriate directories. This saves time and effort and updating the files is easy as I can just import them into Visual Studio and recompile the app, but it does make the program slightly larger.

View the latest beta version in action on Windows 10!

The Microsoft .NET Framework

Doing mainly web development on my degree course, I haven’t had the opportunity to talk about or explain the Microsoft .NET Framework. Essentially all Visual C#, C++ and Visual Basic .NET applications made on any version of Visual Studio since Visual Studio .NET (also called ‘Visual Studio 2002’) run on the Microsoft .NET Framework which is a software framework that allows applications written in these languages to interact with the Windows operating system.

The benefit of using the .NET framework is that it works across a variety of Windows versions, starting with 98 and going right up to Windows 10 and controls such as text boxes, labels, check boxes and so on are compatible and displayed on all. Code written for .NET Framework 1.0 on Visual Studio .NET running on Windows 98 is generally still compatible today with Windows 10 because .NET Framework versions are cumulative, meaning that the later versions also include support for the older ones. The oldest version of .NET Framework that an app written in Visual Studio 2017 (which is the latest version of Visual Studio at the time of writing) can target is .NET Framework 3.5 which works on Windows XP and later. If you use an older version of Visual Studio, you can target apps at older versions of .NET Framework meaning that you could write software today that could be compatible with operating systems as old as Windows 98 or Windows 2000 as long as the appropriate .NET Framework is installed.

When coding Visual C#, C++ or Visual Basic .NET apps in Visual Studio your apps have to use the .NET Framework – that’s just how it works! The only way to write a C# or C++ app in Visual Studio .NET and later that doesn’t use .NET Framework is to write a console application which doesn’t have a GUI. The only way to write a Visual C#, C++ or Visual Basic .NET app without using the .NET Framework is to write it in a really old version of Visual Studio, such as Visual Studio 6.0 which was released in 1998 – 20 years ago! The code for all three languages changed drastically when .NET Framework was introduced in 2002 so code for pre-.NET C#, C++ and Visual Basic is very different to the modern interpretations of these languages and generally not compatible.

The disadvantage of using .NET Framework to build apps is that unfortunately apps are not cross-platform, meaning that generally they only work on Windows. This is because .NET Framework is not available for other operating systems (it will never be compatible with them). There are ways to emulate .NET Framework and the Windows sub-system on Linux operating systems and macOS using third-party tools which means that some .NET Framework-based apps can run on OSes besides Windows (more on that later), but there are unfortunately limitations.

Windows Forms vs Windows Presentation Foundation (WPF)

There are two main design systems for .NET apps. Windows Forms is the older version and WPF is the newer version. There aren’t really that many differences between the two and they’re all to do with how the front-end is coded, so generally the back-end C# code is very similar with only some minor differences between the two.

Windows Forms app use the target language (C#, C++ or Visual Basic .NET) to code the GUI which works well but is quite limited in terms of skinning and general appearance tweaks besides what the language can offer. This is very similar to the kind of thing that developers would have done when coding their GUIs before the days of Visual Studio, which of course allows a user to drag-and-drop elements onto a canvas and the GUI code is written for you and is not accessible by default. It’s compatible across a wide range of .NET Frameworks and can run in emulations on operating systems such as Linux and macOS with little-to-no compatibility issues.

WPF apps use a language called XAML (pronounced ‘zam-all’) to code the GUI which is like a cross between HTML and CSS given that it is a mark-up and styling language. This is the same language used to code GUIs in Windows Phone and Windows 10 Mobile apps. It allows more flexibility in styling and design and includes many features such as spell checking in text fields and the ability to play media files without add-ons, but unfortunately it is not compatible with any operating system besides those that run .NET Framework natively (Windows, basically).

I’ll be coding my app using WPF since it is newer and more flexible, but I’ll also be making a Windows Forms version for compatibility with macOS which will have to be developed separately. Luckily, the C# code behind the program is very similar on each platform.

Generating HTML files from strings in C# text boxes.

By having a TextBox control that the user types into it, it’s possible to take the contents of the text that that user types into the text as a string and then simply concatenate a ‘<p>’ string to the beginning of the TextBox text string and a ‘</p>’ string to the end. Then it is possible to write this string to a HTML file so that it can be display in a web browser.

Example: if a user typed ‘My name is Jason’ into the TextBox control, the generated string would be: <p>My name is Jason</p>.

This way, the user can literally type (or copy and paste) an article into the TextBox in the app, click ‘Generate’ and have a generated HTML file without the need to actually write any HTML code.

The head tags that the user doesn’t ever need to edit are also strings in the program code that are concatenated to the big string that eventually forms the whole article. The challenge with trying to write code in a string in C# is that line breaks and speech marks (” “) have to be taken into account. In C# (and other languages too), a new line in a string is specified by using a “\n” switch in your string and speech marks are specified by using a \ before the first and last speech marks in the string which tells the interpreter to ignore the special characters between these backslashes. For example, a string containing: “My name is \”Hello\” and I write software” will produce ‘My name is “Jason” and I write software’. You can also use the @ symbol before a string is defined which tells the interpreter to interpret the string as a ‘literal’ (or a verbatim string) meaning that it interprets the string with complete disregard for special characters, meaning that there is no need to use the backslashes.

It was of course important to be able to have speech marks in the strings because HTML code uses speech marks to define sources, for example to define a script source in HTML:

script src="js/jquery-3.2.1.min.js"></script>

The location of the script is in speech marks.

In my program, the HTML head information starting with ” up the end of the Metadata tags is stored in a string, written like:

//Doctype-Metatags
string htmlHead ="<!DOCTYPE html>\n\n<!--Code generated with Storehouse Article Generator (Issue 16, Storebase 5.5.5, March 2018)-->\n\n<html lang=\"en\" xmlns =\"http://www.w3.org/1999/xhtml\">\n\n<head>\n<meta name=\"viewport\" content =\"width=device-width, initial-scale=1.0\">\n<meta charset=\"utf-8\";

 

C# shares a lot of common code syntax with other C-based languages such as C++, Java and even JavaScript. You can see that comments are exactly the same in each language, however one big difference between C# and JavaScript (which I have been using a lot over the past six months or so) is that in C# data types usually need to be defined whereas JavaScript (and Python) often are able to intelligently determine the data type based on the contents of the variable. You’ll note above that I had to define the variable ‘htmlHead’ as a string in C# whereas in JavaScript you could simply type ‘var htmlHead = “contents”‘ and JavaScript will know that this variable is likely a string because it contains text and speech marks.

Each section of the HTML document that needed to go together to produce the whole document is saved in a separate string which are all concatenated to produce the final HTML document. The strings that are concatenated to produce the final HTML document are:

String: ‘generatedHtmlTop’

The string ‘generatedHtmlTop’ is a concatenation of the following sub-strings.

  • htmlHead: HTML header information up to the end of the Metadata tags
  • htmlTitle: HTML page information (to title case, meaning that Each Letter Is Capitalised – like that!)
  • htmlScripts: HTML linked scripts, e.g. references to linked JavaScript and CSS files
  • htmlPreload: HTML preloader scripts (these play a big part on the Storehouse website in improving page performance, especially on mobile devices)
  • htmlMenuScript: jQuery/JavaScript inline HTML code to hide the hamburger mode by default
  • htmlHeader: HTML markup code for the website header including the header image
  • htmlHeroContainer: HTML container that the hero image or video sits in

String: ‘generatedArticle’

The string ‘generatedArticle’ is a concatenation of the following sub-strings.

  • titleText: The contents of the text in the text box containing the article title
  • articleLineBreak: A string containing ‘\n<br />\n<br />’ to add a two line breaks on the line below the last line (for the article display)
  • lineBreak: A string containing ‘\n’ to add a literal line break to the file
  • interviewText: The contents of the text in the author’s name box
  • articleLineBreak
  • lineBreak
  • articleTextLined: A string to replace any line breaks in the contents of the Article Text Box (where the user types the article) with the ‘singleArticleLineBreak’ string, which is ‘\n<br />\n’ which is a line break as registered by HTML
  • articleLineBreak
  • lineBreak
  • seeMoreWorkText: A string containing the contents of the ‘Author’s first name’ box and ‘See more of <author’s> work at’
  • singleArticleLineBreak: A string containing  ‘\n<br />\n’ which is a line break as registered by HTML
  • socialText: A string containing the contents of the ‘Social Media Links’ text box
  • articleLineBreak
  • lineBreak

The code for the ‘articleTextLined’ string is as follows:

//Define HTML line break
string singleArticleLineBreak = "\n<br/>\n";

//Replace link breaks in articles with <br/> tags.
string articleTextLined = articleText.Replace(System.Environment.NewLine, singleArticleLineBreak);

This code is critical as it replaces new lines in the article text box with the HTML ‘<br />’ tag which means that new lines are displayed correctly when the page is saved as a HTML document. Without it the articles won’t display correctly.

String: ‘generatedHtmlBottom’

The string ‘generatedHtmlBottom’ is a concatenation of the following sub-strings:

  • htmlComments: A string containing all of the HTML code needed to display the DisQus comments
  • htmlFixedMenu: A string containing all of the HTML code needed to display the fixed menu icon and hamburger menu which is visible when the website is running in responsive mode.

The complete code for generating the HTML article then is therefore:

//Generated HTML

//--HTML Head & Container--//
string generatedHtmlTop = htmlHead + htmlTitle + htmlScripts + htmlPreload + htmlMenuScript + htmlHeader + htmlHeroContainer;

//--Article--//
string generatedArticle = titleText + articleLineBreak + lineBreak + interviewText + articleLineBreak + lineBreak + articleTextLined + articleLineBreak + lineBreak + seeMoreWorkText + singleArticleLineBreak + lineBreak + socialText + articleLineBreak + lineBreak;

//--HTML Comments, Footer & Responsive Navigation--//
string generatedHtmlBottom = htmlComments + htmlFixedMenu;

//--Generated HTML Output--//
string generatedOutput = generatedHtmlTop + generatedArticle + generatedHtmlBottom;

Meaning that the string ‘generatedOutput’ contains the entire HTML article that can be written to a HTML document.

Selecting a hero image

The hero image appears at the top of the page on each article. The way that the app places the hero image into the article is to allow the user to select a file and then copy that file to the appropriate directory within the ‘export’ folder that the app makes (this folder contains all of the critical files and directories required for generated articles to display correctly) and rename it.

When the user clicks on the ‘Browse for Hero’ button the ‘browseForHero’ function is called.

private void browseHero_Click(object sender, EventArgs e)
    {
        browseForHero();
    }

Functions in C#

As you can see from the code above, executing or calling a function is done in exactly the same way as it is in JavaScript and several other C-based languags, but writing them is slightly different. In C#, functions are written in Public Voids meaning that they can be accessed from any part of the program. Button clicks on the other hand are written in Private Voids meaning that they are only accessible to the control that they are referencing (in the case above, the button).

Below is a sample C# function.

public void showMessage() //function to show a message box
    {
        MessageBox.Show("This code is inside a function!");
    }

Running ‘showMessage();’ will display the message box that is defined inside this function. To write the same function in JavaScript you’d simply replace ‘public void’ with ‘function’ (and since ‘MessageBox’ is not a component of JavaScript, you’d replace ‘MessageBox.Show’ with ‘window.alert’).

I wrote the program using functions for the same reasons I use functions in other languages:

  • Save repetition of code
  • Easier to maintain code as only one section of code needs to be maintained and anything that links to it is also updated
  • The same function can be called from multiple buttons or sources

Back to selecting a hero

Using the ‘OpenFileDialog’ in .NET Framework, which this C# app is built upon, the user is presented with the typical ‘Open File’ dialog box that many Windows programs have.

To display this dialog, the following code is used:

public void browseForHero() //function to browse for hero image
    {
        OpenFileDialog openHero = new OpenFileDialog();
        openHero.Filter = "JPEG images|*.jpg";
        openHero.Title = "Select an image file";

A new ‘OpenFileDialog’ called ‘openHero’ is initialised and its filter is set to look for JPEG images (*.jpg). This means that only JPEG files can be used as a hero image. The title of the OpenFileDialog is set to ‘Select an image file’.

When the user clicks on ‘Open’, that is interpreted by C# as a boolean and it returns true. When the user clicks on ‘Cancel’ or closes the dialog, that is returned as false. The boolean variable is ‘return’ and the follow if statement executes if it returns true.

Nullable result = openHero.ShowDialog();

        if (result == true)
        {
            string heroPath = openHero.FileName;
            string subDir = interviewContent.Text.Replace(" ", "-"); //replace the space in the author name with a dash
            string heroExportLocation = globals.currentPath + "\\export\\images\\submissions\\issue16" + "\\" + subDir;
            string heroName = heroExportLocation + "\\" + subDir + "-hero.jpg";

            if (Directory.Exists(heroExportLocation))
            {
                File.Copy(heroPath, heroName, true);
                heroPathText.Text = heroPath;
            }
            else
            {
                Directory.CreateDirectory(System.IO.Path.Combine(globals.currentPath, "export", "images", "submissions", "issue16", subDir)); //create directory to save hero image in
                File.Copy(heroPath, heroName, true);
                heroPathText.Text = heroPath;
            }
        }

If the user selects a file and opens it, four variables are created. The string ‘heroPath’ is created and used to store the name of the file that the user selects from the OpenFileDialog. The string ‘subDir’ is used several times across the course of the app and is always the name of the author in the ‘Author’s Name’ field on the app with any spaces removed and replaced with a dash ( – ). The author’s name is always lowercase because it is impossible to type uppercase letters into the text box on the app since the text box has been set in XAML code to convert all keystrokes to lowercase letters. In the Storehouse Online file system, the images are always stored in a folder called ‘images\submissions\issue16\firstname-lastname’ (where ‘firstname is the author’s first name and ‘lastname’ the last). The string ‘heroExportLocation’ is this file path and is the location that the file is going to be copied to. The string ‘heroName’ simply concatenates the string ‘-hero.jpg’ to the end of the full file path (including the name), meaning that the name of the image is ‘firstname-lastname-hero.jpg’.

Before attempting to copy the image, the function has to check to see if the folder it needs to copy the image to exists. Using the System.IO method in C#, the app can access the files and folders on Windows. The easiest way to implement this is to simply add ‘Using System.IO;’ to the top of the C# file with the other libraries.

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;
using System.Threading;
using System.Resources;
using System.Data;
using Microsoft.Win32;

There are also a lot of other libraries that the app needs to use. All of them above System.IO are default. By referencing System.IO here, it saves having to write out full code, for example ‘Directory’ and ‘File’ are dependant on the System.IO library, so by referencing System.IO I don’t have to type ‘System.IO.Directory’ or ‘System.IO.File’ every time I want to use these, instead I can just type ‘Directory’ and ‘File’.

The function checks to see if the directory specified in the ‘htmlExportLocation’ string variable exists and if it does then it copies the image file from its original location to the new location and renames it. It also displays the image path of the original location in a label on the app so the user can see that an image has been specified for use in the hero. If the directory does not exist then it creates it and copies the file and renames it.

The code to actually inject the hero image into the HTML code so that when the HTML file is created the hero image is displayed in located in the ‘generateHTML’ function.

//--HERO IMAGE, SLIDESHOW OR VIDEO--//

//The hero image may be an image pre-defined by the user or it may be the default if no header image has been selected

string htmlHeroContainer = ""; //initialise the htmlHeroContainer string to concacentate/inject into HTML markup.

//Determine file name of specified hero image
string subDir = interviewContent.Text.Replace(" ", "-"); //replace the space in the author name with a dash           
string specifiedHero = "src =\"../../images/submissions/issue16/" + subDir + "/" + subDir + "-hero.jpg\""; //HTML markup for specified hero image location

string specifiedHeroDir = globals.currentPath + "\\export\\images\\submissions\\issue16" + "\\" + subDir + "\\" + subDir + "-hero.jpg"; //file path (and name) of specified hero to check against
if (File.Exists(specifiedHeroDir))
{
    //Container, Hero image (SPECIFIED static image only) & Text Container
    htmlHeroContainer = "\n\n\n

\n

\n\n

\n\n\n

\n”; } else { //Container, Hero image (DEFAULT static image only) & Text Container htmlHeroContainer = “\n\n\n

\n

\n\n

\n\n\n

\n”; }

Essentially what is happening here is that a string called ‘subDir’ is defined and again it really just specifies the name of the sub-directory to store the hero image in. The path of that hero image that the user selected earlier and is now inside that folder is then converted into a string that HTML can read and stored in the string ‘specifiedHero’. The Article Creator will then check to see if the user has selected a hero image to use by checking to see if a file exists that matches the path of ‘specifiedHeroDir’. If there is a file that matches that path, then the string that was initialised earlier (‘htmlHeroContainer’) is populated with the HTML markup code to insert the hero image into the HTML file.

If the file is not found, then the default hero image is used instead. This will make a little more sense as you read more of the article and discover that the ‘generateHTML’ function is usually called with another function called ‘generateImages’ that copies several images from the app’s Resources to the appropriate image folders – one of these images is called ‘demo.jpg’ and is the demo hero image that the program uses if the app cannot find a user-specified image to use.

Using a YouTube video as the hero image

If the user checks the box that says ‘YouTube Video’ and pastes a YouTube video link into the text box next to it, then a YouTube video can be used as the hero image.

The code to enable this is all in the ‘generateHTML’ function, broken down below.

//Determine if a YouTube video is to be used in the hero
string youtubeURL = @" src=""" + youtubeContent.Text.Replace("watch?v=", "embed/") + @"?autoplay=1""" + " frameborder=\"0\" "; //URL of video in correct embed format and autoplay switch applied
string youtubeHTML = ""; //initialise this variable

Firstly, a string called ‘youtubeURL’ is created which modifies the URL that the user provides into the embed format that YouTube gives you. By getting the program to change the URL, the user can simply copy and paste a standard YouTube video link into the text box without having to manually fish the link from the embed code that YouTube provides. The string replaces the ‘watch?v=’ text in the YouTube video URL with ’embed/’ which is used in the embed URLs and it also adds the ‘?autoplay=1’ text to the URL which means that the video will automatically play.

Then a string called ‘youtubeHTML’ is initialised (which means creating an empty variable for modification later) and the following if statement is executed.

if (youtubeCheck.IsChecked == true && youtubeContent.Text != "")
{
    if (youtubeURL.Contains("youtube.com") || (youtubeURL.Contains("youtu.be"))) //check to see if video is from YouTube
    {
        youtubeHTML = "\n"; htmlHeroContainer = "\n\n\n

\n

\n

” + youtubeHTML + “\n

\n

\n\n\n

\n”; } else { MessageBox.Show(“The URL of the video is not valid. It must be a YouTube video.”); } }

If the check box for a ‘YouTube Video’ hero is selected on the app and there is text in the YouTube video URL field, then the code continues, otherwise the app assumes that an image hero is going to be used instead. Then the nested if statement is executed and if the URL of the video in the text box contains ‘youtube.com’ or ‘youtu.be’, then it is thought that the video is from YouTube and thus can be embedded using the code in the ‘youtubeHTML’ string which was initialised earlier but is now populated. This string is then inserted into the ‘htmlHeroContainer’ string meaning that when the file is saved as a HTML file the video will be displayed. If the URL does not include ‘youtube.com’ or ‘youtu.be’ then a message box explaining that the URL is not valid.

Global variables in C#

Generally speaking, global variables are poor programming practice as their values can change throughout the course of the program’s execution without you knowing and create problems, so C# generally makes it difficult to create global variables which discourages you from using them. The closest thing that you can do in C# to creating global variables is create a Public Static Class (‘public’ meaning that is accessible to the whole program and ‘static’ meaning that the variables are always present – never destroyed) and define variables in there.

Below is a sample:

public static class globals //global variables
    {
        public static int imageCounter = 01; // number of images pasted into the article text
        public static string currentPath = Directory.GetCurrentDirectory(); //CWD
    }

To be able to reference these variables in other parts of the program, add ‘globals.’ to the beginning of the variable name:

string totalNumber = globals.imageCounter.ToString();

The code above takes the ‘global’ variable ‘imageCounter’, converts it from an integer to a string (done by adding the ‘.ToString()’ method) and then saves it in the variable ‘totalNumber’.

The Public Static Class shown above is used in this app to define two variables that need to be accessed throughout the entire program.

Inserting images

Inserting images is done by essentially copying the image file that the user wants to copy into the ‘export\images’ folder and then in there several sub-directories are created, namely ‘submissions’, ‘issue16’ and then a sub-directory called the name of the author (taken from the Author’s Name field in the app) with a dash separating out the first and last name. The image file that the user selected is then renamed from whatever it was originally called to ‘firstname-lastname-01.jpg’, where ‘firstname’ is the author’s first name, ‘lastname’ is the author’s last name and ’01’ is the number of images in that folder.

To begin with, when the Insert Image button is clicked, an ‘OpenFileDialog’ appears just like it did when inserting the hero image. The OpenFileDialog is initialised as ‘openImage’ and its filter is set to *.jpg images, meaning that only JPEG images can be selected and thus inserted. Once the user has selected a file to open, the following code is executed.

if (result == true)
{
    string imagePath = openImage.FileName;
    string subDir = interviewContent.Text.Replace(" ", "-"); //replace the space in the author name with a dash
    string imageExportLocation = globals.currentPath + "\\export\\images\\submissions\\issue16" + "\\" + subDir;
    string imageName = imageExportLocation + "\\" + subDir + "-" + globals.imageCounter.ToString("00") + ".jpg"; //image name will be the name of the author + the value of image counter

    if (Directory.Exists(imageExportLocation))
    {
        File.Copy(imagePath, imageName, true);
    }

    if (!Directory.Exists(imageExportLocation))
    {
        Directory.CreateDirectory(System.IO.Path.Combine(globals.currentPath, "export", "images", "submissions", "issue16", subDir)); //create directory to save hero image in
        File.Copy(imagePath, imageName);
    }

Essentially, selecting an image file to insert and click on ‘Open’ sets the nullable bool result to ‘true’ (just like it did when browsing for a hero image) and several strings are created and two nested if statements are executed.

The string ‘imagePath’ simply contains the name of the file that the user has selected. The string ‘subDir’ is used a lot across the course of the app and just like in the ‘browseForHero’ function, this is the name of the author with the space between their first and last name replaced with a dash. This again will eventually be used to name a folder. The ‘imageExportLocation’ string specifies the directory that the image is going to be copied to – it’s essentially ‘export\images\submissions\issue16\firstname-lastname’ (where ‘firstname’ is the author’s first name and ‘lastname’ is their last). The string ‘imageName’ is the full path of the copied image and it also renames the image to ‘firstname-lastname-01.jpg’. It does this by concatenating the string value of the ‘global’ variable mentioned above called ‘imageCounter’ to the end of the string and by adding (“00”) in the ‘ToString()’ method, it will always be a two digit number.

Once all of that has been set, the program checks to see if the directory path stored in ‘imageExportLocation’ exists and if it does it copies the image file from its original location to its new location, always overwriting any existing files in that directory that have the same name. If the directory doesn’t exist, it creates it and copies the file.

The easiest way to make sure that the image is displayed when the HTML file is generated is to literally add the HTML code for the image into the text box, which will be saved when the HTML file is written. This does mean that the user will see the code, but as long as they don’t edit it then it will work perfectly. The user still doesn’t have to write any code to make the article, it’s just that now they will be able to see a little bit of it.

To add the image code into the article, the following code is used:

//Inject image location into the HTML editor (the user will see this code)

imageName = "src =\"../../images/submissions/issue16/" + subDir + "/" + subDir + "-" + globals.imageCounter.ToString("00") + @".jpg"""; //change the imageName string to a format that can be injected into and read by HTML (remove full file path)

string injectImageLocation = "
\n
\n\n
\n
";

int cursorPosition = articleContent.SelectionStart;

articleContent.Text = articleContent.Text.Insert(cursorPosition, injectImageLocation); //injectable directory of image that can be read by HTML and placed where cursor is 

globals.imageCounter = ++globals.imageCounter; //increment the image counter int by 1

What’s happening here is that the value of ‘imageName’ is changed to a URL that can be used in HTML, so it changed to ‘../../images/submissions/issue16/firstname-lastname/firstname-lastname-01.jpg’. The @ symbol before the last part of the string means that the string is interpreted as a literal (or a verbatim) meaning that the speech marks in the string can be read without the need to use a \ to tell the C# interpreter to ignore the special characters in the string. Instead of those speech marks being read as special characters, they are instead read as part of the string just like any other character.

A string called ‘injectImageLocation’ is then created and this string contains the HTML code that needs to be written in order to display the image. It adds the ‘

An integer variable called ‘cursorPosition’ takes the position of the cursor in the article text box because I assume that the user will click on the area of the text box that they want to insert the image into. The string ‘injectImageLocation’ is then placed into the text box at the cursor position and that inserts all of the code needed to place an image in the article!

Finally, the value of the ‘global’ variable ‘imageCounter’ is incremented by 1 so that if another image is added, it will have ‘-02.jpg’ at the end of the file name, and the following would have ‘-03.jpg’ and so on. Theoretically up to 100 images can be added in an article with the 100th image having ‘-00.jpg’ at the end of the file name before the 101st image would be called ‘-01.jpg’ again and overwrite the first image. I don’t think any article will have this many images in it so that’s OK.

Inserting headings, bold text and italic text

These are all added in a similar method, essentially the relevant HTML tags are inserted into the article text box and the user types between the tags to make the text bold, italic or place it in a heading.

The code for the italics injection is below, but the same applies to the h1 Heading, h2 Heading, h3 Heading and Bold buttons too.

private void italicsButton_Click(object sender, EventArgs e)
    {
        string injectItalics = "" + articleContent.SelectedText + "";

        int cursorPosition = articleContent.SelectionStart;
        articleContent.Text = articleContent.Text.Insert(cursorPosition, injectItalics);
    }

The string ‘injectItalics’ concatenates an ‘i’ to beginning of the selected text in the article text box and an ‘/i’ to the end. The ‘selectedText’ method means that a user can highlight or word or block of text in the textbox, press the button to insert an italic and the HTML italics tags would be added to the beginning and end of that text. Again, the user can see these tags, but if they don’t modify the tags then it will work perfectly fine when the HTML file is generated.

Like the code to insert an image, clicking on an area inside the text box and pressing the italics button will also insert the tags at the point where the cursor is and the user can type text between the tags.

Writing the HTML file

Using .NET Framework’s ‘SaveFileDialog’, the user is able to save files to a specified location using a friendly and rather typical-looking ‘Save As’ dialog.

The ‘Save As’ dialog open in the Storehouse Article Creator.

The save process is fairly complex in the Storehouse Article Creator. Generating the HTML file from the string ‘generatedOutput’ is easy enough, but there are several other tasks that must be completed:

  • The program must create a folder in the current working directory (CWD) called ‘export’ – but first check to see if this folder already exists! If it does, then don’t recreate or overwrite it.
  • Then it must create several folders inside the ‘export’ folder, namely:
    • articles\issue16
    • css
    • images\submissions\issue16
    • js
  • If any of those folders already exist, it must not overwrite them.
  • Copy all of the *.css files from its Resources into the ‘css’ folder, copy all of the *.js files from its Resources into the ‘js’ folder and copy the ‘favicon.ico’, ‘logo_black.png’ and ‘menu.png’ image files from its Resources into the ‘images’ folder. Then it must copy the ‘demo.jpg’ file from its resources into the ‘images\submissions\issue16’ folder – this is the demo hero image that is used if the user does not select their own hero image or a YouTube video to use as the hero image of the article.
  • Save the *.html file into the ‘articles\issue16’ folder and use the naming format ‘author-name-issue16.html’ by default.

The code to accomplish this is quite lengthy and relies on five different functions being activated at the same time to do this. These functions are:

  • createExportDir: Creates the ‘export’ directory and all of the sub-directories inside it (also checks to see if they already exist and deals with any errors)
  • generateImages: Saves the images from the app’s Resources into the ‘images’ folder
  • generateCSS: Saves the CSS files from the app’s Resources into the ‘css’ folder
  • generateJS: Saves the JavaScript scripts from the app’s Resources into the ‘js’ folder
  • generateHTML: Creates the HTML document and opens the ‘Save File Dialog’ to allow the user to save the HTML document.

These functions are called when a button called ‘generateAll’ is clicked:

private void generateAllButton_Click(object sender, EventArgs e)
    {
        createExportDir();
        generateImages();
        generateCSS();
        generateJS();
        generateHTML();
    }

The function to create the export directories (‘createExportDir’) is fairly simple to understand since it’s essentially just an if statement. Here is the code broken down:

public void createExportDir() //function to create export directories
    {
        //Check if a directory called 'export' exists in CWD, if not creare directory and subsequent directories
        if (!Directory.Exists(System.IO.Path.Combine(globals.currentPath, "export")))
        {
            Directory.CreateDirectory(System.IO.Path.Combine(globals.currentPath, "export", "css")); //CSS
            Directory.CreateDirectory(System.IO.Path.Combine(globals.currentPath, "export", "js")); //JavaScript
            Directory.CreateDirectory(System.IO.Path.Combine(globals.currentPath, "export", "images")); //Logo, favicon and menu images
            Directory.CreateDirectory(System.IO.Path.Combine(globals.currentPath, "export", "images", "submissions", "issue16")); //Hero image 
            Directory.CreateDirectory(System.IO.Path.Combine(globals.currentPath, "export", "articles", "issue16")); //HTML
        }

The function is an if statement that checks to see if a directory called ‘export’ exists in the current working directory – the variable ‘currentPath’ which contains the path of the current working directory is a ‘global’ variable (of sort… C# can’t actually do global variables!) and is mentioned earlier in this post. If the directory ‘export’ does not exist, then it creates the directories and names them appropriately. The comments in the code above show you which files go in which directories.

//Only create directories that are missing
        else if (!Directory.Exists(System.IO.Path.Combine(globals.currentPath, "export", "css")))
        {
            Directory.CreateDirectory(System.IO.Path.Combine(globals.currentPath, "export", "css")); //CSS
        }

        if (!Directory.Exists(System.IO.Path.Combine(globals.currentPath, "export", "js")))
        {
            Directory.CreateDirectory(System.IO.Path.Combine(globals.currentPath, "export", "js")); //JavaScript
        }

        if (!Directory.Exists(System.IO.Path.Combine(globals.currentPath, "export", "images")))
        {
            Directory.CreateDirectory(System.IO.Path.Combine(globals.currentPath, "export", "images", "submissions", "issue16")); //Images folder and sub-dirs
        }

        if (!Directory.Exists(System.IO.Path.Combine(globals.currentPath, "export", "articles")))
        {
            Directory.CreateDirectory(System.IO.Path.Combine(globals.currentPath, "export", "articles", "issue16")); //HTML and sub-dirs
        }

    }

If the if statement in the previous half of the function returns false (i.e., the directory ‘export’ already exists), then the program checks to see if the individual directories exist. If they don’t exist, it creates them. If they do exist, the if statement returns false and then it moves onto the next one.

Saving the CSS and JS files from the app’s resources into the appropriate location is also fairly simple. Below is the code to do it for the CSS files:

public void generateCSS() //function to generate CSS (must be called with 'createExportDir')
    {
        string cssExportLocation = (System.IO.Path.Combine(globals.currentPath, "export", "css"));

        //Write CSS files from the resources to the 'export\css' folder
        File.WriteAllText(cssExportLocation + "\\storebase5-5.css", Properties.Resources.storebase5_5);
        File.WriteAllText(cssExportLocation + "\\storebase5-5_article.css", Properties.Resources.storebase5_5_article);
        File.WriteAllText(cssExportLocation + "\\responsive_article.css", Properties.Resources.responsive_article);
        File.WriteAllText(cssExportLocation + "\\responsive_home.css", Properties.Resources.responsive_home);
        File.WriteAllText(cssExportLocation + "\\preloader.css", Properties.Resources.preloader);
    }

Firstly, a string called ‘cssExportLocation’ is defined. The CSS files are saved into the ‘css’ folder inside of the ‘export’ folder, so the Path.Combine method discussed earlier is used to set this directory.

There is no need to check if individual files exist because the ‘File.WriteAllText’ method always overwrites, so if the files already exist they will be overwritten with no exceptions thrown – and if they don’t exist they will be written.

The syntax of the File.WriteAllText method is as follows:

File.WriteAllText(destination, source);

To access files in the app’s Resources, the following syntax is used:

Properties.Resources.NameOfResource

In Visual Studio, each Resource must be given a unique name for this reason.

So, by concatenating the ‘cssExportLocation’ string with the name of the name of the file (two slashes are used to define an absolute file path in C#, e.g. “C:\\Users” is read as ‘C:\Users’ by C#) and using that as the destination and the name of the Resource as the source, the app can write the files from the Resources to the desired location.

This function contains no error-checking whatsoever to save code, so it must be called with ‘createExportDir’ which checks to see if the appropriate directories exist and creates them if they don’t. If you were to run the ‘generateCSS’ function alone it would work perfectly as long as the ‘exports\css’ directory existed, but if it didn’t the program would throw an exception and crash. In the case of my app, since I already wrote a function to check this it was not necessary to write it again and since several functions need to run with the ‘createExportDir’ function for this reason, it saved me having to write the error-checking code several times. Also, this function is typically called as part of a series of functions, meaning that if each of those functions had that error-checking code the app would be needlessly checking to see if the directories existed several times when in practice it only needs to do it once.

The function to generate the JavaScript files is exactly the same because JavaScript files are also text files, however the function to save the images is a little different because the imags are obviously not text files, so instead the ‘File.Save’ method is used which is a little different.

The general syntax of this is:

Source.Save(Destination);

Meaning that the function to save the images looks like this:

public void generateImages() //function to save images from the resources into appropriate directory (must be called with 'createExportDir')
    {
        string imageExportLocation = (System.IO.Path.Combine(globals.currentPath, "export", "images"));

        Properties.Resources.favicon.Save(imageExportLocation + "\\favicon.png");
        Properties.Resources.menu.Save(imageExportLocation + "\\menu.png");
        Properties.Resources.logo_black.Save(imageExportLocation + "\\logo_black.png");
        Properties.Resources.demo.Save(imageExportLocation + "\\submissions\\issue16\\demo.jpg");
    }

Again, Properties.Resources can be used as the source and the destination is the file name concatenated onto the end of the ‘imageExportLocation’ string. Again, this function needs to be run after ‘createExportDir’ for error-checking.

The final function to run to save all files is of course ‘generateHTML’. An example of the code for actually writing HTML code in C# using a lot of string concatenation is mentioned earlier in this post, but the code to save the strings as an HTML file is shown below.

To save the string ‘generatedOutput’ to a HTML file, the SaveFileDialog control is used. As shown in the screenshot earlier, this is the typical ‘Save As’ dialog you see in many Windows programs.

Firstly, a new instance of ‘SaveFileDialog’ called ‘savefile’ is initialised.

//Save file dialog
SaveFileDialog savefile = new SaveFileDialog();

Then the program sets the default save location to ‘export\articles\issue16’ so that the user doesn’t have to worry about saving the HTML file in the correct location. Of course, if the HTML file is not saved in the correct location none of the appropriate CSS, JavaScript and image files will be found and the page won’t look correct.

Although the ‘generateHTML’ function is called with the ‘createExportDir’ function when the user presses on the ‘Generate All’ button, this function does also check to see if the directories exist and creates any that don’t for two reasons:

  • So that regardless of if the directories exist or not, the user will always be saving the HTML file into the correct location. If the program detects that the required directories do not exist, it creates them and then is able to set the default save location to the ‘issue16’ folder inside of the ‘articles’ folder.
  • There is a button on the app that allows the user to just generate the single HTML file without any of the other files. This is helpful if the user wants to update or edit an HTML file and does not need to generate the other files, so by checking to see if the directories exist it can create the other directories anyway to save time in future if the user chooses to eventually generate with all files.

A new string called ‘htmlExportLocation’ is created with contains the ‘export\articles\issue16’ path where the HTML files need to be saved in order to be viewed correctly and then an if statement is run to see if that directory exists. If it does, it sets the ‘InitialDirectory’ (the default save location) as that path and if it doesn’t then it creates all of the appropriate folders and then sets the InitialDirectory as that path.

//Check to see if 'articles\issue16' folder exists and set it as the default save location
string htmlExportLocation = (System.IO.Path.Combine(globals.currentPath, "export", "articles", "issue16"));

if (Directory.Exists(htmlExportLocation))
        {
            savefile.InitialDirectory = htmlExportLocation;
        }
        else
        {
            Directory.CreateDirectory(System.IO.Path.Combine(globals.currentPath, "export", "css")); //make the CSS folder too
            Directory.CreateDirectory(System.IO.Path.Combine(globals.currentPath, "export", "js")); //make the JS folder too
            Directory.CreateDirectory(System.IO.Path.Combine(globals.currentPath, "export", "images", "submissions", "issue16")); //Make the hero image folder too
            Directory.CreateDirectory(System.IO.Path.Combine(globals.currentPath, "export", "articles", "issue16"));
            savefile.InitialDirectory = htmlExportLocation;
        }

Next, the default save name should be in the format of ‘firstname-lastname-issue16.html’ by default which speeds up the creation process by not having to worry about manually naming the files. To do this, a string called ‘htmlDocumentName’ is initialised (meaning it is created as an empty string for use later) and another if statement is run. This time, the if statement checks to see if the text in the ‘Author Name’ field on the app is empty. If it is, then it sets the value of ‘htmlDocumentName’ to ‘article-issue16.html’ (the ‘generic’ file name) and if it isn’t then it sets the value of ‘htmlDocumentName’ to the contents of the field, but replaces any spaces it finds with a dash ( – ) and adding ‘-issue16’ onto the end of the string. The contents of the field is always lowercase because this is set as a property of that TextBox in the XAML code (more on that later), so no code needs to be used to convert the text to lowercase. Finally, the ‘FileName’ property of the ‘savefile’ SaveAsDialog can be set to ‘htmlDocumentName’ meaning that the default name is the contents of that string.

//Set default name ('author name-issue16.html' if applicable, otherwise just 'article-issue16.html')
string htmlDocumentName = ""; //initialise this variable

if (interviewContent.Text == "") //check to see if author name is empty
    {
        htmlDocumentName = "article-issue16.html";
    }
    else
    {
        htmlDocumentName = interviewContent.Text.Replace(" ", "-") + "-issue16.html";
    }

savefile.FileName = htmlDocumentName;

Finally, the file can be written! The filter is set as *.html and *.txt, meaning that the user has the option to save the file as an HTML document or a Text document, but note that Text documents do not render as well because ‘\n’ switches in strings are not interpreted when saving as a Text file. Clicking on the ‘Save’ button in the dialog is interpreted as a boolean value in modern versions of C# such as the version I am using to write this app, so creating a variable called ‘result’ and setting this as a nullable bool to determine if the user has clicked ‘Save’ or not can be used to determine whether or not to write the file.

If the bool returns true, a new StreamWriter called ‘sw’ is initialised and the contents of the ‘htmlDocumentName’ (the default file name) is passed into the StreamWriter and the StreamWriter is then able to write the contents of the ‘generatedOutput’ string (which contains all of the HTML document) to the file.

savefile.Filter = "HTML document (*.html)|*.html|Text document (*.txt)|*.txt|All files (*.*)|*.*";

Nullable result = savefile.ShowDialog();

if (result == true)
        {
            using (StreamWriter sw = new StreamWriter(savefile.FileName))
            sw.WriteLine(generatedOutput);
        }

After that, the HTML file will be in the correct location and will have the correct files in the correct location to be able to display correctly!

Opening a file

The Article Creator can also open HTML files to edit and then save them again.

public void openFile() //function to open HTML file to edit
{
    OpenFileDialog openFile = new OpenFileDialog();
    openFile.Filter = "HTML documents|*.html";
    openFile.Title = "Select an article to edit";

    Nullable result = openFile.ShowDialog();

    if (result == true)
    {
        string filePath = openFile.FileName;
        string fileName = filePath.Substring(filePath.LastIndexOf(@"\")+1); //name of the file that is currently being edited (remove all characters in string of absolute file path before last \ )
        string titleBarText = this.Title + ": Editing file: " + fileName;
        this.Title = titleBarText;

        generateAllButton.IsEnabled = false; //disable 'Generate With All Files' button as only the single HTML file should be saved if a single HTML file is being edited.               
        articleContent.Text = File.ReadAllText(openFile.FileName);
    }
            
}

Just like the ‘browseForHero’ function, the OpenFileDialog is initialised and given a variable name (in this case it’s ‘openFile’). When the user has found an HTML file to open, a string called ‘filePath’ is created which is set to the name of the HTML file that the user opened. Another string called ‘fileName’ is created and this is the full path of the open file, but with all content before the final ‘\’ in the file path removed – for example if a file with a path of ‘C:\Users\Jason\Documents\Website\index.html’ was opened, the contents of ‘fileName’ would be simply ‘index.html’. This string is then displayed in the title bar of the app as it is concatenated onto the end of the next string that is created, called ‘titleBarText’ which contains the name of the app, followed by ‘Editing file: ‘ and then the name of the opened file so that the user can easily see which file is being edited. The ‘Generate All Files’ button is disabled because there is no need to generate all of the files when you are editing just a single HTML file.

Front-end design with XAML

As mentioned several times previously in this article, WPF front-end design is done using a language called XAML. XAML specifies the location of elements such as text boxes, labels and buttons and also their styling. It is possible to write your own XAML code from scratch using Visual Studio’s XAML editor, but the easier way to do it is to use the Visual Studio XAML Designer that writes the appropriate XAML code without you having to code it yourself (sounds a lot like the purpose of my app!)

The XAML Designer in Visual Studio (2017 shown) shows a real-time visual representation of your interface on the left and the XAML code on the right.

Just like in every version of Visual Studio, components that the user can drag onto the application are displayed in the ‘Toolbox’ on the left side of the Visual Studio and the properties of the components that can be modified are shown on the left side, usually underneath the Solution Explorer (which displays all of the files in the project). In Windows Forms apps, modifying the properties edits the C#, C++ or Visual Basic .NET code behind the GUI of the project. This code can be accessed by opening up the ‘form.designer.cs’ (or *.cc for C++ or *.vb for VB.NET) file in Visual Studio (where ‘form’ is the name of the Windows Form). In WPF apps, modifying the properties edits the XAML code behind the interface which is accessible by default in Visual Studio since this code is much easier to edit and sometimes needs to be manually edited if the properties window doesn’t contain the property that the developer wants to edit.

Examples of XAML code

Look at this code for a button:

 

 

The control is defined by typing ‘Button’ and the name by ‘x:Name=”generateButton”‘. The contents of the button (the text inside the button) is set to ‘Generate HTML’, the horizontal alignment set to left, the exact position the button is located on the window (these are coordinates) and the vertical alignment is set to top. The width of the button is 128 pixels and clicking on the button activates ‘click event’ and the C# code located in the ‘generateButton_Click’ function. Finally, the foreground colour is set to white (this is the colour of the text inside the button) and the background colour is set to #FF121212 which is an off-black (interestingly I chose this hue because it is the same colour that YouTube uses for its dark theme!)

It’s as really as simple as that!

All of these properties are editable from C# code, for example ‘IsEnabled’ is a XAML property that every component has to determine if it is active or not. ‘SpellCheck’ is a component of a text box that can be turned on or off using C# code by using the following code.

private void articleContent_TextChanged(object sender, TextChangedEventArgs e)
{
    articleContent.SpellCheck.IsEnabled = true;
}

This C# code is activated whenever the user clicks inside the ‘articleContent’ text box. Each time the user clicks inside that text box, the spell checker is enabled.

Similarly, buttons can be disabled by setting the ‘IsEnabled’ XAML property to false using C# code.

generateAllButton.IsEnabled = false; //disable 'Generate With All Files' button as only the single HTML file should be saved if a single HTML file is being edited.

XAML properties can also be checked using C# code and if certain properties are true then certain code can be executed. Look at the if statement below that will activate code if a check box called ‘youtubeCheck’ is checked and if the text (another XAML property) of the text box is not empty.

if (youtubeCheck.IsChecked == true && youtubeContent.Text != "")
{
    //execute code
}

A little like divs in HTML, XAML components can be placed inside of each other. For example, by default all components are placed inside a XAML ‘Grid’ component which holds all of the components in the interface. The code looks a little like this:

 

 

 

 

 

 

Note that comments in XAML are done in the same format as comments in HTML.

By placing components in ‘Grid’ tags, the components are placed in a XAML grid. Simple!

By default, WPF apps are not scrollable. The developer must manually enclose the XAML components in a ‘ScrollViewer’ component editing the XAML code, which is probably why Visual Studio shows the XAML code by default.

Enclosing all of the XAML code in ScrollViewer tags adds a scrollbar to the right side of the app meaning that the user can scroll up and down it.

That is a very brief overview of how front-end design is done in WPF apps using XAML.

As mentioned earlier, coding Windows Phone 8.1 and Windows 10 UWP apps uses a very similar setup with XAML being the front-end language. Below is a screenshot I took in November 2015 of Visual Studio 2015 displaying the XAML code and design view of a Windows Phone 8.1 app built on the Microsoft Silverlight framework. You can clearly see the grid and components coded in XAML.

Visual Studio 2015 displaying the XAML code and design of a Windows Phone 8.1 app.

Cross-compatibility

The WPF app isn’t compatible with any operating system besides Windows due to the way that WPF apps utilise the .NET Framework. There are several tools out there that can make Windows apps run on a Mac or a Linux-based machine – examples include Wine, Wineskin and Mono. These are all open source and are generally maintained by the communities that wrote them, however none of them have plans to include support for WPF apps in the future. This means that the only version of the app that can run on other operating systems is the Windows Forms version which can run on the older .NET Frameworks that these emulation apps support and has been around for years and years so these tools have been developed to allow these apps to run and have had time to mature. There is a paid emulation tool called ‘Crossover’ that may support WPF apps, but given that it is essentially just a refined version of Wine, I’m not convinced it will.

This does mean that if I want to continue the development of the app for other platforms, I’ll have to continue developing the Windows Forms version of the app. It’s not too much of a deal because the C# code behind the WPF and Windows Forms app is very similar, but it will be more time consuming as time goes on. I actually started developing this project using Windows Forms, but as soon as I wanted to put spell checking into the app and discovered that it’s only possible with WPF apps I switched development to WPF. However, when I discovered that WPF apps can’t run on a Mac, I started developing the Windows Forms version alongside.

macOS and Mac OS X

I used a free program called WineBottler to ‘bottle’ the *.exe file with a load of open-source .NET Framework alternatives (based on a really old version of .NET Framework, mind!) and Windows subsystem emulators into an *.app file that can run on a Mac. WineBottler has an option to ‘bottle itself’ into the *.app file, meaning that the app can run on a Mac that does not have Wine installed – this makes the app accessible to more Mac users and easier to deploy because they don’t also have to download and install Wine.

I don’t own a Mac computer, so instead I run a virtual machine of macOS 10.13 ‘High Sierra’ on my Windows 10 PC inside of VMware Workstation. At the time of writing, High Sierra is the latest version of macOS and it generally works really well in VMware given that it was not designed to run on PC hardware at all. There are some minor bugs, mostly graphics related, and performance issues, but these don’t affect the way that my app seems to run. Using my VM of High Sierra, I used WineBottler to ‘bottle’ the *.exe file and then I transferred the *.app file it created to another VM of High Sierra – only this one didn’t have Wine installed.

 

WineBottler’s app bundle creator options.

The Windows version of the app is under 1MB in size which is absolutely tiny. Unfortunately, because the Mac version has to include .NET Framework and some Windows subsystem files and then a copy of Wine so that the app can run on Macs that don’t have Wine installed, the *.app bundle is usually between 600 and 700MB in size which is considerably larger. It’s not a massive deal but it is of course at least 600 times larger than the Windows version! When zipped using the built-in archiver in High Sierra, the file size is typically halved which makes distribution more manageable.

The results can be seen in the video demonstration of the app running in High Sierra below!

So the usability of the app on a Mac isn’t as good as it is on Windows and what’s interesting is that when the app is run using Wine without bottling it or bundling Wine without the *.app package, it does actually create the ‘export’ folder on the user’s desktop and not inside the *.app package where the *.exe is located. However, this means that the user would need to have Wine installed on their Mac beforehand and would need to know how to run the software in Wine before they could run it.

At the end of the day, although the majority of people who will want to use this program use a Mac, they are generally fairly technically-minded people and I know them all personally. This mean that I could in theory create a VHD (virtual hard disk) of Windows 10, install VirtualBox on their Macs (free!) and then create a virtual machine of Windows 10 for them to use in VirtualBox using that VHD. They could run the Windows version of the app in the virtual machine and that would work so much better for them. You can even set up shared folders between the virtual machine and the host operating system meaning that the exported files could go straight to a folder on their Mac without having to manually copy the files out of the virtual machine. VirtualBox also has the ability to run in ‘seamless mode’ meaning that apps can run without the Windows interface so it looks like they are running on the Mac.

It was really interesting to see the app running on a Mac though!

Using Wine, it was possible to get the Windows Forms version of Article Creator running on macOS 10.13 High Sierra, but it was not as usable as the Windows version.

Linux-based operating systems

I created a virtual machine of Ubuntu 17.10 which is the latest version of Ubuntu at the time of writing and installed Wine and WineTricks (which can be used to resolve some compatibility problems when running .NET apps in Wine) from the Ubuntu Software Store. Unfortunately, it appeared that a Wine extension called ‘wine-mono’ was missing and although I found some instructions on how to install it, it looked complicated and beyond the reach and skill level of the average user. I therefore assumed that providing you could get this app to run on Linux using Wine, it would look and perform similar to how it did on the Mac.

I couldn’t even get the Windows Forms version of my app running under Wine on Ubuntu 17.10 due a missing extension called ‘mono’ which is an open source .NET Framework alternative.

Running the app in a virtual machine of Windows 10 on Linux and macOS

After looking in the virtual machine settings for each of my virtual machines, I found that it was possible to enable VT-X and VT-D hardware virtualisation in VMware virtual machines meaning that it was possible to run a 64-bit virtual machine inside a virtual machine. I first tried installing Windows 10 in a virtual machine inside of VirtualBox on my VMware virtual machine of High Sierra but the performance of VirtualBox on the virtual machine of High Sierra was poor – probably because High Sierra is not designed to run inside of a virtual machine.

I then tried the same on my virtual machine of Ubuntu 17.10 and had much better luck and was able to install a 64-bit version of Windows 10 Pro inside of VirtualBox. I then created a folder on the desktop of the Ubuntu host called ‘VMshare’ and in VirtualBox set this up as a shared folder meaning that the ‘VMshare’ folder is accessible to the host (Ubuntu in this example) and guest (Windows 10) operating systems. This means that the *.exe file for the Article Creator can be placed in the VMshare folder and it will produce the output in the same folder, meaning that the software can be run in the Windows virtual machine and the files it exports are directly accessible on the host operating system so that files don’t need to be manually copied from the virtual machine to the host.

See the video below to see this in action in Ubuntu 17.10.

Also shown in the video is VirtualBox running in ‘seamless mode’ which essentially ‘blends’ the guest operating system into the host. As shown in the video, this makes the app running inside the virtual machine look as if it were really running on Ubuntu!

Article Creator running inside the Windows 10 virtual machine in VirtualBox on Ubuntu 17.10 in ‘seamless mode’. It almost looks like it is running on Ubuntu.

The virtual machine route seems to be a great option for those who want to use the app without having Windows has their main OS. The three disadvantages however are:

  • You must have a copy of Windows to install inside the virtual machine for this to work (a VHD containing the operating system could be circulated but this is potentially not legal)
  • The computer must have a CPU that supports Intel VT-D and VT-X (or AMD equivalent) which means that this idea won’t work on computers with older CPUs
  • The VHD can potentially be gigabytes and gigabytes large (potentially up to size specified when creating the virtual machine!) so there must be available hard drive space

And of course you also must have the virtualisation software installed on your operating system. VirtualBox is free and compatible with macOS, most modern versions of Mac OS X and most popular Linux distributions (such as Ubuntu and Linux Mint), but it might not be compatible with some more obscure operating systems.

Older versions of Windows

Initially the app was targeted at .NET Framework 4.6.1 meaning that the oldest version of Windows that the app can run on is Windows 7 SP1 which was released in 2011. .NET Framework 4.6.1 cannot be installed on any versions of Windows older than this. At the time of writing, Windows 7 SP1 is the oldest operating system that Microsoft still supports and all of the common web browsers still work on it, which means that the app will run on Windows 7 SP1 (providing .NET Framework 4.6.1 has been installed) and the files that it generates can be viewed correctly in browsers that run on this operating system.

I know that there is code in my app that requires at least .NET Framework 4 to function correctly, so I won’t be able to ever re-target the app to use a version older than 4. .NET Framework 4 can be installed on Windows XP SP3 and later, meaning that support for Windows XP SP3 and Vista SP1 can be added if the app is targeted at .NET Framework 4 instead. This may be slightly counter-intuitive since neither of these operating systems are supported by Microsoft anymore and fewer and fewer modern browsers are supporting these older operating systems meaning that the website files that the app generates might be able to be viewed correctly. For example, the final version of Google Chrome that is compatible with Windows XP and Vista is Chrome 49, released on March 2nd 2016 which is over two years ago. But I thought I’d try it anyway, take a look at the video and screenshots below.

As expected, the .NET Framework 4 implementation of the Article Creator did work on Windows XP and Vista, but there is really very little point to running the app on these operating systems since very browsers that can display the files that the app generates still work on these old OSes.

The .NET 4 implementation did run on Windows XP SP3, but it wasn’t very fast and the buttons looked a lot more ‘blocky’.
Unsurprisingly, the 17-year-old Internet Explorer 6 browser did not display the website properly. XP does support up to Internet Explorer 8, but even this browser is 9 years old. Very few modern browsers support XP.
The .NET 4 implementation worked on Windows Vista (SP2) too but again, it has the same problems as XP has in that few modern browsers run on it meaning that viewing the generated files is difficult.

All things considered, the people who will most likely using this will be myself (who uses Windows 10) and the Storehouse editors who generally all have Macs, so support for anything older than Windows 10 really isn’t that important. It was interesting to see how WPF apps function on the older versions of Windows though. The app itself functions fine. but when it comes to viewing the files it generates in a modern browser these older versions of Windows become useless.

Conclusion and thoughts!

Wow! This has been another lengthy and detailed post!

It was great fun creating a C# app and coding back-end again. My university work is mainly about front-end design and usability studies, so it was good to take a step back from that and approach software development from ‘the other side’ – the technical side. The technical side requires thinking extremely logically about how certain tasks can be achieved and the best way to do them. It’s something that I used to be good at and it seems I still am!

This little project of mine has given me an opportunity to:

  • Refresh my C# skills
  • Take a break from web design and coding for the web and think about coding for another application (desktop)
  • Learn to write a WPF app (before I had only used Windows Forms and Windows 10 UWP – and a little bit of Windows Phone 8.1 coding)
  • Enable me to think about how an app actually works and how to avoid possible crashes and errors
  • Consider how to make an app cross-compatible to make it useful for a wider audience and understand what limits some apps from being cross-compatible
  • Consider why some platforms do not need to be worried about when trying to make an app cross-compatible
  • Possibly improve my JavaScript skills (since C# and JavaScript share a lot of common code and ideas)
  • Above all, create an app that will myself and others a lot of time and effort!

I’ve learned a lot about Microsoft .NET Framework whilst making this and also how to potentially be able to run Windows apps on Linux-based operating systems as well as Macs. That side of the project hasn’t been a massive success so if I were to do this again I’d look to build the app using a platform that makes writing cross-compatible code easier, perhaps something like Xamarin (which Microsoft has acquired and has implemented into modern versions of Visual Studio!) that doesn’t rely on .NET Framework.

The importance of knowing about front-end AND back-end development as a UX Designer

As a UX designer, if you know how an app or a website or any piece of software is written and constructed, then you will have a better understanding of why some things cannot be done or why some things take a long time to implement. As a designer, you may design an interface component that takes a software development an incredible amount of time and effort to code and get right! It’s also good to understand the frustrations of what other people go through when working on similar project as you.

You also appreciate your role as an interface designer and software tester more. When you code an application from scratch and learn how much thought goes into it, it can be easy to forget about the UI and the user experience as a whole and become very focused on ensuring that the program or website runs with no bugs or errors and functions as it should. That is the role of a software developer. Your role is to design the interface and focus on delivering the user experience process of finding out the need of a client and developing the software around that. The two halves must go together to make a working product!