Freitag, 6. Juni 2014

Lokalisierung einer Windows 8 Store App

Die Lokalisierung in Windows Store Apps funktioniert denkbar einfach. Soll Beispielsweise der Text eines TextBlock's in verschiedenen Sprachen dargestellt werden, so muss diesem Control lediglich eine x:Uid zugewiesen werden. Zum Beispiel folgendermaßen:
 <Page  
   x:Class="App2.MainPage"  
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"  
   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  
   mc:Ignorable="d">  
   <Grid HorizontalAlignment="Center" VerticalAlignment="Center">  
     <TextBlock x:Uid="MyTextBlock" />  
   </Grid>  
 </Page>  

Jetzt muss in dem Projekt ein Ordner angelegt werden, der Strings heißt. In diesen kommen weitere Verzeichnisse, die den Namen der gewünschten Sprache im BCP-47 Format haben. Z.B. de-DE oder nur de oder en. Jedes dieser Verzeichnisse bekommt eine Resources.resw Datei.

Für unser Beispiel legen wir die Resource MyTextBlock.Text mit dem Wert "Hallo Welt!" im Deutschen und im Englischen das gleiche mit dem Wert "Hello World!" an. Das Pattern ist also Uid.PropertyName und zeigt, dass es nicht nur möglich ist, den anzuzeigenden Text, sondern auch andere Properties eines Controls zu setzen.

Das war es schon, wird die Anwendung gestartet, wird der Text in der jeweiligen Standard Sprache angezeigt.

Donnerstag, 3. April 2014

XP sagt auf Wiedersehen

Microsoft hat es schon vor einiger Zeit angekündigt und nun ist es soweit! Windows XP wird in 5 Tagen und 6 Stunden den Support einstellen!

Spätestens jetzt sollten auch die letzten Firmen und Privatpersonen Abschied nehmen und sich nach etwas neuem umschauen. Denn ohne Sicherheitsupdates und Hotfixes wird es auf kurz oder lang Probleme mit dem System geben.

Den aktuellen Countdown gibt es direkt von Microsoft hier!

Donnerstag, 13. März 2014

Asynchrone Commands testen leicht gemacht

Was war das immer für ein Krampf die Execute Methode eines Commands zu testen, das asynchonen Code ausführt. Das hat aber schon seit geraumer Zeit ein Ende. NUnit unterstützt seit der Version 2.6.2 das async await, das mit C# 5.0 der Entwicklerwelt zur Verfügung gestellt wurde.

Für alle Commands, die längere Aktionen ausführen sollen, nutze ich die folgende Klasse:
 public class AsyncCommand<TExecuteArg, TCanExecuteArg> : ICommand  
 {  
      public event EventHandler CanExecuteChanged  
      {  
           add  
           {  
                if (_canExecuteMethod == null)  
                     return;  
                CommandManager.RequerySuggested += value;  
           }  
           remove  
           {  
                if (_canExecuteMethod == null)  
                     return;  
                CommandManager.RequerySuggested -= value;  
           }  
      }  
      public AsyncCommand(Func<TExecuteArg, Task> executeMethod, Func<TCanExecuteArg, bool> canExecuteMethod = null)  
      {  
           if (executeMethod == null)  
                throw new ArgumentNullException("executeMethod");  
           _executeMethod = executeMethod;  
           _canExecuteMethod = canExecuteMethod;  
      }  
      public Task Execute(TExecuteArg arg)  
      {  
           return _executeMethod(arg);  
      }  
      public bool CanExecute(TCanExecuteArg arg)  
      {  
           return _canExecuteMethod == null || _canExecuteMethod(arg);  
      }  
      bool ICommand.CanExecute(object parameter)  
      {  
           return CanExecute((TCanExecuteArg) parameter);  
      }  
      async void ICommand.Execute(object parameter)  
      {  
           await Execute((TExecuteArg) parameter);  
      }  
      private readonly Func<TExecuteArg, Task> _executeMethod;  
      private readonly Func<TCanExecuteArg, bool> _canExecuteMethod;  
 }
