Quellcodeformatierung unter Xamarin Studio

Unter Xamarin Studio ist es wie in vielen IDEs möglich den Quelltext automatisch zu formatieren. Allerdings unterscheidet sich das Konzept etwas, von anderen C#/.NET IDEs wie dem Visual Studio. Xamarin Studio kennt hierbei einmal Benutzerrichtlinien und normale Einstellungen. In den Einstellungen kann die Codeformatierung für den entsprechenden Nutzer angelegt und modifiziert werden.

Die Einstellungen im Xamarin-Studio

Die Einstellungen im Xamarin Studio

Möchte man bestimmte Einstellungen allerdings auf mehreren Rechnern nutzen, so sollte man lieber eine Benutzerrichtlinie anlegen. Wenn die passenden Einstellungen in der Benutzerrichtlinie definiert sind, können sie auch als Datei exportiert und auf dem anderen Rechner importiert werden. Damit die Nutzerrichtlinie Wirkung zeigt, muss sie in den Einstellungen ausgewählt werden – damit werden die aktuellen Einstellungen mit denen der Richtlinie überschrieben. Ändert man die Richtlinie muss dieser Prozess wiederholt werden. Nachdem die Einstellungen angepasst wurden, kann die geöffnete Datei mittels Ctrl + I neu formatiert werden.

Doxygen Dokumentation für C# unter Mac OS X erzeugen

Ein Quelltext wird während der Entwicklung gewöhnlich kommentiert. Unter C# bzw. .NET gibt es dafür Kommentare nach einem bestimmen Schema. Über einer Methode könnte ein solcher Kommentar z.B. aussehen:

/// <summary>
/// Distance between a and b.
/// </summary>
/// <param name="a">The first vector.</param>
/// <param name="b">The second vector.</param>

Diese Kommentare kann die freie Software Doxygen auswerten und daraus eine Dokumentation erzeugen. Im Gegensatz zu anderen Lösungen wie Sandcastle ist Doxygen betriebsystemübergreifend verfügbar und kann somit – wie in diesem Beispiel – unter Mac OS X genutzt werden. Im ersten Schritt sollte Doxygen installiert werden. Unter Mac OS X kann dies einfach über MacPorts geschehen:

sudo port install doxygen

Nachdem Doxygen installiert ist, sucht man im Terminal den Ordner des Entwicklungsprojektes heraus und gibt dort ein:

doxygen -g projektname.doxygen

Damit wird eine Standard-Doxygen-Konfiguration erzeugt. In dieser Datei werden nun ein paar Änderungen vorgenommen:

PROJECT_NAME = "Testprojekt"
PROJECT_NUMBER = "Release Candidate 1"
OUTPUT_DIRECTORY = docs
RECURSIVE  = YES

Über den Aufruf:

doxygen projektname.doxygen

kann nun die HTML-Dokumentation des Quelltextes erzeugt erzeugt werden und diese anschließend im Browser genutzt werden.

Quelltext im Visual Studio automatisch formatieren

Das Visual Studio formatiert den Quellcode automatisch nach den eingestellten Richtlinien. Wenn man nun aber die Richtlinien ändert, steht man vor dem Problem, das der Quelltext noch nach den alten Richtlinien formatiert ist.

Die Formatierungseinstellungen im Visual Studio

Die Formatierungseinstellungen im Visual Studio

Leider gibt es keine direkte Option im Visual Studio um den bestehenden Quelltext am Stück neu zu formatieren. Allerdings kommt man mit einem kleinen Makro (abgeleitet vom VS Formater Macro) an dieser Stelle weiter. Dazu wird im Visual Studio die Package Manager Console (zu finden unter Tools -> NuGet Package Manager -> Package Manager Console) geöffnet und dort folgendes eingegeben:

function f($projectItems) { $projectItems | ? { $_.Name -ne $null -and $_.Name.EndsWith( ".cs" ) -and -not $_.Name.EndsWith( ".Designer.cs" ) } | % { $win = $_.Open('{7651A701-06E5-11D1-8EBD-00A0C90F26EA}') ; $win.Activate() ; $DTE.ExecuteCommand('Edit.FormatDocument') } ; if ($projectItems) { $projectItems | % { f($_.projectItems) } } }
 
$dte.Solution.Projects | % { f($_.ProjectItems) }

Das Visual Studio öffnet nun alle *.cs Dateien in der geöffneten Solution und formatiert die Quelltexte neu. Dieser Vorgang ist dabei relativ langsam und führt bei größeren Projekten dazu das das Visual Studio einfriert. Auf Stack Overflow gibt es eine elegantere Lösung:

function FormatItems($projectItems) {
    $projectItems |
    % {
        # Write-Host "    Examining item: $($_.Name)";

        if ($_.Name -and $_.Name.ToLower().EndsWith(".cs") `
            -and (-not $_.Name.ToLower().Contains(".designer."))) {

            $win = $_.Open('{7651A701-06E5-11D1-8EBD-00A0C90F26EA}');
            $win.Activate();

            $dte.ExecuteCommand('Edit.FormatDocument');

            if (!$_.Saved) {
                Write-Host "    Saving modified file: $($_.Name)";
                $dte.ExecuteCommand('File.SaveSelectedItems');
            }

            $dte.ExecuteCommand('Window.CloseDocumentWindow');
        }

        if ($_.ProjectItems -and ($_.ProjectItems.Count -gt 0)) {
            # Write-Host "    Opening sub-items of $($_.Name)";

            FormatItems($_.ProjectItems);
        }
    };
}

$dte.Solution.Projects | % {
    Write-Host "-- Project: $($_.Name)";

    FormatItems($_.ProjectItems)
}
;

Bei dieser Lösung wird jede Datei nach der Neuformatierung, gespeichert und wieder geschlossen. Leider wird auch diese Lösung von Datei zu Datei langsamer, so das sie für größere Projekte wiederrum unbrauchbar ist. Mit der Extension Format Document gibt es eine Lösung welche schnell genug ist, allerdings funktioniert diese nur unter Visual Studio 2010. Nach einigen Anpassungen habe ich eine Version gebaut, welche auch unter Visual Studio 2012 und 2013 läuft. Das Problem an dieser Variante ist, das Dateien in Ordnern nur berücksichtigt werden wenn der Ordner im Solution Explorer geöffnet ist. Alles in allem ist keine der vorgestellten Lösungen wirklich optimal, allerdings kann man viele Fälle mit den vorgestellten Lösungen lösen.

Methode nach Notwendigkeit unter .NET invoken

Manchmal ruft man eine Methode unter .NET aus einem anderen Thread heraus auf. Je nachdem wie die Methode aufgerufen wird, kann es notwendig sein die Methode über Invoke aufzurufen. Mit folgendem Pattern geschieht dies nach Notwendigkeit automatisch:

private void MakeSomeFoo()
{
	MethodInvoker method=delegate
	{
		//Do some foo
		DoSomeFoo();
	};

	if(InvokeRequired) BeginInvoke(method);
	else method.Invoke();
}

Im MethodInvoker-Delegate ist der eigentliche Quellcode der Funktion zu finden. Dieser wird je nach Notwendigkeit im korrekten Thread aufgerufen.

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.