Datum und Zeit in einem Property Grid bearbeiten

Wenn man in einem .NET Property Grid ein DateTime-Objekt bearbeitet, so klappt ein Kalender auf, in welchem das Datum eingestellt werden kann. Anschließend kann umständlich die Uhrzeit eingestellt werden. Möchte man dieses Prozedere etwas vereinfachen, kann man für das DateTime-Objekt einen neuen UITypeEditor schreiben:

public class DateTimePickerEditor : UITypeEditor
{
	IWindowsFormsEditorService windowsFormsEditorService;
	DateTimePicker dateTimePicker=new DateTimePicker();

	public DateTimePickerEditor()
	{
		dateTimePicker.Format=DateTimePickerFormat.Custom;
		dateTimePicker.CustomFormat=String.Format("{0} {1}",
                 Application.CurrentCulture.DateTimeFormat.ShortDatePattern,
                 Application.CurrentCulture.DateTimeFormat.ShortTimePattern);
	}

	public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
	{
		return UITypeEditorEditStyle.DropDown;
	}

	public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
	{
		if(provider!=null)
		{
			windowsFormsEditorService=provider.GetService(typeof(IWindowsFormsEditorService)) as IWindowsFormsEditorService;
		}

		if(this.windowsFormsEditorService!=null)
		{
			dateTimePicker.Value=(DateTime)value;
			windowsFormsEditorService.DropDownControl(dateTimePicker);
			value=dateTimePicker.Value;
		}

		return value;
	}
}

Nachdem der Editor fertiggestellt ist muss beim entsprechenden DateTime-Objekt noch der passende der Editor per Attribut definiert werden:

[EditorAttribute(typeof(DateTimePickerEditor), typeof(UITypeEditor))]
public DateTime DateAndTime;
{
	get
	{
		return dateAndTime;
	}
	set
	{
		dateAndTime=value;
	}
}

Damit verfügt man nun über einen Editor im Property Grid, welcher die Bearbeitung von Datum und Zeit komfortabel erlaubt.

Private Variablen und Eigenschaften mittels NUnit testen

Manchmal möchte man private Variablen und Eigenschaften einer Klasse mittels NUnit testen. Im Normalfall lautet die Antwort auf diese Fragestellung – Nein. Stattdessen soll nur das öffentliche Interface getestet werden. Möchte bzw. muss man trotzdem ein privates Mitglied einer Klasse testen, so muss man sich der Reflection bedienen. Das könnte dann so aussehen:

string[] lines=(string[])typeof(MyClass).GetField("Lines",BindingFlags.NonPublic|BindingFlags.Static).GetValue(null);

In diesem Fall wird sich das statische String Array Lines aus der Klasse MyClass geholt. Je nachdem, wie man die entsprechenden BindingFlags einstellt, ist es auch möglich Instanzvariablen zu ermitteln.

Pattern für asynchronen Timer

In den letzten Tagen habe ich nach einem Pattern für C#/.NET gesucht welches elegant einen Timer zur Verfügung stellt. Gestoßen bin ich dabei auf ein Pattern, welches sich die neuen Keywörter async und await aus den aktuellen C#-Versionen zu Nutze macht. Mit Hilfe dieser Schlüsselwörter lassen sich nebenläufige Funktionen ohne größeren Overhead entwickeln. Die Timer-Funktion sieht dabei so aus:

async void StartPollingTimer()
{
    while(true)
    {
        await Task.Delay(2000);

        //Do something
    }
}

Aufgerufen wird das ganze dabei einfach mittels:

StartPollingTimer();

Der Entwickler muss sich dabei nicht mehr um die Thread-/Task-Verwaltung kümmern und kann damit auf die Schnelle einen Timer implementieren, welcher asynchron läuft.

NSSpeechSynthesizer und NSSpeechRecognizer unter Mono nutzen

Unter Mac OS X gibt es in der API die Klassen NSSpeechSynthesizer und NSSpeechRecognizer. Während die eine Klasse dazu dient Text auszugeben, kann die andere Klasse dazu genutzt werden Sprache zu erkennen. Der NSSpeechSynthesizer kann unter Mono einfach genutzt werden:

var synthesizer=new NSSpeechSynthesizer();
synthesizer.StartSpeakingString("Hallo Welt.");

Schwieriger wird das ganze bei der Klasse NSSpeechRecognizer. Mit Hilfe dieser Klasse ist es möglich auf bestimmte Kommandos zu reagieren. Im ersten Moment muss die Klasse angelegt werden und einige Optionen gesetzt werden:

var recognizer=new NSSpeechRecognizer();

string[] cmds=new string[] {"Computer"};

recognizer.Commands=cmds;
recognizer.BlocksOtherRecognizers=false;
recognizer.DisplayedCommandsTitle="RecognizerTest";
recognizer.Delegate=new RecognizerDelegate();

recognizer.ListensInForegroundOnly=false;
recognizer.StartListening();

Wenn nun das Kommando Computer erkannt wird, wird die Instanz vom RecognizerDelegate angerufen. Das Delegate sieht dabei wie folgt aus:

public class RecognizerDelegate : NSSpeechRecognizerDelegate
{
    public override void DidRecognizeCommand(NSSpeechRecognizer sender, string command)
    {
        //Do something
    }
}

Im Delegate selbst gibt es die Methode DidRecognizeCommand welche als Parameter das erkannte Kommando enthält.

Eine Statusbar-App für Mac OS X mittels Mono und Xamarin Studio entwickeln

Bei Mac OS X befindet sich oben am Bildschirmrand die Menü- und Statusbar. In diesem Artikel soll es darum gehen, eine solche Statusbar-App in Mono mittels des Xamarin Studios zu erstellen. Im ersten Schritt wird dazu ein neues MonoMac-Projekt im Xamarin-Studio angelegt. Wenn man dieses Projekt startet, findet man ein leeres Mac OS X-Fenster vor.

Ein neues MonoMac Projekt wird angelegt

Ein neues MonoMac Projekt wird angelegt

In dem neu angelegten Projekt wird eine neue Klasse mit dem Namen AppController angelegt. Diese wird mit folgendem Inhalt gefüllt:

using System;
using MonoMac.Foundation;
using MonoMac.AppKit;

namespace StatusBarApp
{
    [Register("AppController")]
    public partial class AppController : NSObject
    {
        public AppController()
        {
        }

        public override void AwakeFromNib()
        {
            var statusItem = NSStatusBar.SystemStatusBar.CreateStatusItem(30);
            statusItem.Menu = statusMenu;
            statusItem.Image = NSImage.ImageNamed("status");
            statusItem.HighlightMode = true;

            mcQuit.Activated+=(object sender, EventArgs e) =>
            {
                NSApplication.SharedApplication.Terminate(this);
            };
        }
    }
}

Damit die Anwendung kein Menü und kein Dock-Icon mehr besitzt, müssen wir die Info.plist bearbeiten. In dieser Datei muss ein neuer Schlüssel mit dem Namen Application is agent (UIElement) und dem Typ Boolean angelegt werden. Der Wert des neuen Schlüssels wird dabei auf YES gesetzt.

Der neue Schlüssel wird mit dem PList-Editor des Xamarin Studios hinzugefügt

Der neue Schlüssel wird mit dem PList-Editor des Xamarin Studios hinzugefügt

Nun öffnen wir die Datei MainMenu.xib, welche von Xamarin Studio in Xcode geöffnet wird. Hier ziehen wir ein neues Objekt vom Typ Menu in den Designer und entfernen alle Einträge bis auf einen. Dem verbliebenen Eintrag geben wir die Beschriftung Quit. Anschließend fügen wir ein Object hinzu und begeben uns in den Identity Inspector. Dort tragen wir bei Custom Class unter Class den Namen AppController ein. Das vorhandene Hauptmenü kann anschließend entfernt werden.

Das Design unter Xcode

Das Design unter Xcode

Nun muss das Menü mit dem Quellcode verbunden werden, dazu wird der Assistance Editor in Xcode geöffnet. Als Quelltext wird auf der rechten Seite des Editors die Datei AppController.h ausgewählt. Nun wird das Menü mittels gedrückter Steuerungstaste (Strg/Ctrl) in die Headerdatei gezogen. Damit legen wir ein Outlet an. Dieses bekommt den Namen statusMenu. Das gleiche wird anschließend mit dem Menüeintrag Quit gemacht. In diesem Fall wird dabei eine Action definiert, welche den Namen mcQuit bekommt. Nun kann Xcode wieder geschlossen werden.

Dem Projekt muss nun noch eine 29×22 Pixel große Grafik hinzugefügt werden. Die Grafik (in diesem Fall status.png) wird beim Laden als Icon für die Statusleiste genutzt. Als letzten Schritt können die Dateien MainWindow.cs, MainWindow.xib und MainWindowController.cs entfernt werden. Nachdem diese Objekte auch im AppDelegate entfernt wurden, ist die Anwendung fertig. Der Quelltext des Projektes kann sich auch heruntergeladen werden. Er kann dabei von jedermann frei verwendet (Public Domain) werden.