Wie man sehen kann, ist die Execute Methode mit dem async Keyword versehen. Alles was in der Execute Action ausgeführt wird, kann also asynchron sein.

Die Benutzung ist einfach, so wie man es vom async/await bzw. von den synchronen Commands her kennt. Hier ein Beispiel in dem im MainViewModel drei Sekunden nach dem Ausführen des Commands eine Nachricht gesetzt werden soll.
 public class MainViewModel : ViewModelBase  
 {  
      public string Message  
      {  
           get { return _message; }  
           set  
           {  
                _message = value;  
                NotifyPropertyChanged("Message");  
           }  
      }  
      public AsyncCommand<object, object> LongRunningCommand { get; private set; }  
      public MainViewModel()  
      {  
           LongRunningCommand = new AsyncCommand<object, object>(OnLongRunningExecute);  
      }  
      private async Task OnLongRunningExecute(object args)  
      {  
           await Task.Run(() => Thread.Sleep(TimeSpan.FromSeconds(3)));  
           Message = "Test message";  
      }  
      private string _message;  
 }
Die OnLongRunningExecute Methode ist hier auch mit dem async Keyword versehen und in der Methode werden dann die drei Sekunden gewartet bevor die Nachricht gesetzt wird.
Diese Implementierung hat den großen Vorteil, das die Anwendung nicht einfriert nachdem der Button geklickt wurde.

Und nun zum eigentlichen Thema: Testen!
Wie schon geschrieben, unterstützt NUnit seit der Version 2.6.2 das Ausführen von asynchronen Tests. Dementsprechend einfach ist es das Command zu testen:
 [TestFixture]  
 public class LongRunningCommand  
 {  
      [Test]  
      public async void Usage()  
      {  
           var viewModel = new MainViewModel();  
           await viewModel.LongRunningCommand.Execute(null);  
           viewModel.Message.Should().Be("Test message");  
      }  
 }
Benutzt man eine ältere Version von NUnit, läuft der Test in weniger als einer Sekunde durch und wird beim Assert schief laufen.

Hier der Sourcecode mit Visual Studio 2012 Solution.

Mittwoch, 12. März 2014

Window Einstellungen in UserSettings komfortabel speichern

Es ist wahrscheinlich schon seit Windows 95 Standard, dass sich eine Anwendung wieder an der Stelle öffnet, an der sie das letzte mal beendet wurde.

WPF spielt hier gut mit den UserSettings zusammen und es können ohne großen Aufwand alle nötigen Daten gesichert und für den nächsten Anwendungsstart wieder geladen werden.

Bei der Settings.settings Datei muss drauf geachtet werden, dass der Zugriff auf public gesetzt wird. Ansonsten müssen einfach alle Eigenschaften eingetragen werden, die gesichert werden sollen.


Im XAML benötigen man noch einen Zugriff auf die Settings. Diesen Zugriff stelle ich in der App.xaml zur Verfügung.

 <Application x:Class="Sample.App"  
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
        xmlns:properties="clr-namespace:Sample.Properties">  
   <Application.Resources>  
     <ResourceDictionary>  
       <properties:Settings x:Key="Settings" />  
     </ResourceDictionary>  
   </Application.Resources>  
 </Application>

Danach können diese Eigenschaften an dem Hauptfenster der WPF Anwendung gebunden werden. In meinem Beispiel in der MainView.xaml.

 <Window x:Class="Sample.MainView"  
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
     Width="{Binding Source={StaticResource Settings}, Path=Default.MainViewWidth, Mode=TwoWay}"  
     Height="{Binding Source={StaticResource Settings}, Path=Default.MainViewHeight, Mode=TwoWay}"  
     Top="{Binding Source={StaticResource Settings}, Path=Default.MainViewTop, Mode=TwoWay}"  
     Left="{Binding Source={StaticResource Settings}, Path=Default.MainViewLeft, Mode=TwoWay}"  
     WindowState="{Binding Source={StaticResource Settings}, Path=Default.MainViewWindowState, Mode=TwoWay}"  
     Title="Sample">  
   <Grid />  
 </Window>

Es muss beachtet werden, dass der Mode beim Binding auf TwoWay gesetzt wird, weil die Werte sonst nur gelesen, aber nicht wieder zurück in die Settings geschrieben werden.

Zum Schluss müssen die Einstellungen noch gesichert werden. Das mache ich generell beim Beenden der Anwendung. Ich mache dies allerdings nur, wenn die Anwendung ordnungsgemäß beendet wird, um ggf. einen inkonsistenten Zustand der Daten zu verhindern. Diesen Zustand wird es bei den hier gezeigten Eigenschaften zwar nie geben, allerdings können ja noch beliebig viele andere Eigenschaften in den Settings gesichert werden, bei denen die Konsistenz sichergestellt werden muss.
In der App.xaml.cs habe ich demnach die OnExit Methode überschrieben und rufe dort ggf. die Save Methode der Settings Klasse auf.

 public partial class App  
 {  
      protected override void OnExit(ExitEventArgs e)  
      {  
           base.OnExit(e);  
           if (e.ApplicationExitCode == 0)  
                Settings.Default.Save();  
      }  
 }

Nun sollte sich bei jedem Start der Anwendung das Fenster genau dort wieder öffnen, an der es zuletzt auch geschlossen wurde.

Freitag, 24. Januar 2014

Lambda Expressions nichts anderes als ein Kompilerschwindel?!

Lambda Ausdrücke hat wahrscheinlich jeder C# Entwickler lieben gelernt. Lang definierte Delegates gehören schon lange der Vergangenheit an. Aber was genau steckt eigentlich hinter diesen Lambda Expressions?

Eigentlich gar nichts so sehr besonderes. Der Compiler macht am Ende ganz normale Klassen- und Methodenaufrufe draus. Wer ab und an mal seine Assemblies decompiliert ist bestimmt auch schon mal auf die DisplayClass Klassen gestoßen. Diese sind mit dem CompilerGenerated Attribut versehen und dienen genau für unseren Zweck: Lambda Ausdrücke.

So wird aus folgendem Code:
 namespace LambdaSpike  
 {  
   public class ClassWithLambdaExpression  
   {  
     public ClassWithLambdaExpression()  
     {  
       var i = 3;  
       var foo = new Action(() => Console.Write("{0}: do something..", i));  
     }  
   }  
 }

Folgendes nachdem es der Compiler unter die Mangel genommen hat:
 public class ClassWithLambdaExpression  
 {  
   [CompilerGenerated]  
   private sealed class c__DisplayClass1  
   {  
     public int i;  
     public void b__0()  
     {  
       Console.Write("{0}: do something..", this.i);  
     }  
   }  
   public ClassWithLambdaExpression()  
   {  
     ClassWithLambdaExpression.c__DisplayClass1 c__DisplayClass = new ClassWithLambdaExpression.c__DisplayClass1();  
     c__DisplayClass.i = 3;  
     Action foo = new Action(c__DisplayClass.b__0);  
   }  
 }

Dienstag, 21. Januar 2014

Performance Schub im Visual Studio WPF Designer

Bei der Entwicklung von WPF Anwendungen kann einen der Designer im Visual Studio aufgrund der Performance schon mal zur Weißglut bringen. Eine kleine Änderung im XAML Code hat zur Folge, dass das komplette Projekt neu kompiliert wird. Das kann je nach Projektgröße unter Umständen mehrere Sekunden dauern.

Hat man einen Style bzw. einen Theme im XAML Code definiert, so wird dieser natürlich auch bei jeder Änderung im Designer mit kompiliert. Das kann je nach größe recht lange dauern.

Abhilfe kann dabei die Auslagerung des Styles schaffen. Legt man ein eigenes Projekt für diese Styles an, so muss dieser Code nicht jedes mal auf's neue kompiliert werden. Als weiteren Vorteil sehe ich die bessere Trennung zwischen den eigentlichen Views und deren Design.