Biggle's Blog

Web- und Software Development

by Mario Priebe

Bedingte Formatierung im Datagrid – WPF Quicky

Die Frage auf Codekicker lautete:

Wie kann ich in einem DataGrid eine Zelle je nach Inhalt formatieren? So wie die Bedingte Formatierung in Excel oder Access, also rot bei negativen Werten und grün bei positiven Werten. Hab schon mein Glück mit einem Converter versucht, aber das klappt irgendwie nicht.

Ich habe dazu einen Converter geschrieben, der den Wert entgegen nimmt, diesen auf kleiner 0 prüft und das Resultat als Brush für den Hintergrund zurück gibt. Ist der Wert kleiner 0 wird grün, ist der Wert größer 0 wir rot zurück gegeben.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
    if (value.ToString() == String.Empty)
        return null;
 
    decimal val = decimal.Parse(value.ToString());
 
    return (val < 0) ? Brushes.Red : Brushes.Green;
}
 
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
    return value;
}
}

Im XAML muss in der Windows Resource der Converter referenziert werden:

1
2
3
<Window.Resources>
    <Converters:SignedUnsignedConverter x:Key="SignedUnsigned" />
</Window.Resources>

Das DataGrid verwendet den Converter wie folgt:

1
2
3
4
5
6
7
8
9
10
11
12
<DataGrid Name="dataGrid" AutoGenerateColumns="False" MouseDoubleClick="dataGrid_MouseDoubleClick">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Name" Binding="{Binding Name}" />
        <DataGridTemplateColumn Header="Price">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Price}" Background="{Binding Price, Converter={StaticResource SignedUnsigned}}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

Auch in einer TextBox kann der Converter verwendet werden:

1
<TextBox Name="textBox" Background="{Binding ElementName=textBox, Path=Text, Converter={StaticResource SignedUnsigned}}"/>


Viel Spaß beim entwickeln : )

by Mario Priebe

SQLite Datenbanken in C# Applikationen verwenden

System.Data.SQlite aus dem Hause phxsoftware bietet eine Schnittstelle zur Verwendung von portablen Datenbanken im SQLite Format. Im Folgenden möchte ich zeigen, wie man diese auf unterschiedlicher Weise, in C# Applikationen verwenden kann.

Um eine SQLite Datenbank zu erstellen, gibt es eine Menge von Managementapplikationen oder auch Browsererweiterungen, z.b für den Firefox. Ich verwende, um mir erstmalig eine Datenbank zu erstellen, den kostenlosen SQLiteBrowser. Die erstellte Datenbank speichere ich dann in meinem TestProjekt, mit welchem ich auf diese zugreifen möchte.

Als erstes holen wir uns die Installation oder die Binaries. Je nach Architektur wird dann im Projekt, auf die entsprechende dll referenziert. Ich verwende die System.Data.SQLite.dll für x86, welche sich im bin Ordner befindet.

SQLiteCommand

Im ersten Beispiel, verwende ich die SQLiteCommand-Klasse, um auf die Datenbank zugreifen.

Nach dem Einbinden des Namespace “using System.Data.SQLite;” stehen uns die Klassen SQLiteConnection und SQLiteCommand zur Verfügung. (Mehr benötigen wir erstmal in unserem Beispiel nicht.)

Den Pfad, zur zuvor angelegten Datenbank lege ich in der app.config fest, damit dieser konfigurierbar bleibt:

1
2
3
4
5
<configuration>
  <appSettings>
    <add key="DATASOURCE" value="../../DataBase/data" />
  </appSettings>
</configuration>

im Code dann (namens DataProvider.cs), holen wir uns den Pfad über den ConfigurationManager in eine KlassenVariable. Hier muss explizit auf System.Configuration referenziert werden

1
private string DataSource = ConfigurationManager.AppSettings.Get("DATASOURCE");

Das Speichern, Emitteln und Löschen erledigen wir über das SQLiteCommand. Zum Öffnen und Schließen der SQLiteConnection habe ich mir zwei Methoden geschrieben:

1
2
3
4
5
6
7
8
SQLiteConnection connection;
 
private void OpenConnection()
{
    connection = new SQLiteConnection();
    connection.ConnectionString = "Data Source=" + DataSource;
    connection.Open();
}
1
2
3
4
5
private void CloseConnection()
{
    connection.Close();
    connection.Dispose();
}

Speichern von Einträgen

1
2
3
4
5
6
7
8
9
10
11
OpenConnection();
 
using (var command = new SQLiteCommand(connection))
{
    command.CommandText = string.Format("INSERT INTO Entities (Beschreibung, HtmlName, Unicode, Zeichen) VALUES('{0}', '{1}', '{2}', '{3}')",
                    entity.Beschreibung, entity.HtmlName, entity.Unicode, entity.Zeichen);
 
    command.ExecuteNonQuery();
}
 
CloseConnection();

Ermitteln von Einträgen

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
OpenConnection();
 
