Archiv der Kategorie: Programmierung

AngularJS + NodeJS Schulung

Vorraussetzung

Installation der folgenden Komponenten:

NodeJS

Konsolenbefehle

npm init -y // erstellt die package.json und bestätigt alles mit y
npm install typescript --save-dev // Mit Typescript entwickeln - fügt in package.json eine devDependencies hinzu
npx tsc --init // Erzeugt tsconfig.json (enthält z.B. die Ecma-Script-Version)
npx tsc --watch // Schaut nach Änderungen
node src/hello.js // Interpretiert das Javascript damit wir keinen Browser brauchen mit Node kann man aufs Dateisystem zugreifen
npm installiert pakete
npx temporäres Paket

Aufgabe 1: Klassen & Methoden

Baue eine Klasse die etwas zurückgibt bei folgendem Code

let s: Student = new Student();
let label:string = s.getLabel(123457);
console.log(label); // "Student mit Matrikelnummer: 123456"

Lösung 1

class Student {
    oldNumber:number = -1;

    getLabel(matNr:number):string {
        if (matNr == 123456)
        {
            this.oldNumber = matNr;
            let zusammenGebaut = "Die Nr. " + this.oldNumber;
            return zusammenGebaut;
        }
        else
        {
            return `Student mit Matrikelnummer: ${matNr}`;
        }
    }
  }

Aufgabe 2: Konstrukturen

Sorge dafür, dass diese Ausgabe über einen Konstruktor funktioniert

let s: Student = new Student("Max", 123456);
let label: string = s.getLabel();
console.log(label); // "Student Max mit Matrikelnummer: 123456";

Lösung 2

class Student {
    name: string;
    mNr: number;

    constructor(_name: string, _mNr: number) {
      this.name = _name;
      this.mNr = _mNr;
    }

    getLabel() {
        return `Student ${this.name} mit Matrikelnummer ${this.mNr}`;
    }
  }

Aufgabe 3: Auslagern in andere Dateien

Lagere die Klasse Student in eine andere Datei aus, so dass sie mit den folgenden Kommandos wieder instanziert werden kann

import {Student} from "./student"

let s: Student = new Student("Max", 123456);
let label: string = s.getLabel();
console.log(label); // "Student Max mit Matrikelnummer: 123456";

Lösung 3

Lege die Klasse student.js im gleichen Verzeichnis wie hello.js an und kopiere die Student-Klasse von Lösung 2 rein:

export class Student {
    oldNumber:number = -1;
    name: string;
    mNr: number;

    constructor(_name: string, _mNr: number) {
      this.name = _name;
      this.mNr = _mNr;
    }

    getLabel() {
        return `Student ${this.name} mit Matrikelnummer ${this.mNr}`;
    }
  }

Aufgabe 4: ESLint für sauberen Code

Säubere den Code mit ESLint

Ansatz 4

Führe die folgenden Konsolenbefehle aus um ESLint zu verwenden:

npm init @eslint/config
npx eslint src/hello.ts

Beobachtung 4

ESLint meckert:

Lösung 4

Ändere den Code so, dass aus den Variablen aus Lösung 3 anstelle von let das Keyword const verwendet wird:

import {Student} from "./student"

const s: Student = new Student("Max", 123456);
const label: string = s.getLabel();
console.log(label); // "Student Max mit Matrikelnummer: 123456";

Microsoft Excel VBA: How to delete a worksheet in a workbook / Ein Arbeitsblatt in einer Arbeitsmappe löschen

Problem

A worksheet within a workbook shall be deleted via VBA in Excel.
Ein Arbeitsblatt soll in einer Arbeitsmappe gelöscht werden.

Approach / Ansatz

  • Create a new SUB method with the worksheet name as parameter / Definition einer neuen Sub-Methode mit Übergabe des Namen des zu löschenden Arbeitsblattes
  • Iterate all worksheets / über alle Arbeitsblätter iterieren
    • Check the name of the current worksheet / Namen der Worksheets prüfen
      • When the name matches the SUB paramter, the worksheet will get deleted via .Delete method / Wenn der Name des übergebenen Parameters entspricht, wird das worksheet gelöscht mit der .Delete Methode

Solution / Lösung

