Dynamische Silverlight UI mit C(l)ick

Manchmal kommen mir so Ideen und ich probiere rum bis es geht ohne eine Idee zu haben wofür eigentlich. Meine heutige Abendbeschäftigung sind entschärfte Commands um dynamisch ein Formular zu erzeugen. Meist sieht man den Einsatz von Commands im Zusammenhang mit MVVM. Ich will es aber einfacher. Zunächst die Ausgangsituation. Silverlight 4 besitzt ein Command Attribut mit denen man Commands deklarativ zuweisen kann. Weiters kann man mit dem XAMLReader ein UI Element aus einem String erzeugen lassen. Wenn man Events per Attribut zuweisen möchte meckert der XAML Parser.

Also wie sieht normalerweise ein Button Event aus

 <Button Content="fester Button"  
Height="37" Click="Button1_Click"
HorizontalAlignment="Left" Margin="42,35,0,0"
Name="Button1" VerticalAlignment="Top" Width="102" />

Im VB.NET Code dann im Ansatz so

 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)

Alternativ kann man auch im Command Attribut ein Command angeben. Dazu benötigt man aber eine Klasse die das Interface ICommand implementiert. In der minimal Ausstattung wie folgt mit einer simplen MessageBox.

Public Class HannesCommand1
    Implements ICommand
    Public Sub HannesCommand1()
    End Sub
    Public Function CanExecute(ByVal parameter As Object) As Boolean Implements System.Windows.Input.ICommand.CanExecute
        Return True
    End Function

    Public Event CanExecuteChanged(ByVal sender As Object, ByVal e As System.EventArgs) Implements System.Windows.Input.ICommand.CanExecuteChanged

    Public Sub Execute(ByVal parameter As Object) Implements System.Windows.Input.ICommand.Execute
        MessageBox.Show("hannescommand1")
    End Sub
End Class

Das Command kann aber nicht direkt verwendet werden. Der Umweg muss über die Ressourcen. In jedem Fall benötig man den Namensraum auf das aktuelle Silverlight Projekt das den Namen KoelnSL heißt. Der Namensraum wird willkürlich local genannt.

 xmlns:local="clr-namespace:KoelnSL"
  

Das Command wird dann als Unterelement deklariert über den Namesraum local und den Klassennamen.

<Button Content="Button" Height="38" 
    HorizontalAlignment="Left" Margin="121,227,0,0" 
Name="Button1" VerticalAlignment="Top" Width="105" > <Button.Command> <local:HannesCommand1></local:HannesCommand1> </Button.Command> </Button>

Alternativ besteht auch die Möglichkeit über eine Statische Ressource zu gehen. Die Instanz wird per x:Key willkürlich hCommand benannt.

<UserControl.Resources>
        <local:HannesCommand1 x:Key="hCommand"></local:HannesCommand1>
</UserControl.Resources>

Im XAML des Button Elements kann man dann mit kurzer Syntax direkt per Command Attribut die Bindung deklarieren auf hCommand.

<Button Content="Button" Height="38" Command="{StaticResource hCommand}"
                 HorizontalAlignment="Left" Margin="121,227,0,0" 
Name="Button1" VerticalAlignment="Top" Width="105" >

Soweit die Theorie zum Teil Commands. Als nächstes gehts um das dynamsiche laden von XAML. Die passende Klasse ist XAMLReader zu finden im Namenraum System.Windows.Markup. Damit kann aus einem String ein UIElement erstellt werden, das man an den XAML Tree anhängen kann. Der Parser benötigt allerdings den XAML presentation Namensraum im String.

 Private Sub Button1_Click(ByVal sender As System.Object, 
ByVal e As System.Windows.RoutedEventArgs) Dim s As String = "<Button xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" " + " Content=""dynamischer Button"" Command=""{StaticResource hCommand}""
Height=""37"" HorizontalAlignment=""Left"" "
+ " Margin=""42,107,0,0"" Name=""Button2"" VerticalAlignment=""Top"" Width=""189"" >" + "</Button>" Dim xaml As UIElement = XamlReader.Load(s) LayoutRoot.Children.Add(xaml) End Sub

Das Problem war bei mir das der XAML Parser von Silverlight zur Laufzeit einen Fehler wirft, weil er hCommand nicht findet. Es scheint ein Problem in der Hierarchie geben, dem ich später auf den Grund gehen werde. Aber ich weis das wenn eine Resource nicht gefunden wird, der Parser in den Ressourcen von APP.XAML nachschlägt. Deshalb also einfach dort deklariert.

<Application 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" x:Class="KoelnSL.App" xmlns:local="clr-namespace:KoelnSL"> <Application.Resources> <local:HannesCommand1 x:Key="hCommand1">
</local:HannesCommand1> </Application.Resources> </Application>

Demnächst auch ein echtes MVVM Beispiel mit Binding.

Kommentar schreiben