List<HtmlEntity> entities = new List<HtmlEntity>();
using (var command = new SQLiteCommand(connection))
{
    command.CommandText = "SELECT * FROM Entities";
 
    using (SQLiteDataReader reader = command.ExecuteReader())
    {
        while (reader.Read())
        {
            entities.Add(new HtmlEntity
            {
                Beschreibung = reader[0].ToString(),
                HtmlName = reader[1].ToString(),
                Unicode = reader[2].ToString(),
                Zeichen = reader[3].ToString()
 
            });
        }
        reader.Close();
    }
}
 
CloseConnection();

Löschen von Einträgen

1
2
3
4
5
6
7
8
9
10
11
OpenConnection();
 
using (var command = new SQLiteCommand(connection))
{
    command.CommandText = string.Format("DELETE FROM Entities WHERE Beschreibung = '{0}' AND HtmlName = '{1}' AND Unicode = '{2}' AND Zeichen =  '{3}'",
        entity.Beschreibung, entity.HtmlName, entity.Unicode, entity.Zeichen);
 
    command.ExecuteNonQuery();
}
 
CloseConnection();

Achtung! Es ist möglich, das die SQLite Assembly sich nicht mit dem 4.0 .NET  kompilieren lässt. (Mixed mode assembly is built against version ‘v2.0.50727′ of the runtime and cannot be loaded in the 4.0 runtime without additional configuration information), hier kann man sich aber mit folgendem Eintrag, innerhalb des “configuration-Knoten” in der app.config behelfen

1
2
3
<startup useLegacyV2RuntimeActivationPolicy="true">
	<supportedRuntime version="v4.0"/>
</startup>

Tipp via: stackoverflow


SQLite & Entity Framework

Es ist auch möglich, eine SQLite Datenbank als Datensource für ein Entity-Framework-Model anzugeben. Das erstelle Entity FrameworkModel stellt uns nun den Kontext bereit, Einträge zu persistieren, zu ermitteln und zu löschen.

Eintrag speichern

1
2
3
4
5
6
7
8
public void  InsertData(HtmlEntity entity)
{
    using (var context = new HtmlEntityEntities())
    {
        context.AddToEntities(entity);
        context.SaveChanges();
    }
}

Einträge ermitteln

1
2
3
4
5
6
7
8
9
10
11
12
13
public List<HtmlEntity> GetAllHtmlEntities()
{
    List<HtmlEntity> entities;
 
    using (var context = new HtmlEntityEntities())
    {
        entities = (from e in context.Entities
                    select e).ToList();
 
    }         
 
    return entities;
}

Eintrag löschen

1
2
3
4
5
6
7
8
9
10
11
public void DeleteData(HtmlEntity entity)
{
    using (var context = new HtmlEntityEntities())
    {
        HtmlEntity obj = (HtmlEntity)context.GetObjectByKey(entity.EntityKey);
 
 
        context.DeleteObject(obj);
        context.SaveChanges();
    }
}

LINQ to SQLite

Wie wir an den EF Methoden gesehen haben, können wir nun einfach mit LINQ die Operationen ausführen.

Am Beispiel “Einträge ermitteln” wurde LINQ bereits verwendet, diese kann dann natürlich auch durch eine Where-Klausel erweitert werden:

1
2
3
4
5
6
using (var context = new HtmlEntityEntities())
{  
    return (from e in context.Entities                        
            where e.Beschreibung == keyword                      
            select e).FirstOrDefault();
}

Auch wenn es so scheint, dass die System.Data.SQLite.Linq.dll wichtig für den Zugriff mit LINQ ist, wir benötigen diese dll nicht, denn durch das generieren des EF Models, steht uns hier LINQ aus dem Framework zu Verfügung.

Fragen? Einfach in den Kommentaren damit. Viel Spaß beim entwickeln : )

by Mario Priebe

Mehrfachvererbung – Ein Beispiel in C#

Angestichelt durch Ilker sein Blogpost, bin ich der Sache mit der Mehrfachvererbung unter .NET mal etwas auf den Grund gegangen. Der Ansatz mit Mixin, Interfaces und ExtensionMethods scheint ja schon seit .NET 3.0 zu bestehen und scheint mir bisher auch der Beste zu sein. Einen weiteren schönen Artikel kann man bei Galileo Computing lesen.

Hier ein Beispiel wie ich das verstanden habe und umsetzen würde.

Interfaces

1
2
3
4
public interface IMixinDateTime
{ }
public interface IMixinOneMoreInterface
{ }

ExtensionMethods

1
2
3
4
5
6
7
8
9
10
11
12
public static class MixinExtensionMethods
{
    public static int GetYearDiff(this IMixinDateTime mxDateMethod, DateTime dateTime)
    {
        return new DateTime(DateTime.Now.Subtract(dateTime).Ticks).Year - 1;
    }
 
    public static void OneMoreMethod(this IMixinOneMoreInterface mxOneMoreMethod)
    {
        //implement method here ...
    }
}

Klassen, welche die Interfaces erben (ggf. implementieren)

1
2
3
4
5
6
7
8
9
public class Car : IMixinDateTime
{
    public DateTime Baujahr { get; set; }
}
 
public class Person : IMixinDateTime, IMixinOneMoreInterface
{
    public DateTime Birthday { get; set; }
}

Verwendung

1
2
3
4
5
6
7
8
9
Person person = new Person();
person.Birthday = new DateTime(1973, 01, 23);
var personAge = person.GetYearDiff(person.Birthday);
 
Car car = new Car();
car.Baujahr = new DateTime(2000, 01, 01);
var carAge = car.GetYearDiff(car.Baujahr);
 
person.OneMoreMethod();

Da beliebig viele Interfaces geerbt werden können, erschließt sich hier, wie das Prinzip funktioniert. Weitere Meinungen, Ergänzungen oder Ansätze sind gerne als Kommentar gesehen.

Viel Spaß beim entwickeln : )

by Mario Priebe

Generic.List sortieren | C# Quicky

Um eine generische Liste zu sortieren kann man die Sort Methode auf folgender Art und Weise überschreiben:

1
2
3
public List<Begegnung> Begegnungen { get; set; }
 
Begegnungen.Sort((x, y) => DateTime.Compare((DateTime) x.Spiel.DatumUhrzeit, (DateTime) y.Spiel.DatumUhrzeit));


Beispiel

1
2
3
4
5
6
7
8
9
10
11
12
13
Begegnungen = new List<Begegnung> { new Begegnung { Spiel = new Spiel{DatumUhrzeit = DateTime.Now} }
    , new Begegnung { Spiel = new Spiel{DatumUhrzeit = DateTime.Today.AddDays(2)} } 
    ,new Begegnung{Spiel = new Spiel{DatumUhrzeit = DateTime.Today.AddHours(-5)}}
    ,new Begegnung{Spiel = new Spiel{DatumUhrzeit = DateTime.Today.AddMinutes(66)}}};
 
 
Begegnungen.ForEach(b => Console.WriteLine(b.Spiel.DatumUhrzeit));
 
Begegnungen.Sort((x, y) => DateTime.Compare((DateTime) x.Spiel.DatumUhrzeit, (DateTime) y.Spiel.DatumUhrzeit));
 
Console.WriteLine("---");
 
Begegnungen.ForEach(b => Console.WriteLine(b.Spiel.DatumUhrzeit));
1
2
3
4
5
6
7
8
9
internal class Begegnung
{
    public Spiel Spiel { get; set; }
}
 
internal class Spiel
{
    public DateTime DatumUhrzeit { get; set; }
}

Viel Spass beim entwickeln : )

by Mario Priebe

Praktische Muster – Commands

Ein schönes Beispiel für ein praktisches Entwurfsmuster habe ich im Archiv der dot.net gefunden.

In der Ausgabe 1/2009 beschreibt Marc André Zhou mit einem einfachen Beispiel, wie man ein Muster für Commands implementiert.

Hierzu definiert er ein Interface ICommand, welches die Methode Execute() festlegt.

1
2
3
4
public interface ICommand
{
    void Execute();
}

Die Klassen, die das Interface implementieren, öffnen jeweils eine Applikation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class CMDNotepad : ICommand
{
    public void Execute()
    {
        Process process = new Process();
        process.StartInfo = new ProcessStartInfo(@"notepad.exe");
        process.Start();
    }
 
    public override string ToString()
    {
        return "notepad.exe";
    }
}

Im MainProgramm dann, werden die einzelnen Commands einer Liste vom Typ ICommand hinzugefügt

1
2
3
4
var commands = new List<ICommand>();
commands.Add(new CMDNotepad());
commands.Add(new CMDIExplorer());
commands.Add(new CMDCalc());

und anschliessend ausgegeben.

1
2
3
4
5
foreach (ICommand cmd in commands)
{
    Console.WriteLine("Start command: {0}", cmd);
    cmd.Execute();
}

Ich finde das Beispiel auch als eine sehr gute Erklärung, wie ein Interface arbeitet und an welcher Stelle man eins einsetzen sollte.

Viel Spass beim entwickeln : )

by Mario Priebe

Extension Method String.Reverse() – C# Quicky

Wie man mit einer erweiterten Methode einen String “umdreht”, soll folgendes Beispiel zeigen:

Man definiert eine statische Klasse und in dieser kann man dann an den entsprechenden Datentypen, in diesem Beispiel am Datentyp String, eine weitere Methode implementieren:

1
2
3
4
5
6
7
8
9
public static class ExtensionMethods
{
    public static string Reverse(this string txt)
    {
        var reverseString = txt.ToCharArray();
        Array.Reverse(reverseString);
        return new string(reverseString);
    }
}

Aufgerufen wir das ganze dann wie folgt:

Console.WriteLine("Mein Text".Reverse());

Viel Spass beim entwickeln : )