Sub DeleteWorksheet(worksheetName As String)
Dim ws As Worksheet, wb As Workbook

Set wb = ActiveWorkbook

Application.DisplayAlerts = False

For Each ws In wb.Worksheets
    If ws.Name = worksheetName Then
        ws.Delete
        Exit For
    End If
Next

Application.DisplayAlerts = True

End Sub

C# Threads: Was bedeutet „signaled“ beim AutoResetEvent-Konstruktor und im Kontext von AutoResetEvent?

Problemfeld

AutoResetEvent bietet über einen globalen oder übergeordneten Kontext die Möglichkeit durch den Aufruf der WaitOne-Methode innerhalb des Thread-Codes, Threads zu blockieren bis ein Signal aus einem anderem Kontext gesendet wird. Der andere Kontext sollte dabei auch Zugriff auf das steuernde AutoResetEvent-Objekt haben.

Konstruktor-Parameter

AutoResetEvent event_1 = new AutoResetEvent(true);
AutoResetEvent event_2 = new AutoResetEvent(false);

Ein Thread, welcher event_1.WaitOne() aufruft, blockiert nicht da signaled auf TRUE steht.

Ein Thread, welcher event_2.WaitOne() aufruft, blockiert da signaled über den Konstruktor mit FALSE initialisiert wurde.

Ruft ein Thread die Methode „WaitOne“ auf, wird dieser allerdings nur blockiert, wenn AutoResetEvent mit false initialisiert wurde.

Event auf „signaled“ ohne Konstruktor setzen

Um die blockierten Threads nun aus einem anderen Kontext, welcher auch Zugriff auf das AutoResetEvent-Objekt haben muss, zu steuern können die Methoden .Set() und .Reset() des AutoResetEvents aus dem steuerenden Kontext heraus genutzt werden:

// Setzt den Status auf "nicht signalisiert" / "non signaled" 
// Threads blockieren nach Aufruf von AutoResetEvent.WaitOne()
event_1.Reset(); 

// Setzt den Status auf "signalisiert" / "signaled"
// Threads blockieren NICHT nach Aufruf von AutoResetEvent.WaitOne()
event_2.Set(); 

Nur einer, der wartenden Threads erhält ein Signal wenn Set() aufgerufen wird. Will man alle wartenden Threads befreien, muss man Set() mehrfach aufrufen.

Unterschied zu ManualResetEvent

  • ManualResetEvent signalisiert allen wartenden Threads, dass diese die WaitOne()-Methode passieren dürfen. Sie ist also wie eine Tür, die sich für alle öffnet. ManualResetEvent.Reset(); schließt, die Tür, ManualResetEvent.Set(); öffnet die Tür.
  • AutoResetEvent signaliert maximal einem wartendendem Thread, dass er nach Aufruf der AutoResetEvent.WaitOne()-Methode weitermachen darf. Um alle blockierten Threads zu befreien, muss AutoResetEvent .Set() entsprechend der Anzahl wartender Threads aufgerufen werden. Wenn kein AutoResetEvent auf „signaled“ gesetzt wurde, wird auch niemand durchgelassen. Das entspricht der Warteschlange auf Ämtern oder Ärzten, wo man eine Nummer ziehen muss und immer nur einer aufgerufen wird.

Visual Studio : Project or Subproject does not compile / is not compiling or only compiles when the Build function in the context menu of the project explorer or in the VS menu is called explicitly

Problem

The project always shows an old status or an old version of the application when the „Start“-Button of Visual Studio has been clicked.

When the Build process is started manually before pressing the start button, the program version is the current / acutal one.

The target state should be that the program has always the current version without calling the BUILD funtion explicit.

Assumption

The root cause of this issue only occurs in a Visual Studio solution with more than one project.

Solution

  1. Make sure the project (i.e. „TestProject“) is set as startup project with the context menu (it appears bold in the project explorer).
  2. Right-click the Visual Studio Solution and select „Properties“.
  3. Got to the „configuration“ page in the appearing window (left side of the dialog)
  4. Select the „Build“ checkbox for the project that always shows the old status
  5. Press the OK button and try again.

WPF DataGrid MouseBinding Gesture List

Problem

The MouseBinding Tag in XAML is declaring a property „Gesture“, but it is hard to find a full reference / a complete list for all gestures of the MouseBinding tag.

Solution

Accepted gestures can be found in the enumeration MouseAction

LeftClick1A left mouse button click.
LeftDoubleClick5A left mouse button double-click.
MiddleClick3A middle mouse button click.
MiddleDoubleClick7A middle mouse button double-click.
None0No action.
RightClick2A right mouse button click.
RightDoubleClick6A right mouse button double-click.
WheelClick4A mouse wheel rotation.
List of possible gestures

Tortoise SVN: Show log with older messages and version history entries / it looks like commits are truncated or deleted after a point in time.

Problem

When you right click a folder in the Windows Explorer and you choose „TortoiseSVN -> Show log“ you are not able to see all entries. Even when you change the date range on the upper right of the window you can not fetch all entries.

It seems like that older SVN Server History entries are deleted. But in fact this is not the case.

Solution

First check the date range on the upper right of the window.

After that try to fetch the „lost“ entries by pressing the „Show All“ button on the lower left of the window.

C#.NET : Custom Collections anstelle von List erstellen über die mit foreach( … ) iteriert werden kann

Intention

Um die Klasse List<T> vor Zugriffen zu schützen / zu beschränken oder diese mit Notification-Events (z.B. ObservableCollection) auszustatten werden für den jeweiligen Verwendungszweck eigene Collections verwendet.

Ansatz

Um eine eigene Collection zu erstellen, welche mit foreach( … ) über die Elemente der eingekapselten Struktur (also z.B. List<T>) zu iterieren, benötigt man eine Enumerator-Klasse, welche die Methoden …

  • MoveNext()
  • Reset()
  • … und die Property „Current“ implementiert

implementiert (hier MyCollectionEnumerator) … sowie natürlich die gecustomizte Collection-Klasse selber, die die Datenstruktur enthält (hier MyCollection).

Lösung

using System;
using System.Collections.Generic;

namespace Irrsinn
{
    // Diese Klasse definiert mit MoveNext / Reset und der Property
    // Current aus dem Interface IEnumerator wie foreach(String s in col)
    // über die eingekapselte Liste iterieren darf.
    public class MyCollectionEnumerator : System.Collections.IEnumerator
    {
        private List<string> StringList;
        private int Counter = -1;

        // Im Konstruktor wird die Liste übergeben um die Operationen
        // MoveNext / Reset / Current darauf ausführen zu können
        public MyCollectionEnumerator(List<string> _StringList)
        {
            this.StringList = _StringList;
        }

        // Geht auf den nächsten Datensatz, der in der Liste 
        // gespeichert ist. Wenn MoveNext() false zurückgibt
        // ist das Ende der Liste erreicht
        public bool MoveNext()
        {
            Counter++;
            return Counter < StringList.Count;
        }

        // Setzt die Collection zurück.
        public void Reset()
        {
            Console.WriteLine("RESET!");
            Counter = -1;
        }

        // Gibt immer das aktuelle Element zurück, was mit 
        // MoveNext erreicht wurde
        public object Current
        {
            get
            {
                return StringList[Counter];
            }
        }
    }

    public class MyCollection
    {
        // Intern ist sind Collections meistens vom Typ List<T>
        // aber die eigene Implementierung gibt uns die Möglichkeit
        // den Zugriff auf die Liste anzupassen.
        private List<string> _StringList = new List<string>();

        // Hinzufügen eines Strings
        public void AddString(string newString)
        {
            this._StringList.Add(newString);
        }

        // GetEnumerator wird benötigt um mit foreach(...)
        // über die Collection zu iterieren
        public System.Collections.IEnumerator GetEnumerator()
        {
            return new MyCollectionEnumerator(_StringList);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // Gecustomizte Collection
            MyCollection myCol = new MyCollection();
            myCol.AddString("Schatzi schenk mir ein Foto");
            myCol.AddString("schenk mir ein Foto vom Bier");
            myCol.AddString("Schatzi schenk mir ein Foto");
            myCol.AddString("Dann schenk ich Dir auch eins");
            myCol.AddString("vom Tier (also von den Muppets)");


            foreach (string s in myCol)
            {
                Console.WriteLine(s);
            }

            Console.ReadLine();
        }
    }
}

WPF MVVM: Was ist der Sinn hinter RelayCommand und wozu braucht man RelayCommand?

Problemfeld

RelayCommand (s) erfüllen den Zweck von Actions / Delegates und sind somit Funktionszeiger die es erlauben, zu einem späteren Zeitpunkt eine Methode aufzurufen.

Sie implementieren das Interface ICommand, welches von den WPF Controls genutzt wird, um bei Bedarf die Execute()-Methode aufzurufen. D.h. die Execute()-Methode soll nur dann aufgerufen werden, wenn das WPF Control das Ereignis tatsächlich auslöst und nicht bereits zur Bindung.

Ohne RelayCommands müsste man für jeden Command eine eigene Klasse schreiben, welche vom Interfache ICommand erbt. Sie helfen somit Code einzusparen.

Verwendung in einem MVVM Pattern

Häufige Verwendung: In einer XAML Datei wird ein Button definiert, der an einen RelayCommand gebunden wird, welcher zu einem späteren Zeitpunkt aufgerufen werden soll:

Das ViewModel, welches die View instanziert, muss einen RelayCommand „PerformCalibration“ definieren, der erst aufgerufen wird, wenn der Button geklickt wird (Relay) und nicht sofort bei der Bindung an den ButtonCommand.

Für diesen Zweck beinhaltet das ViewModel, welches die View instanziert, eine Funktion die den RelayCommand zurückgibt:
 

Der Button ruft die Funktion „Execute“ des implementierten RelayCommands auf, wenn er geklickt wird.

Da RelayCommands „Actions“ sind, haben Sie keinen Rückgabewert.

C# und Delegaten, Func, Action, Predicate

Was sind Delegates?

Beispiel:
public delegate string MeinDelegateName(string s);

Ein Delegate deklariert einen Datentyp (hier MeinDelegateName) anhand einer Funktionssignatur. Eine Funktionssignatur, welche den Aufbau einer Funktion darstellt, sieht folgendermaßen aus:

Rückgabewert DelegateName (Argumente)

Diesem Datentyp kann nun eine oder mehrere (siehe +=-Operator) Funktionen mit genau dieser Funktionssignatur zugewiesen werden, was das Aufrufen dieser Funktionen ermöglicht, ohne deren Namen zu kennen. Dadurch wird die Implementierung der Funktion von dem aufrufendem Code entkoppelt.

Ein Verwendungsbeispiel wären EventListener / Events, welchen über Delegates die Funktion übergeben wird, die beim Eintritt des Events aufgerufen werden soll. Über den += Operator können einem Event mehrere Funktionen zugewiesen werden (z.B. bei einem Windows-Fenster das OnLoad-Event).

Bei der Verwendung von Delegates muss also der Delegate-empfangende Code den Namen der Funktion (bzw. Methode) nicht wissen und kann diese trotzdem aufrufen. Delegates anonymisieren also Funktions- bzw. Methodennamen. Ein ähnlicher Mechanismus für Klassen stellen Interfaces zur Verfügung. Interfaces anonymisieren allerdings nicht per se Namen der deklarierten Methoden/Funktionen sondern lediglich der Klassennamen. Wäre eine Anonymisierung von Funktions- und Methodennamen gewünscht, könnten die Delegates in den Interfaces deklariert werden.

Deklaration von Delegate-Typen mit dem normalen Delegate-Schlüsselwort

// Definition des Delegatentyps SageHalloWeltDelegate:  
// Eine Funktionssignatur, welcher ein string übergeben
// wird und welche einen String zurückgibt, wird festgelegt
public delegate string SageHalloWeltDelegate(string s); 

public string sageHalloWeltFunktion(string s)
{
    Console.Write("Hallo");
    return " Welt";
}

public Program()
{
    // Instanz der Funktion "delegateInstanzDerFkt" mit der 
    // Funktionssignatur "SageHalloWeltDelegate"
    SageHalloWeltDelegate delegateInstanzDerFkt = sageHalloWeltFunktion;
    
    // Aufruf der instanzierten Funktion 
    Console.WriteLine(delegateInstanzDerFkt("Hallo"));		
}

