Monthly Archives: October 2010

Sprachumschaltung und WPF

Wer mit .NET “aufgewachsen” ist, der kennt das System.Threading.Thread.CurrentThread.CurrentCulture bzw. CurrentUICulture. Damit kann man z.B. in WinForms-Anwendungen die Formatierungen der Ausgaben beeinflussen. Diese Culture wird auch in den meisten Objekten verwendet wenn man “ToString()” aufruft. Bestes Beispiel dafür ist DateTime. Intern wird hier die aktuelle Culture (CurrentCulture) des aktuellen Threads verwendet.

Dieses ganze Konzept ist aber nicht so ganz WPF kompatibel. Dazu gibt es zwei Gründe: Erstens basiert bei WPF (fast) alles auf DependencyProperties, welche Vererbung und auch Änderungsbenachtrichtigungen schon automatisch unterstützen. Auch spielen die Converter eine große Rolle beim Anzeigen von Daten. Dabei wird immer eine Culture mitgegeben in den Konvertierungsmethoden mitgegeben. AUs diesem Grunde spielt die “Thread.CurrentThread.CurrentCulture” in WPF keine Rolle mehr!

Die Sprache wird in WPF also auch über ein DependencyProperty umgeschaltet: FrameworkElement.Language

Das kann man einfach testen indem man z.B. ein DateTime-Property an an TextBlock bindet. Dabei wird die Datum/Uhrzeit immer in en-us angezeigt! Egal welche Sprache nun das Betriebssystem oder den Benutzer hat. Ob dies ein Bug oder Feature ist, sei mal dahingestellt.

Um also beim Starten der Applikation die Sprache auf die aktuelle Sprache zu setzen, muss man für jedes TopLevel-Fenster das Language Property korrekt initialisieren, am besten im Konstruktor:

this.Language = 
  System.Windows.Markup.XmlLanguage.GetLanguage(
    System.Threading.Thread.CurrentThread.CurrentUICulture.Name
  );

Will man eine Sprachumschaltung dynamisch machen, so könnte man auch ein Binding auf dieses Language-Property machen. Dazu muss man aber wissen, dass ja jedes Binding auch eine Culture hat. Da aber die Culture aus dem vererbeten “Language” DependencyProperty kommt beisst sich hier die Katze in den Schwanz… aus diesem Grund scheitert auch ein Binding der Form:

Language={Binding MyCurrentCulture.Name}

mit der Fehlermeldung (InnerException):
Binding for property 'Language' cannot use the target element's Language for conversion; if a culture is required, ConverterCulture must be explicitly specified on the Binding.
Wer diese Meldung genau liest erkennt, dass man für den Converter die Culture explizit vorgeben muss! Damit muss der Bindning Ausdruck z.B. wie folgt aussehen:

Language={Binding MyCurrentCulture.Name,
  ConverterCulture={x:Static glob:CultureInfo.InvariantCulture}}

Dabei ist der Namespace “glob”:

xmlns:glob="clr-namespace:System.Globalization;assembly=mscorlib"

Damit wird nun das Binding möglich.
Und natürlich wird jedes Binding nochmals ausgeführt (bzw. der passende Converter aufgerufen), bei welcher die Language vererbt wurde (was eigentlich überall der Fall ist).
Man sieht also auch: Die Anzeige wird nicht nicht bei Werteänderung aktualisiert, sondern auch bei “Language-Property” Änderung 😉

Anbei mal ein ganz kleines Testprojekt, welches das Umschalten der Language zur Laufzeit anhand dem DateTime aufzeigt:
WpfCulture.zip

TFS 2010 – Hotfix Rollup ist verfügbar

Für den TFS 2010 gibt es schon diverse “Hotfix Rollups”. Aktuell ist der September 2010 Hotfix Rollup verfügbar. Er behebt einige Fehler im TFS 2010.
Mehr Infos siehe:
A hotfix rollup (build 10.0.30319.341) is available for Team Foundation Server 2010

Der Hotfix kann hier runtergeladen werden:
KB983504 – TFS 2010: Important Post-RTM Releases – Home
oder auch hier:
TFS 2010: Important Post-RTM Releases

TFS2010 – Verwaltung von Alerts

Mit den TFS Power Tools kann man ja immerhin seine eigenen Alerts verwalten. Leider ist es damit als Admin aber auch nicht möglich andere Alerts zu verwalten bzw. anzuzeigen oder zu ändern.
Auch habe ich bei mir den Effekt, dass E-Mail Alerts welche ich für andere angelegt habe, nicht gesendet werden…

Um den Verlauf der Benachrichtigung zu sehen, kann man direkt auf dem Data-Tier in der SQL-Datenbank Folgende Abfrage ausführen:

SELECT TOP 10 [HistoryId],[JobSource],[JobId],[QueueTime],[StartTime],[EndTime],[AgentId]
,[Result],[ResultMessage],[QueuedReasons],[QueueFlags]
  FROM [Tfs_Configuration].[dbo].[tbl_JobHistory]
  WHERE [JobId] = 'A4804DCF-4BB6-4109-B61C-E59C2E8A9FF7'
  ORDER BY [StartTime] DESC

Um zu sehen, was für Alerts alles eingerichtet sind kann man die Folgende Abfrage ausführen:

SELECT TOP 50 [Id],[EventType],[Expression],[SubscriberId]
,[Schedule],[DeliveryType],[Address],[Classification]
  FROM [Tfs_DefaultCollection].[dbo].[tbl_EventSubscription]

Das “DefaultCollection” muss man durch die entsprechende TFS-Collection ersetzen.

LowLevel Hooks sind böse

Es gibt ja viele, die stehen auf Hooks. Es gibt auch sog. LowLevel Hooks, welche keine DLL benötigen, sondern im Kontext des Prozesses (Threads) laufen, welche das SetWindowsHookEx aufgerufen hat.
Das Problem ist nun bei solchen Hooks, das diese in der Vergangenheit sehr oft zu Verzögerungen im ganzen Windows System geführt haben, wenn ein Hook in der Callback etwas länger gebraucht hat oder sonstwie Fehler gehabt hat.

Dies hat MS nun versucht zu in Windows 7 (RTM) beheben. Die Lösung ist einfach:
Der Hook wird einfach entfernt, wenn er 11 Mal länger als 300 ms gebraucht hat 😉 (wobei ich 300 ms immer noch sehr lang finde…)

Siehe auch: Global hooks getting lost on Windows 7