Profile Picture

Sirwan Afifi

Stories from a web developer.

© 2018. Sirwan Afifi All rights reserved.

Developing Console-based UI in C#

As you know Console Applications don’t have graphical user interface or GUI. Instead, they run from Command Line, for example instead of writing a name into a textbox and clicking a button we would instead invoke the Console Application and provide the name as a parameter. In fact, in Console Applications we instead interact with the user using text inputs. For example, we could prompt something like this:

The user can then write a name and hit enter then we can read that text input into our application.

Wouldn’t be better to make it beautiful? This is where we can use Terminal.Gui a cross-platform GUI toolkit:

Sample app

Terminal.Gui is a library intended to create console-based applications using C#. The framework has been designed to make it easy to write applications that will work on monochrome terminals, as well as modern color terminals with mouse support. This library works across Windows, Linux and MacOS.

Using this UI toolkit is pretty simple, all you need to do is adding its package into your project:

dotnet add package Terminal.Gui

The simplest application looks like this:

using System;

namespace consoleTest
{
    using Terminal.Gui;

    class Demo {
        static int Main ()
        {
            Application.Init ();

            var n = MessageBox.Query (50, 7,
                "Question", "Do you like console apps?", "Yes", "No");

            return n;
        }
    }
}

This example shows a prompt and returns an integer value depending on which value was selected by the user (Yes, No, or if they use chose not to make a decision and instead pressed the ESC key):

Sample app

As you can see the first thing to do is calling Application.Init (); to actually initialize the application. We can also create a window and then add a menu to it:

Application.Init ();
var top = Application.Top;

// Creates the top-level window to show
var win = new Window (new Rect (0, 1, top.Frame.Width, top.Frame.Height-1), "MyApp");
top.Add (win);

// Creates a menubar, the item "New" has a help menu.
var menu = new MenuBar (new MenuBarItem [] {
    new MenuBarItem ("_File", new MenuItem [] {
        new MenuItem ("_New", "Creates new file", ()=> {}),
        new MenuItem ("_Close", "", () => {}),
        new MenuItem ("_Quit", "", () => { top.Running = false; })
    }),
    new MenuBarItem ("_Edit", new MenuItem [] {
        new MenuItem ("_Copy", "", null),
        new MenuItem ("C_ut", "", null),
        new MenuItem ("_Paste", "", null)
    })
});
top.Add (menu);

// Add some controls
win.Add (
    new Label (3, 2, "Login: "),
    new TextField (14, 2, 40, ""),
    new Label (3, 4, "Password: "),
    new TextField (14, 4, 40, "") {  },
    new CheckBox (3, 6, "Remember me"),
    new RadioGroup (3, 8, new [] { "_Personal", "_Company" }),
    new Button (3, 14, "Ok"),
    new Button (10, 14, "Cancel"),
    new Label (3, 18, "Press ESC and 9 to activate the menubar"));

Application.Run ();

Sample app

You can build even complex console-based UI using this toolkit:

using System;
using System.Linq;
using NStack;
using Terminal.Gui;
using TestingGuiCS.Models;

namespace TestingGuiCS
{
    class Program
    {
        static void Main(string[] args)
        {
            Application.Init ();
            var top = Application.Top;

            // Creates a menubar, the item "New" has a help menu.
            var menu = new MenuBar (new MenuBarItem [] {
                new MenuBarItem ("_File", new MenuItem [] {
                    new MenuItem ("_Quit", "", () => { top.Running = false; })
                })
            });
            top.Add (menu);


            // Creates the top-level window to show
            var win = new Window (new Rect (0, 1, top.Frame.Width, top.Frame.Height-1), "Movie Db");
            top.Add (win);

            // Add some controls
            var txtSearchLbl = new Label(3, 1, "Movie Name: ");
            var txtSearch = new TextField(15, 1, 30, "");
            var forKidsOnly = new CheckBox(3, 3, "For Kids?");
            var minimumRatingLbl = new Label(25, 3, "Minimum Rating: ");
            var minimumRatingTxt = new TextField(41, 3, 10, "");
            var searchBtn = new Button(3, 5, "Filter");
            var allMoviesListView = new ListView(new Rect(4, 8, top.Frame.Width, 200), MovieDataSource.GetList(forKidsOnly.Checked, 0).ToList());
            searchBtn.Clicked = () =>
            {

                double rating = 0;
                var isDouble = double.TryParse(minimumRatingTxt.Text.ToString(), out rating);
                if(!string.IsNullOrEmpty(minimumRatingTxt.Text.ToString()) && !isDouble)
                {
                    MessageBox.ErrorQuery(30, 6, "Error", "Rating must be number");
                    minimumRatingTxt.Text = ustring.Empty;
                    return;
                }

                win.Remove(allMoviesListView);
                if (string.IsNullOrEmpty(txtSearch.Text.ToString()) || string.IsNullOrEmpty(minimumRatingTxt.Text.ToString()))
                {
                    allMoviesListView = new ListView(new Rect(4, 8, top.Frame.Width, 200),
                        MovieDataSource.GetList(forKidsOnly.Checked, rating).ToList());
                    win.Add(allMoviesListView);
                }
                else
                {
                    win.Remove(allMoviesListView);
                    win.Add(new ListView(new Rect(4, 8, top.Frame.Width, 200),
                        MovieDataSource.GetList(forKidsOnly.Checked, rating)
                            .Where(x =>
                            x.Name.Contains(txtSearch.Text.ToString(), StringComparison.OrdinalIgnoreCase)
                        ).ToList()));
                }

            };
            win.Add (
                txtSearchLbl,
                txtSearch,
                forKidsOnly,
                minimumRatingLbl,
                minimumRatingTxt,
                searchBtn,
                new Label (3, 7, "-------------Search Result--------------")
            );

            Application.Run ();
        }
    }
}

Sample app

You can grab the working sample project from GitHub.

What about cross platform UI frameworks?

Developing cross platform UIs is not officially supported by Microsoft, But there are some open source projects out there for doing so:

Does making decision matter?

Photo by Felix Russell-Saw on Unsplash

We make decision all the time, most of these decisions are done unconsciously, others we agonize over, we all have been there agonizing over a difficult or big decision, we always worry about what to do next, in fact we are trying to make the right decision, But in my opinion there’s no such thing as the right thing or the wrong thing, it’s been a big deal for me because making decisions (big and little ones) have been challenging in my life.

Last Friday I was talking with a friend (Foad) about making decisions, he told me about something called Decidophobia or simply fear of making decisions.

Life is full of options and choices so don’t waste your time to worry about right and wrong decisions JUST take action it’s worth it.

Running PowerShell on macOS

It’s been a while I have been using macOS as my primary operating system, you can read about my expreince here.

Today I wanted to run a PowerShell script, I searched around and figured out Microsoft has made PowerShell open source open source and the good news is that PowerShell is now cross-platform! this means that you can also run PowerShell scripts on Linux, macOS.

Actually to get PowerShell to work all you need to do is installing it using Homebrew:

brew cask install powershell

Before preceding, make sure you have already installed Homebrew-Cask on your machine.

Homebrew-Cask extends Homebrew and brings its elegance, simplicity, and speed to macOS applications and large binaries alike. It only takes 1 line in your shell to reach 3759 Casks maintained by 4856 contributors.

That’s it, now PowerShell is installed, so you can use it in your terminal:

There’s also a great VSCode extension to write, debug PowerShell scripts: