Archiv der Kategorie: .NET

C#.NET: QR Code erzeugen mit QRCoder.dll / QR-Codes mit C# oder VB.NET erstellen / generieren

Beispiel: Kostenloser QR Code Generator

Hier ein kostenloser QR Code Generator, welcher in ASP.NET mit C# als Backend realisiert wurde:

https://www.my-asp-experiments.com/QRCode

Beschreibung

QRCoder ermöglicht das Erstellen von QR-Codes mit einer einfachen Bibliothek. Solange keine QR-Code-Version angegeben wird, passt sich die Größe der generierten QR-Codes an den zu codierenden Text an.

Die folgenden Parameter werden unterstützt:

  • ECC Level: Fehlerkorrekturlevel. Gibt an wieviel Redundanzen eingebaut werden um im Fehlerfalle trotzdem lesbare Q- Codes zu erhalten. Je höher der Level ist, desto weniger Text kann im QR-Code einer bestimmten Größe gespeichert werden. Es gibt 4 ECC-Level={L, M, Q, H}, die in der folgenden ENUM definiert sind:
    QRCodeGenerator.ECCLevel
  • Version (optional): Die QR-Code-Version legt eine feste Größe (Modulanzahl) für den generierten QR Code fest. Die QR-Code-Größe definiert sich durch die Anzahl der „Module“ in der Matrix. Ein „Module“ definiert ein Quadrat im QR-Code. Wird keine Version angegeben, vergrößert sich der QR-Code automatisch auf die entsprechende Version.
    Beispiele: Version 1 hat eine Größe von 21×21 Modulen, also 1(21×21), Version 2(25×25), 3(29×29), 4(33×33), 5(37×37), 6(41×41), 7(45×45), 8(49×49), 9(53×53), 10(57×57), 11(61×61) …
  • Pixel pro Modul: Die Anzahl der verwendeten Pixel für die Darstellung eines Moduls im QR-Code. Da Module im QR-Code quadratisch sind, gilt der Parameter für Breite und Höhe. Durch die exakte Festlegung der Pixel kann verhindert werden, dass der QR-Code wegen einer Skalierung unscharf oder verschwommen wird (wg. Aliasing).
  • Text (bzw. Textformat des zu codierenden Textes): Ein codierter Text kann numerische, alphanumerische, binäre oder Kanji-Zeichen enthalten. Die Reihenfolge dieser möglichen Zeichensätze legt von links nach rechts fest, wieviel Text insgesamt im QR-Code enthalten sein kann. Rein numerische Zeichen benötigen wenig Platz im QR-Code, wodurch für eine festgelegte Größe (Version) z.B. viel mehr Text codiert werden kann. Wenn ein Text aber nur ein einziges Kanji-Zeichen beinhaltet, wird der gesamte Textinhalt für Kanji codiert, was dazu führt dass weniger Text für eine Version (festgelegte Anzahl von Modulen) codiert werden kann.

Die folgende Tabelle verdeutlicht anhand der oben genannten Parameter, welche Datenkapazität (Textlänge) nach Version, ECC Level und verwendetem Zeichensatz erwartet werden kann:

Version (Modulzahl)NumerischAlphanumerischBinärKanji
LMQHLMQHLMQHLMQH
1(21)4134271725201610171411710874
2(25)7763483447382920322620142016128
3(29)1271017758776147355342322432262015
4(33)187149111821149067507862463448382821
5(37)255202144106154122876410684604465523727
6(41)32225517813919515410884134106745882654536
7(45)37029320715422417812593154122866495755339
8(49)46136525920227922115712219215210884118936652
9(53)552432312235335262189143230180130981411118060
10(57)6525133642883953112211742712131511191671319374
11(61)77260442733146836625920032125117713719815510985
12(65)88369148937453541929622736728720315522617712596
13(69)1022796580427619483352259425331241177262204149109
14(73)1101871621468667528376283458362258194282223159120
15(77)1250991703530758600426321520412292220320254180136
16(81)14081082775602854656470365586450322250361277198154
17(85)15481212876674938734531408644504364280397310224173
18(89)172513469487461046816574452718560394310442345243191
19(93)1903150010638131153909644493792624442338488384272208
20(97)2061160011599191249970702557858666482382528410297235
21(101)22321708122496913521035742587929711509403572438314248
22(105)2409187213581056146011348236401003779565439618480348270

Installation von QRCoder.dll

Die Bibliothek „QRCoder“ kann über die gängigen Quellen bezogen werden und muss dann ggfs. als Verweis hinzugefügt werden:


Einige der genannten Quellen tun dies allerdings automatisch

GitHub

https://github.com/codebude/QRCoder

.NET CLI

dotnet add package QRCoder --version 1.4.3

Package Manager

NuGet\Install-Package QRCoder -Version 1.4.3

Package Reference

<PackageReference Include="QRCoder" Version="1.4.3" />

Paket CLI

paket add QRCoder --version 1.4.3

Script & Interactive

#r "nuget: QRCoder, 1.4.3"

Cake

// Install QRCoder as a Cake Addin
#addin nuget:?package=QRCoder&version=1.4.3

// Install QRCoder as a Cake Tool
#tool nuget:?package=QRCoder&version=1.4.3

C# Konsolenanwendung

Die folgende C# Konsolenanwendung erzeugt drei QR-Codes der Version 5 (also 37×37 Module) mit dem Fehlerkorrekturlevel L (niedrigster Korrekturlevel für viel Platz) und 4×4 Pixel pro Modul. Der Text ist binär, da er die Sonderzeichen einer URL aber keine Kanji-Zeichen beinhaltet. Der erste QR-Code beinhaltet nur den Text „d“ und wird deswegen als alphanumerisch klassifziert.

Außerdem wird der „Ruhebereich“ des QR-Codes (weißer Rand) abgeschnitten, was nicht immer zu empfehlen ist, da diese Trennung für einen korrekten Scan benötigt wird.

using QRCoder;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace QRCodeTestConsole
{
    public class Program
    {
        public static Program prg;
        public const int version5QRCodeSize = 148 + 32;
        public const int pixelPerModule = 4;
        public const int moduleVersion = 5;
        public const int croppedBorderPixels = 16; 
        public const QRCodeGenerator.ECCLevel eccLevel = QRCodeGenerator.ECCLevel.L;

        public Program()
        {
            string[] content = { "d", 
                                 "https://www.youtube.com/playlist?list=PLA4OWG_-fY-JLoj-bHIPiUU1SJquB9X8J",
                                 "https://www.youtube.com/playlist?list=PLA4OWG_-fY-JLoj-bHIPiUU1SJquB9X8J----------------------...........oipipoiopiopipoipiooipo"};
            
            for (int i = 0; i < content.Length; i++)
            {
                string current = content[i];              

                string msgResult = this.GenerateQRCode(current, "QRCode" + i + ".bmp");
                
                if (!msgResult.ToLower().Equals("ok"))
                {
                    Console.WriteLine(msgResult);
                }
            }

            Console.ReadLine();
        }

        public string GenerateQRCode(string content, string fileName)
        {
            try
            {
                QRCodeGenerator qrGenerator = new QRCodeGenerator();
                QRCodeData qrCodeData = qrGenerator.CreateQrCode(content, eccLevel, false, false, QRCodeGenerator.EciMode.Default, moduleVersion);
                QRCode qrCode = new QRCode(qrCodeData);
                Bitmap qrCodeImage = new Bitmap(qrCode.GetGraphic(pixelPerModule));

                // Ruhezone abschneiden - falls nicht 
                // gewünscht bei qrCodeImage.Save aufrufen 
                Bitmap croppedBmp = qrCodeImage.Clone(new Rectangle(croppedBorderPixels, croppedBorderPixels, qrCodeImage.Width - 2 * croppedBorderPixels, qrCodeImage.Height - 2 * croppedBorderPixels), qrCodeImage.PixelFormat);
                croppedBmp.Save("CROP_" + fileName);
            }
            catch (Exception e)
            {
                return e.ToString();
            }

            return "ok";
        }

        public static void Main(string[] args)
        {
            prg = new Program();
        }
    }
}

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.

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:

Visual Studio 2013 : Show folders with *.cs files in the solution explorer after they suddenly disappeared / hidden

Problem

Sometimes it happens, that you have created folders in Visual Studio for your application and had put some *.cs C# Source Code files that suddenly disappeard in the solution explorer.

Analysis

I.e. that can happen when you have forgotten to save your Visual Studio application project, berfore you have closed the IDE.

Solution

Use the file explorer and navigate to your Visual Studio solution (alternatively you can right-click a source code file in your folder and select „Open contained folder“ from the context menu).

Open the .csproj file in your solution in a text editor of your choice:

.csproj files store the project structure of the solution explorer

Go to the section where the <ItemGroup /> tags are declared and add a new section with the folders and source code files you want to show in your solution like in the screenshot below

My folders Command, ViewModelBase, ViewModel and Model disappeard over night, so i readded the marked group

You can add all cs-files with a wildcard star like it is shown in the screenshot above.

C# .NET : Collections im .NET Framework

Intention

Eines der wichtigsten .NET Elemente zum Verwalten vom Datenbeständen im Speicher sind Collections (Auflistungen). Im Vergleich zu normalen Array-Typen bieten diese die Möglichkeit zur Laufzeit Objekte hinzuzufügen, ohne vorher die Größe/die Anzahl der Objekte in der Collection zu kennen. Collections bieten Funktionen zum Hinzufügen, Entfernen und Suchen/Finden von Objekten. Ist ein Objekt in einer Auflistung erstmal gefunden, kann dieses über die Objektreferenz auch direkt in der Auflistung geändert werden.

Typsicher
  • Bessere Leistung
  • keine explizite Umwandlung notwendig um auf Objekteigenschaften zuzugreifen
  • Akzeptieren beim Erstellen einen Typparamter <T>
  • Unterstützung für Windows-Store-Apps
Typsicher…
Generische Auflistungen
Generische Auflistun…
Nicht
generische Auflistungen
Nicht…
Auflistungen
(Collections)
Auflistungen…
Nicht typsicher
  • Speichern Elemente als Objekt (Object)
  • erfordern explizite Umwandlung in den Objekttyp um auf Objekteigenschaften zuzugreifen
  • keine Unterstützung für Windows-Store-Apps
Nicht typsicher…
System.Collections.Concurrent
System.Collections.Concurrent
System.Collections
System.Collections
System.Array
System.Array
System.Collections.Generic
System.Collections.Generic
Threadsicher
Threadsicher
Findet man oft in älterem Code
Findet man oft…
System.Collections.Immutable
System.Collections.Immutable
NuGet-Paket
NuGet-Paket
Actor
Actor
Hinzufügen
Hinzufügen
Ändern
Ändern
Entfernen
Entfernen
Suchen
Suchen
        Collection
  1. Object 1
  2. Object 2
  3. Object 3
  4. Object n
Collectio…
«interface»
 System.Collections.IEnumerable
«interface»…
foreach(Object o in Collection) 
{
  o.Property…
}
foreach(Object o in Collectio…
«interface»
 System.Collections.Generic.IEnumerable
«interface»…
LINQ
var
query = from Object o in Collection
where o.Attribute > 95
select o;

foreach (Object o in query) {
Console.WriteLine(o.Attribute + „“
);
}
LINQ…
Viewer does not support full SVG 1.1

Auflistungen implementieren das Interface „IEnumerable“, um das Iterieren durch die Objekte in der Liste zu ermöglichen. Die foreach-Schleife nutzt beispielsweise dieses Interface um durch alle Objekte einer Collection zu iterieren.

Über die Abfragesprache LINQ (Language Integrated Query) lassen sich SQL-ähnliche Abfragen auf Collections durchführen,

Namespaces / Namensräume

Der Namensraum für .NET Framework Collections liegt unter System.Collections.*, wobei weitere Sub-Namensräume existieren.

  • System.Collections.Concurrent (mehrere Threads / Tasks können parallel auf diesen Collections im Speicher operieren)
  • System.Collections.Immutable (man arbeitet hierbei nur auf Kopien / die ursprünglichen Daten werden nicht geändert – muss zusätzlich über NuGet-Paket installiert werden)
  • System.Collections.Generic

Dynamische Strukturen/Collections allokieren immer 2^n Speicher-Plätze

Die Property „Capacity“, welche an jeder Collection anhängt, zeigt die Anzahl der Speicherplätze, die die Collection intern als Array alloziert hat. Bei 1025 Elementen werden intern 2048 Plätze vorbereitet. Bei 2049 Elementen werden intern 4096 Plätze vorbereitet.

C# .NET Eine geeignete Datenstruktur für Tabellen / DataTable erstellen / Best .NET DataType for tables

Problem

Die Datenstruktur DataTable von .NET muss richtig initialisiert wreden

Lösung

public DataTable initDataGrid()
{
	DataColumn c0 = new DataColumn("ID");
	DataColumn c1 = new DataColumn("FILE");
	DataColumn c2 = new DataColumn("SITE");
	DataColumn c3 = new DataColumn("OBJEKTSTEREOTYPE");
	DataColumn c4 = new DataColumn("TAB");
	DataColumn c5 = new DataColumn("STEREOTYPE");
	DataColumn c6 = new DataColumn("CONNECTION");
	DataColumn c7 = new DataColumn("LINK");
	DataColumn c8 = new DataColumn("LINK_TO_ID");
	DataColumn c9 = new DataColumn("ALIAS");

	dataTable.Columns.Add(c0);
	dataTable.Columns.Add(c8);
	dataTable.Columns.Add(c1);
	dataTable.Columns.Add(c2);
	dataTable.Columns.Add(c9);
	dataTable.Columns.Add(c3);
	dataTable.Columns.Add(c4);
	dataTable.Columns.Add(c5);
	dataTable.Columns.Add(c6);
	dataTable.Columns.Add(c7);

	return dataTable;
}

public void main()
{
    DataTable dataTable = new DataTable("Tabellenname");
    dataTable.Clear(); 

    // Hier in einer Schleife die Tabelle befüllen
    // Use i.e. Loops to fill the table like this
    DataRow row = dataTable.NewRow();
    row["ID"] = "1";
    row["FILE"] = "2";
    row["SITE"] = "3";
    row["OBJEKTSTEREOTYPE"] = "4";
    row["TAB"] = "5";
    row["STEREOTYPE"] = "6";
    row["CONNECTION"] = "7";
    row["LINK"] = "8";
    row["ALIAS"] = "9";
    dataTable.Rows.Add(row);
}

.NET Winforms C# : Eine Baum-Komponente befüllen (TreeView)

Problem

Der TreeView-Baum soll anhand von Strings befüllt werden

Ansatz

Verwendung eines Backslashes wie bei Dateipfaden zur Baumeinrückung

Lösung

private void populateTreeFromStringArray(string[] lines)
{
	SortedList sl = new SortedList();
	this.treeView1.Nodes.Clear();
	this.treeView1.BeginUpdate();
	// this.treeView1.ShowRootLines;
	TreeNodeCollection parentNodes = this.treeView1.Nodes;
	foreach (string line in lines)
	{
		string[] stringParts = line.Split('\\');

		TreeNode nd = null;
		// Der Parent Key wird leer inititalisiert
		string strParentKey = string.Empty;
		foreach (string s in stringParts)
		{

			string sTrimmed = s.Trim();

			if (sTrimmed == string.Empty)
			{
				continue;
			}

			if (strParentKey.Length > 0)
			{
				strParentKey = string.Concat(strParentKey, @"\", sTrimmed);
			}
			else
			{
				strParentKey = string.Concat(strParentKey, sTrimmed);
			}

			if (sl.ContainsKey(strParentKey))
			{
				//verwende diesen
				nd = sl[strParentKey] as TreeNode;
			}
			else
			{
				//create new
				nd = new TreeNode(sTrimmed);
				//den FullPath adden
				sl.Add(strParentKey, nd);
				parentNodes.Add(nd);
			}

			parentNodes = nd.Nodes;
		}
	}
	this.treeView1.EndUpdate();
}

private void button4_Click(object sender, EventArgs e)
{
	 string[] lines=new string[]
	 {
		 @"E:\",
		 @"E:\Bier",
		 @"D:\Eigene Dateien",
		 @"D:\Programme\Games",
		 @"D:\Eigene Dateien\Eigene Musik2",
		 @"D:\",
		 @"D:\Eigene Dateien\Eigene Downloads\Multi",
		 @"D:\Eigene Dateien\Eigene Downloads\Multi\CD 1",
		 @"D:\Eigene Dateien\Eigene Downloads\Multi\CD 2",
		 @"D:\Eigene Dateien\Eigene Downloads\Multi\CD 3",
		 @"D:\Eigene Dateien\Eigene Downloads\Multi\CD 3\Teil 2",
		 @"D:\Eigene Dateien\Eigene Downloads\Multi\CD 4"
	 };

	 populateTreeFromStringArray(lines);
 }