mark-image

Mark Hartkemeyer

I am a software developer and IT service desk professional.

Thanks for looking at my portfolio! 🙂

Product Showcase

AsqDataEntryApp

screenshot-of-asq-data-entry-app

Summary:

  • This application creates Excel files from data input from Ages and Stages Questionnaires.

List of Benefits:

  • Data entry staff can quickly and easily input important data from Ages and Stages Questionnaires into an Excel spreadsheet.
  • Data analysts can then take that data and perform analysis on it.

Challenges I Overcame:

  • How do I validate the data input by the data entry staff?
  • On my text boxes, I used a Validating event, checking the length of the text in the textbox:

        private void TextBox_Validating(object? sender, CancelEventArgs e)
        {
            TextBox textBox = sender as TextBox;
    
            if (textBox.Text.Length == 0)
            {
                e.Cancel = true;
            }
        }
                        

    I use something similar on my combo boxes. In my submit button's click event, I set a bool to see if validation succeded or failed:

        bool inputIsValid = ValidateInput();
    
        if (inputIsValid == true)
        {
            ...
        }
        else
        {
            MessageBox.Show("Validation failed.");
        }
                        
  • Per my requirements, I needed an age, plus an "age code" of months ('M') or years ('Y'). How do I find the age of the child from a date of birth?
  • I did this:

        private (string, string) GetAgeAndAgeCode(DateTime dateOfBirth, DateTime dateAsqCompleted)
        {
            int age = GetAgeInMonths(dateOfBirth, dateAsqCompleted);
            string ageCode = "M";
    
            if (age > 11)
            {
                age = GetAgeInYears(dateOfBirth, dateAsqCompleted);
                ageCode = "Y";
            }
    
            return (age.ToString(), ageCode);
        }
    
        private int GetAgeInMonths(DateTime dateOfBirth, DateTime dateAsqCompleted)
        {
            int age = ((dateAsqCompleted.Year - dateOfBirth.Year) * 12) + dateAsqCompleted.Month - dateOfBirth.Month;
    
            return age;
        }
    
        private int GetAgeInYears(DateTime dateOfBirth, DateTime dateAsqCompleted)
        {
            int age = dateAsqCompleted.Year - dateOfBirth.Year;
    
            // Go back to the year in which the person was born in case of a leap year
            if (dateOfBirth.Date > dateAsqCompleted.AddYears(-age)) age--;
    
            return age;
        }
                        

    I then took the age and age code and inserted them into cells in Excel spreadsheet:

        public void AddRow(AsqModel asqModel)
        {
            Workbook = App.Workbooks.Open(FilePath);
            Worksheet = (Excel.Worksheet)Workbook.Worksheets[1];
    
            Excel.Range range = (Excel.Range)Worksheet.Cells[Worksheet.Rows.Count, 1];
            int lastRow = range.get_End(Excel.XlDirection.xlUp).Row;
            int newRow = lastRow + 1;
    
            ...
    
            (string age, string ageCode) = GetAgeAndAgeCode(asqModel.DateOfBirth, asqModel.DateAsqCompleted);
            App.Cells[newRow, 4] = age;
            App.Cells[newRow, 5] = ageCode;
    
            ...
    
            Workbook.Close(true);
        }
                        

RotationTracker

screenshot-of-rotation-tracker

Summary:

  • This application tracks employee rotations, such as on-call rotations.
  • It is designed to allow users to view their positions and the positions of their coworkers in weekly, bi-weekly, or monthly rotations.
  • It is currently only used by me, but there is an option to allow my coworkers to use it (with some users being administrators and some not).

List of Benefits:

  • Employees can view where they are currently in the rotations.
  • Administrators can modify the rotations or add notes, such as two employees swapped their turns.
  • The rotations advance automatically, when the date/time they advance has passed.
  • Users are notified in the UI when the rotation has advanced.

Challenges I Overcame:

  • How do I store my app's data?
  • I used SQLite data access.

  • How do I keep track of when the rotation advances?
  • I added these two properties in my RotationModel class:

        public RecurrenceInterval RotationRecurrence { get; set; } = RecurrenceInterval.Weekly;
        public DateTime NextDateTimeRotationAdvances { get; set; }
                        
  • How do I advance the rotation after a date/time has passed?
  • I did this:

        DateTime now = DateTime.Now;
    
        if (now > rotation.NextDateTimeRotationAdvances)
        {
            rotation.AdvanceRotation();
            rotation.SetNextDateTimeRotationAdvances();
            ...
        }
                        
  • How do I display notifications after the rotation has advanced?
  • I did this:

        private async void DisplayNotificationsAsync()
        {
            if (notificationMessage != "")
            {
                notificationTextBlock.Text = notificationMessage;
                notificationStackPanel.Visibility = Visibility.Visible;
                await Task.Delay(5000);
                notificationStackPanel.Visibility = Visibility.Collapsed;
            }
        }
                        

TextCopier

screenshot-of-text-copier

Summary:

  • This application allows you to store and copy pieces of text to the clipboard from a list. It allows you to move items up or down in the list, and to sort them A to Z.

List of Benefits:

  • Users can store text they frequently need to copy, and copy it easily.
  • Users can sort their text as they like.
  • The app's data is stored locally in a SQLite database, something the user can keep nearby and is quick to access.