Durch .NET vordefinierte Delegattypen: Action / Func / Predicate

 .NET enthält jedoch eine Reihe von Delegattypen, die Programmierer verwenden können, damit sie keine neuen Typen (wie oben der Typ „SageHalloWeltDelegate„) erstellen müssen. Diese Typen lauten Func<>Action<> und Predicate<>

Die Deklarationszeile des Delegate-Typs
public delegate string SageHalloWeltDelegate(string s);
fällt somit weg.

  • Action<> wird verwendet, wenn eine Aktion mithilfe der Argumente des Delegaten ausgeführt werden muss. Die von dem Typ gekapselte Methode gibt keinen Wert zurück.
    Die Signatur darf maximal 16 Argumente enthalten.

    Bsp. für eine Action
    Action<string> delegateInstanzDerFkt = sageHalloWeltFunktion;

    Hier würde der Teil “ Welt“ aus dem obigen Beispiel nicht zurückgegeben werden.
  • Func<> wird üblicherweise verwendet, wenn eine Transformation ausgeführt werden muss, Sie also die Argumente des Delegaten in ein anderes Ergebnis transformieren müssen. Projektionen sind ein gutes Beispiel. Die von dem Typ gekapselte Methode gibt einen angegebenen Wert zurück.
    Die Signatur darf maximal 16 Argumente enthalten.

    Bsp. für Rückgabewert „string“ und Übergabewert „string“:
    Func<string, string> delegateInstanzDerFkt = sageHalloWeltFunktion;

    Der letzte Typparameter der Func-Deklaration ist jeweils der Rückgabewert.
    Func<string, string, int> delegateInstanzDerFkt = sageHalloWeltFunktion;
    würde einen Integer-Wert zurückgeben und ihr würden zwei Strings übergeben werden.
  • Predicate<> wird verwendet, wenn Sie ermitteln müssen, ob das Argument die Bedingung des Delegaten erfüllt. Sie können auch die Schreibweise Func<T, bool> verwenden. In diesem Fall gibt die Methode einen booleschen Wert zurück.
    Predicates werden meistens bei LINQ verwendet, wenn man zum Beispiel in Collections oder Listen etwas suchen möchte. Meistens wird Predicate dann als LAMBDA-Ausdruck geschrieben.
    Die Signatur darf maximal 16 Argumente enthalten.

    Func<string, bool> delegateInstanzDerFkt = sageHalloWeltFunktion;
    ist also äquivalent mit
    Predicate<string> delegateInstanzDerFkt = sageHalloWeltFunktion;
    und würde mit dem obigen Beispiel zu einem Fehler führen, da die Methode sageHalloWeltFunktion einen String zurückgibt.

Konvertieren von Lamda-Ausrücken in Delegateinstanzen

// Berechne quadrat
Func<int, int> square = x => x * x; 
Console.WriteLine(square(5));

// Konkateniere String
Func<string, string, string> concat = (a,b) => a + " " + b;
concat("Hello", "World");

// Einzelne Action wird ohne Übergabeparameter (Rückgabe hat sie nicht)
Action line = () => Console.WriteLine("Hello world!");
line();

// Einzelne Action wird ohne Übergabeparameter (Rückgabe hat sie nicht)
Action line = text => Console.WriteLine(text);
line("Hello world!");

Example:

VBA: Check if string StartsWith / StartWith or EndsWith / EndWith

Problem

Visual Basic for application does not have function to test, whether a string starts with or ends with another string like it is included in the .NET Framework

Approach

Those function can easily created by using the existing string functions

Solution

The following code can be pasted to a VBA project:

Public Function EndsWith(str As String, ending As String) As Boolean
     Dim endingLen As Integer
     endingLen = Len(ending)
     EndsWith = (Right(Trim(UCase(str)), endingLen) = UCase(ending))
End Function

Public Function StartsWith(str As String, start As String) As Boolean
     Dim startLen As Integer
     startLen = Len(start)
     StartsWith = (Left(Trim(UCase(str)), startLen) = UCase(start))
End Function

Example usage:

If StartsWith(„My string has something in it“, „My string“) Then Msg Box „It is in it!“
If EndsWith(„My string has something in it“, „in it“) Then Msg Box „It is in it!“