Challenges I Overcame:

  • How do I select the text to copy from a column of Copy buttons?
  • In the Copy button click event, I casted the sender to a button, and then the button's data context to a model I created.
    Then, I actually copied the text:

        var button = (Button)sender;
        var textItem = (TextItemModel)button.DataContext;
        Clipboard.SetText(textItem.Text);
                        
  • How do I sort the list differently for users who want to sort by Description A to Z, versus using a "custom sort"?
  • I made two different queries/methods to read (select) the data from my SQLite DB.
    I had some help from a contributor to re-write the second query to "collate nocase" for SQLite to properly order the items:

        public List ReadAllTextItemsOrderedBySortPosition()
        {
            string sql = "select Id, Description, Text, SortPosition from TextItems order by SortPosition;";
    
            return _db.LoadData(sql, new { }, _connectionString);
        }
    
        public List ReadAllTextItemsOrderedByDescription()
        {
            string sql = "select Id, Description, Text, SortPosition from TextItems order by Description collate nocase;";
    
            return _db.LoadData(sql, new { }, _connectionString);
        }
                        

Open Source Contributions

open-source-image

Eventus

UnitConversionApp


My Learning Path

online-learning-image

C# Topics:

Topic Date Learned
Basic Variables September, 2021
Conditionals (If/Else, and Switch Statements) September, 2021
Type Conversion September, 2021
Do/While Loops September, 2021
Arrays September, 2021
Lists September, 2021
Dictionaries October, 2021
For Loops October, 2021
Foreach Loops October, 2021
Methods October, 2021
Breakpoints October, 2021
Exceptions October, 2021
Static Classes October, 2021
Instantiated Classes October, 2021
Properties November, 2021
Namespaces November, 2021
Class Libraries November, 2021
Tuples November, 2021
Inheritance November, 2021
Interfaces November, 2021
Access Modifiers November, 2021
Abstract Classes November, 2021
Method Overriding November, 2021
Method Overloading November, 2021
Extension Methods November, 2021
Generics November, 2021
Events November, 2021
Enums November, 2021
Unit Test Projects December, 2021
WinForms Projects December, 2021
WPF Projects December, 2021
ASP.NET Core Razor Pages Projects December, 2021
ASP.NET Core MVC Projects December, 2021
ASP.NET Core API Projects December, 2021
SQL Server Data Access with Dapper December, 2021
SQLite Data Access with Dapper December, 2021
MySQL Data Access with Dapper December, 2021
MongoDB Data Access December, 2021
CosmosDB Data Access December, 2021
Text File Data Access December, 2021
API Data Access December, 2021
LINQ December, 2021
Lambda Expressions December, 2021
Entity Framework January, 2022
Dependency Injection January, 2022
See my C# test projects on GitHub

HTML Topics:

Topic Date Learned
Tags May, 2022
Boilerplate May, 2022
Structuring Text May, 2022
Lists May, 2022
Images May, 2022
Anchor Tags May, 2022
Tables May, 2022
Forms May, 2022
See my HTML test projects on GitHub

CSS Topics:

Topic Date Learned
Inline CSS May, 2022
Internal CSS May, 2022
External CSS May, 2022
Selectors May, 2022
Favicons May, 2022
Divs May, 2022
Display Property May, 2022
Positioning May, 2022
Font Styling May, 2022
Font Sizing May, 2022
Float and Clear May, 2022
Z-Index and Stacking Order May, 2022
Media Queries May, 2022
Combining Selectors May, 2022
Bootstrap - Navbar May, 2022
Bootstrap - Grid Layout May, 2022
Bootstrap - Containers May, 2022
Bootstrap - Buttons May, 2022
Bootstrap - Carousel May, 2022
Bootstrap - Cards May, 2022
See my CSS test projects on GitHub

JavaScript Topics:

Topic Date Learned
Alerts May, 2022
Logging to the Console May, 2022
Data Types May, 2022
Variables May, 2022
Primitive Types February, 2023
String Operations May, 2022
Dynamic Typing February, 2023
Objects June, 2022
Arrays May, 2022
Functions May, 2022
Methods June, 2022
Arithmetic Operators May, 2022
Assignment Operators May, 2022
Comparison Operators May, 2022
Equality Operators May, 2022
Ternary Operator February, 2023
Logical Operators May, 2022
If/Else Statements May, 2022
Switch Case Statements June, 2022
While Loops May, 2022
Do While Loops February, 2023
For Loops May, 2022
For In Loops February, 2023
For Of Loops February, 2023
Break and Continue February, 2023
Random Numbers May, 2022
Events June, 2022
DOM Manipulation May, 2022
Callback Functions June, 2022
Objects - Basics February, 2023
Factory Functions February, 2023
Constructor Functions February, 2023
Cloning Objects February, 2023
jQuery - Manipulating Styles June, 2022
jQuery - Manipulating Text June, 2022
jQuery - Manipulating Attributes June, 2022
jQuery - Event Listeners June, 2022
jQuery - Adding and Removing Elements June, 2022
jQuery - Animations June, 2022
Node.js with Express - Get Requests and Routes June, 2022
Node.js with Express - Sending Files in Responses June, 2022
Node.js with Express - Post Requests June, 2022
Node.js with Express - API Get Requests June, 2022
Node.js with Express - API Post Requests June, 2022
See my JavaScript test projects on GitHub

React Topics:

Topic Date Learned
React - JSX June, 2022
React - JSX Expressions & ES6 Template Literals June, 2022
React - JSX Attributes & Styling June, 2022
React - Components June, 2022
React - ES6 Import, Export, and Modules June, 2022
React - Props June, 2022
React - Map Function June, 2022
React - ES6 Map/Filter/Reduce Functions June, 2022
React - ES6 Arrow Functions June, 2022
React - Conditional Rendering with Ternary and AND Operators June, 2022
React - State with useState Hook June, 2022
React - ES6 Object and Array Destructuring June, 2022
React - Event Handling June, 2022
React - Forms June, 2022
React - ES6 Spread Operator June, 2022
See my React test projects on GitHub