aneinandergereiht: POCO nach XML oder JSON in Silverlight


Aktuell bin ich wieder mal in einer Silverlight Schulung. Obwohl ich das Thema wirklich von A-Z kenne, entdecke ich immer wieder Neues. Dieses mal im ausgezeichneten Silverlight 4 Buch von Thomas Claudius Huber (erschienen bei Galileo). Thomas macht auf Seite 833 etwas, was ich so nicht tun würde. Er nimmt einen DataContractJsonSerializer um einen JSon Rückgabe eines REST Services nach POCO zu wandeln. Interessante Idee, aber nicht im Sinne des Erfinders. Dafür waren wohl eher die Klassen JSoneArray oder JSonObject gedacht. Nicht desto trotz – einen Blick wert. Aber ich möchte erst mal die Basics aufgreifen. Ein Objekt, hier z.B. Person muss serialsiert werden um z.B. im Isolated Storage dauerhaft gespeichert zu werden.

Zunächst einmal ein Prototyp der einfach das Objekt serialisiert und im UI ausgibt. Es müssen drei Namensräume eingebunden werden

System.IO
System.Runtime.Serialization
System.Text

Dann wird der klassische DataContractSerializer angeworfen der XML erzeugen wird. Am Ende wird das erzeugte Byte Array in UTF Encodiert um die Anzeige zu realisieren.

Dim p As New person
Dim ms As New MemoryStream()
Dim ser As New DataContractSerializer(GetType(person))
ser.WriteObject(ms, p)
Dim array() As Byte = ms.ToArray()
ms.Close()
TextBlock1.Text = Encoding.UTF8.GetString(array, 0, array.Length)
image

Alternativ gibt es auch noch ein Klasse XMLSerializer mit den Methoden Serialize und Deserialize auf die ich hier aktuell nicht eingehen möchte. Will man Json erzeugen muss man einen anderen Serialisierer nehmen. Der wiederum findet sich im Namensraum System.Runtime.Serialization.Json. Dann muss nur eine Zeile getauscht werden.

Dim ser As New DataContractJsonSerializer(GetType(person))
image

Deutlich zu erkennen ist, das die Datenmenge bei Json im Vergleich zu XML deutlich geringer ist. Aus diesem Grund sehe ich auch SOAP als noch viel schwer gewichtigeres XML Format sehr kritisch und sehe die Zukunft eher in REST basierten Ansätzen wie das moderne ODATA.

Wie kommen nun die Daten wieder zurück? Der sehr gut verkürzte Code.

Dim p As New person
Dim ser As New DataContractJsonSerializer(GetType(person))
Dim ms As New MemoryStream(Encoding.UTF8.GetBytes(TextBlock1.Text))
p = ser.ReadObject(ms)
ms.Close()
    
Im Grund nichts Neues. Das gibts in .NET schon eine ganze Weile (seit 3.5).


Erstellt am: 15.09.2010 21:54:48 | Kommentare: | Erstellt von: Hannes Preishuber
Kategorien: .Net, Silverlight, VB,


Asynchrone Validierung von Benutzereingaben mit INotifydataErrorInfo


Manchmal ist die Wahl wirklich die Qual. In Silverlight 4 gibt es mindestens vier mir bekannte Möglichkeiten in Dialogen Eingaben des Benutzers zu prüfen.

  • per Exception (von Anbegin)
  • per Eigenschaftsattribut (mit RIA Services eingeführt)
  • IDataErrorInfo
  • INotifyDataErrorInfo (neu in SL4)

Mit dem letzteren werden wir uns hier nun beschäftigen. Wenn eine Datenklasse das Interface INotifyDataerrorInfo implementiert kann von andere Stelle im Code ein Fehler Event aufgerufen werden. Im Unterschied zu IDataErrorInfo kann dann ein Property auch mehrere Fehler besitzen (ob es sich darüber freuen wird?) was den Code nicht einfacher macht.

Darüber hinaus kann man direkt das ErrorsChanged Event aufrufen und so auch asynchron validieren.

Mein folgendes Silverlight Beispiel ist Teil einer kleinen APP die die UST ID auf Gültigkeit beim zuständigen Finanzamt prüft. Das heißt es werden Daten an einen Webservice geschickt und dieser antwortet für jedes Feld ob dies gültig oder ungültig ist. Der Benutzer muss dann die Eingabe korrigieren oder seinem Geschäftspartner mitteilen das eine UST freie Lieferung nicht möglich ist.

Dazu erstellte ich mir einen Datenklasse die später dann auch an das UI per Binding gebunden wird. Die Attribute dienen ebenfalls der Eingabe validierung bzw dem Layout des Dialoges. Dort kommen Label Steuerelemente zum Einsatz die dann z.B. Display Name verwenden.

Public Class ustidFirma
    Implements INotifyDataErrorInfo
    <Required()>
    <Display(Name:="Ustid")>
    Public Property ustid As String
    <Required()>
    <Display(Name:="Firma")>
    Public Property firma As String

Wesentlicher ist aber die Logik. Eine exemplarische Implementierung nachdem das Interface InotifyDataErrorInfo implementiert wird. Es werden zwei Methoden benötigt. Die Eigenschaft HasErrors definiert ob grundlegend Fehler vorhanden sind. Die Funktion GetErrors gibt eine Liste der Fehler zurück die für einen bestimmte Eigenschaft, z.B. ustid, vorliegen. Das ErrorsChanged Event dient dazu die UI über Änderungen zu informieren.

Imports System.ComponentModel
Public Class test1
    Implements INotifyDataErrorInfo
    Public Event ErrorsChanged(ByVal sender As Object, 
ByVal e As System.ComponentModel.DataErrorsChangedEventArgs)
Implements System.ComponentModel.INotifyDataErrorInfo.ErrorsChanged Public Function GetErrors(ByVal propertyName As String)
As System.Collections.IEnumerable
Implements System.ComponentModel.INotifyDataErrorInfo.GetErrors End Function Public ReadOnly Property HasErrors As Boolean
Implements System.ComponentModel.INotifyDataErrorInfo.HasErrors Get End Get End Property End Class

Zurück zu meinem Beispiel UST Prüfung. Um die Fehler zu verwalten erstelle ich mir eine Liste für die Attribute und deren Fehler.

 Private errors As New Dictionary(Of String, List(Of String))

HasErrors liefert dann zurück ob in der Liste was drin steht.

Public ReadOnly Property HasErrors As Boolean Implements System.ComponentModel.INotifyDataErrorInfo.HasErrors
 Get
     Return errors.Count > 0
 End Get
End Property

Die Funktion GetErrors, liefert die Fehlerliste für das ausgewählte Property.

Public Function GetErrors(ByVal propertyName As String) 
As System.Collections.IEnumerable
Implements System.ComponentModel.INotifyDataErrorInfo.GetErrors If errors.ContainsKey(propertyName) Then Return errors(propertyName) Else Return Nothing End If End Function

 

Eine manuell von mir erstellte Hilfsfunktion RaisErrorsChanged füllt die Fehlerliste und wirft dann das Event um im  Userinterface die Bindung zu aktualisieren.

Public Sub RaiseErrorsChanged(ByVal propertyName As String, ByVal Fehler As String)
 If Not errors.ContainsKey(propertyName) Then errors(propertyName) = New List(Of String)()
   errors(propertyName).Add(Fehler)
   RaiseEvent ErrorsChanged(Me,
   New DataErrorsChangedEventArgs(propertyName))
End Sub

Diese Sub wird von mir sozusagen per Hand aufgerufen. Die dazu gehörige Logik blende ich hier aus. Stellen Sie sich einfach einen Button vor der folgenden Code enthält.

 Dim ui As ustidFirma = LayoutRoot.DataContext
 ui.RaiseErrorsChanged("ustid", "USTID falsch")

Da es sich um eine gebundenes Objekt handelt kann ich jederzeit dieses Objekt zurückholen und darauf dann die Methode RaiseErrorsChanged aufrufen. Im XAML Code sind dafür mehrere Dinge nötig. Der Namensraum (hier willkürlich local genannt) um auf die Projektklassen zugreifen zu können. Die deklarative Instanz mit dem frei gewählten Namen uf1.  Das Grid mit dem Namen Layoutroot ( Silverligth Default) bekommt dann dieses Objekt uf1 per Binding in seinem DataContext zugewiesen. Beachten Sie das dies notwendig ist, um im vorigen Codeblock damit agieren zu können und das Label und die Textbox zu Binden. Dabei ist noch wesentlich das in der Bindung der Text Eigenschaft der Textbox das Binding Attribut ValidatesOnNotifyDataErrors gesetzt wird. Der folgende XAML Code ist stark gekürzt.

xmlns:local="clr-namespace:KoelnSL"
             >
    <UserControl.Resources>
        <local:ustidFirma x:Key="uf1"/>
..... <Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource uf1}}"> ..... <sdk:Label Target="{Binding ElementName=txtmyID}"/> <sdk:Label Target="{Binding ElementName=txtID}"/> ..
<TextBox x:Name="txtmyID" /> <TextBox x:Name="txtID"
Text="{Binding ustid,Mode=TwoWay,ValidatesOnExceptions=true,
NotifyOnValidationError=true,ValidatesOnNotifyDataErrors=True}"
/> .. </Grid>

Der Vollständigkeit halber noch der fertige Dialog.

image



Erstellt am: 15.09.2010 06:57:51 | Kommentare: | Erstellt von: Hannes Preishuber
Kategorien: .Net, Silverlight, VB,


WebCam Bild schiessen und in Isolated Storage speichern


Man muss das Rad nicht immer neu erfinden. Im heutigen Beispiel kommt deshalb die Library Imagetools zum Einsatz. Diese verwendet wiederum eine Zip Bibliothek und die wiederum … Und am Ende wird meine Silverlight Anwendung davon profitieren. Der “Use Case” ist eine Webcam im Browser. Der Benutzer kann ein Foto Schießen und dieses dauerhaft speichern.

Den Part mit der Webcam halte ich hier sehr kurz. Zur Darstellung wird ein einfaches Rechteck (Rectangle1) verwendet.

 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
CaptureDeviceConfiguration.GetAvailableVideoCaptureDevices(0)
  Dim wb As New VideoBrush
  wb.SetSource(cs)
  Rectangle1.Fill = wb
  If CaptureDeviceConfiguration.AllowedDeviceAccess Or CaptureDeviceConfiguration.RequestDeviceAccess Then
     cs.Start()
  End If
End Sub

Wenn der Benutzer auf den Button drückt läuft das aktuelle Bild als Video. Ein zweiter Button dient dazu den Snapshot zu erstellen und das Bild zu speichern. Dazu müssen die DLL’s ImageTools, ImageTools.IO.Png und ImageTools.Utils als Referenz eingebunden werden.

image

Frage Nummer eins ist, wie kommt man ans Bild? Und in welchem Format? Wer in den Dokus nachschlägt wird immer das Event CaptureImageAsync finden. Allerdings kann man auch direkt die Writeablebitmap Klasse verwenden um einen Screenshot eines beliebigen UIElements zu erstellen. Auch bei CaptureImageAsync erhält man ein Obekt vom Typ WriteableBitmap. Braucht nur ein bisschen mehr Code. Ein weiterer Unterschied ist, das Writeablebitmap erst nach vollständigen Rendering den “Screenshot” erstellt. Mit CaptureImageasync  bekommt man den Screenshot schneller aber ohne Effekte ala Pixelshader. Für das Capturen von laufenden Videos braucht es aber noch ein wenig mehr. Dazu dient dann Videosink. Mehr dazu im Blog von Rene Schulte.

Im Silverlight Isolated Storage kann dann das Bild serialisiert gespeichert werden. Dazu wird aus dem WriteableBitmap zunächst ein Bild vom Typ PNG erzeugt. Ein netter Trick ist die Extension Methode ToImage, die der WriteableBitmap Klasse zugewiesen wird. (enthalten in Utils). Der PngEncoder erzeugt das korrekte PNG Format. Es liegen auch noch Encoder für BMP, GIF und JPG bei.

Private Sub speichern_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles speichern.Click
 Dim wb As New WriteableBitmap(Rectangle1, Nothing)
 Image1.Source = wb
 Dim iso As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication
 Using sr As IsolatedStorageFileStream = iso.OpenFile("bild" + Date.Now.ToString("YYYMMDDHHmmss") + ".png", FileMode.OpenOrCreate)
   Using bw As BinaryWriter = New BinaryWriter(sr)
     Dim enc As PngEncoder = New PngEncoder()
     Dim bytesImage As Byte()
     Using ms As MemoryStream = New MemoryStream()
       Dim itImage = wb.ToImage()
       enc.Encode(itImage, ms)
       bytesImage = ms.ToArray()
       bw.Write(bytesImage)
     End Using
  End Using
 End Using
End Sub

Ziemlich cool ist, das die Bilder dann auch wirklich physikalisch auf der Festplatte rum liegen.

image



Erstellt am: 13.09.2010 21:10:30 | Kommentare: | Erstellt von: Hannes Preishuber
Kategorien: .Net, VB, Silverlight,


Bild aus Explorer in die Silverlight Anwendung ziehen


“Nur kein Code ist guter Code”. Ein Zitat aus meinem Munde [Hannes Preishuber]. Entsprechend versuche ich immer mit minimalen Code mein Ziel zu erreichen. Vielleicht auch ein Grund warum ich mit Layern und MVxx recht sparsam umgehe.

Deshalb bin ich auch ganz stolz auf mein Silverlight Bilder Drag & Drop Beispiel. Fünf Zeilen Code. Weniger geht kaum.

Drag& Drop ist eine Funktion in Silverlight 4 die sowohl für OOB als auch in Browser Anwendungen funktioniert. Der Benutzer kann eine oder mehrere Dateien auf ein UIElement ziehen und dort fallen lassen. Dafür muss im UIElement das Attribut Allowdrop auf true gesetzt werden. Dann werden vier mögliche Events gefeuert.

  • DragEnter
  • DragOver
  • DragLeaver
  • Drop

Wirklich wichtig ist nur das letzte Ereignis Drop. Die anderen Events könnten verwendet werden um den Benutzer durch z.B. Farbänderungen sichtbar zu machen wohin er gerade dropped. In Meinem Beispiel möchte ich auf ein Image Element ein Bild ziehen können. Da das Image ohne Bild nicht sichtbar ist, reagiert es auch auf keine Events und ist nicht abschätzbar wo die Grenzen sind. Ähnliches passiert meinen Silverlight Kurs Teilnehmer recht häufig mit einem Rechteck. Das ist auch nur clickbar wenn es mit einer Brush gefüllt ist.

Um also den Rahmen zu zeichnen und das Drop Event zu bekommen, packe ich einfach das Image in ein Border der gefüllt ist.

<Border HorizontalAlignment="Left" 
Height="211" Margin="75,0,0,0" Drop="Image1_Drop" AllowDrop="True" VerticalAlignment="Top"
Width="202"> <Border.Background> <LinearGradientBrush EndPoint="0.5,1"
StartPoint="0.5,0"> <GradientStop Color="Black" Offset="0"/> <GradientStop Color="White" Offset="1"/> </LinearGradientBrush> </Border.Background> <Image
MouseLeftButtonDown="Image1_MouseLeftButtonDown" x:Name="Image1" Stretch="Fill" /> </Border>

Im Drop  Event bekommt man per e.Data die Liste der gedroppten Dateien. In meinem Fall nehme ich einfach die erste Datei im Index und gehe davon aus das es ein JPG oder PNG ist. Dann wird die Datei per Filestream geöffnet und einem BitmapImage zugewiesen. Dieses wiederum ist die perfekte Quelle für das Image Element.

Private Sub Image1_Drop(ByVal sender As System.Object, 
ByVal e As System.Windows.DragEventArgs) Dim fi As FileInfo =
e.Data.GetData(DataFormats.FileDrop)(0) Using fs As FileStream = fi.OpenRead Dim bi As New BitmapImage bi.SetSource(fs) Image1.Source = bi End Using End Sub

 

imageimage

wie gesagt alles Beispiele aus meiner Silverlight Schulung. Der nächste Termin ist in Leipzig.



Erstellt am: 09.09.2010 20:34:00 | Kommentare: | Erstellt von: Hannes Preishuber
Kategorien: .Net, Silverlight, VB,


Silverlight Zwischenablage


Ein weiteres (sehr kleines) Beispiel aus meiner Silverlight Trickkiste. Irgendwann muss ich das mal strukturieren und ein Silverlight Tutorial draus machen. Da irgendwann in weiter Zukunft liegt zunächst mal was kleines. Die Zwischenablage des Betriebssystems kann in Silverlight 4 gelesen und geschrieben werden. Leider kann der Benutzer aber nur reine Texte kopieren.

Es gibt drei Methoden auf dem statischen Clipboard Objekt.

  • ContainsText
  • GetText
  • SetText

Name ist Programm.

Da der User den Zugriff auf die Zwischenablage (ähnlich der Webcam) explizit erlauben muss, gibt es eigentlich drei Fälle. Folgender Silverlight Code mit VB.NET zeigt die Szenarien.

Try
    If Clipboard.ContainsText() Then
       TextBox1.Text = Clipboard.GetText()
    Else
       MessageBox.Show("Zwischenablage leer")
    End If
Catch ex As SecurityException
    MessageBox.Show("Bitte Zugriff auf Zwischenablage erlauben")
End Try

Das funktioniert OOB ( out of browser) und auch für Browser Anwendungen.



Erstellt am: 09.09.2010 20:13:34 | Kommentare: | Erstellt von: Hannes Preishuber
Kategorien: Silverlight, VB, .Net,


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.



Erstellt am: 07.09.2010 21:55:34 | Kommentare: | Erstellt von: Hannes Preishuber
Kategorien: Silverlight, XAML, .Net,


Silverlight Transformationen Detailinfos


In meiner letzten Silverlight Schulung hat ein Teilnehmer ziemlich pentrant nachgefragt in welcher Reihenfolge Transformationen ausgeführt werden. Ich habe geantwortet gleichzeitig. Damit hatte ich recht und unrecht zugleich.

Seit Silverlight 4 erzeugt Expression Blend Transformationen per Attribute in einem CompositeTransform Element

<Button Content="Button" RenderTransformOrigin="0.5,0.5" UseLayoutRounding="False" d:LayoutRounding="Auto" Margin="5">
    <Button.RenderTransform>
    	<CompositeTransform TranslateY="-13" Rotation="19.549"/>
    </Button.RenderTransform>
</Button>

Wenn nun mehrere Buttons in einem Stackpanel platziert werden sieht man in Blend zwei Effekte

image

Die Ursprüngliche Position des Buttons wird hellblau dargestellt. Das liegt daran das das Reendering zunächst durchgeführt wird als ob das UIElement ganz normal vorhanden wäre. Hier eben drei Buttons in einem Stackpanel. Das macht auch sicher Sinn. Wohin sollten die Buttons auch rutschen? Danach wird die Transformation angewandt. In diesem Beispiel eine Drehung und eine Positionsänderung auf der Y Achse.

Vor Silverlight 4 hat Expression Blend (als 3 oder kleiner) eine Transformgroup erzeugt. Diese enthielt dann die Transformationen als Unterelemente. Eine Menge XAML Code und vor allem teuflisch da Animationen die Elemtente per Index angesteuert haben. Ein entferntes Transformation Element hat so ziemlich weit reichende Auswirkungen. Entsprechend ist der Lösungsansatz von Silverlight 4 per CompositeTransform auch wesentlich besser.

Seltsamerweise enthalten die Silverlight 4 Design Vorlagen auch noch immer den alten Weg per Transformgroup

<LinearGradientBrush EndPoint="0,1" MappingMode="Absolute" SpreadMethod="Repeat" StartPoint="20,1">
<LinearGradientBrush.Transform>
<TransformGroup>
<TranslateTransform X="0"/>
<SkewTransform AngleX="-30"/>
</TransformGroup>                                 

Nun zur zentralen Frage. Spielt die Reihenfolge der Element in der Transformgroup eine Rolle? Die Standardreihenfolge unter Blend war wie folgt. Dies habe ich auch nie in Frage gestellt und verändert.

<TransformGroup>
    <ScaleTransform/>
    <SkewTransform/>
    <RotateTransform/>
    <TranslateTransform/>
</TransformGroup>

 

image

 

Wenn man nun die Reihenfolge von TranslateTransform und RotateTransform wie folgt tauscht, ändert sich in der Tat die Oberfläche, was der Beweis dafür ist, das es eine entscheidende Rolle spielt.

<TransformGroup>
 <TranslateTransform X="200"/>
 <RotateTransform Angle="45"/>
</TransformGroup>
image


Erstellt am: 06.09.2010 21:21:06 | Kommentare: | Erstellt von: Hannes Preishuber
Kategorien: Silverlight, Blend,


Selektierten Eintrag in Silverlight Listbox anders darstellen


Die Silverlight Listbox wird noch ein Thema für ein eigenes Buch. Wer bei Bing nach Beträgen dazu sucht wird vieles dazu finden. U.a. hier und hier und hier. Ein Kunde meiner Silverlight Schulung hat mich gefragt wie man einen Eintrag einer Listbox der ausgewählt (selected) ist, anders darstellt. Nun habe ich mich geistig auf die Suche nach dem passenden Template gemacht. Das ist ist aber falsch gedacht. Silverlight verwendet für die “aktiven” Parts den Visual State Manager der das Verhalten beeinflusst.

Um an diesem VSM zu gelangen muss man in das generated Item Container Template der Silverlight Listbox.

image

Dann erhält man umfangreichen XMAL Code. Die wichtigen Stellen habe ich gelb markiert.

<UserControl.Resources>
<Style x:Key="ListBoxItemStyle1" TargetType="ListBoxItem">
<Setter Property="Padding" Value="3"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Top"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="TabNavigation" Value="Local"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid Background="{TemplateBinding Background}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver">
<Storyboard>
<DoubleAnimation Duration="0" To=".35" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="fillColor"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<DoubleAnimation Duration="0" To=".55" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="contentPresenter"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="SelectionStates">
<VisualState x:Name="Unselected"/>
<VisualState x:Name="Selected">
<Storyboard>
<DoubleAnimation Duration="0" To=".75" 
Storyboard.TargetProperty="Opacity"
Storyboard.TargetName="fillColor2"
/>
</Storyboard> </VisualState> </VisualStateGroup> <VisualStateGroup x:Name="FocusStates"> <VisualState x:Name="Focused"> <Storyboard> <ObjectAnimationUsingKeyFrames Duration="0"
Storyboard.TargetProperty="Visibility"
Storyboard.TargetName="FocusVisualElement"
> <DiscreteObjectKeyFrame KeyTime="0"> <DiscreteObjectKeyFrame.Value> <Visibility>Visible</Visibility> </DiscreteObjectKeyFrame.Value> </DiscreteObjectKeyFrame> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Unfocused"/> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Rectangle x:Name="fillColor" Fill="#FFBADDE9"
IsHitTestVisible="False" Opacity="0" RadiusY="1" RadiusX="1"/> <Rectangle x:Name="fillColor2" Fill="red"
IsHitTestVisible="False" Opacity="0" RadiusY="1" RadiusX="1"/> <ContentPresenter x:Name="contentPresenter" Margin="5" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalAlignment="Left" /> <Rectangle x:Name="FocusVisualElement"
RadiusY="1" RadiusX="1" Stroke="#FF6DBDD1"
StrokeThickness="5"
Visibility="Collapsed"/> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </UserControl.Resources>

Entsprechend sieht dann meine Liste nicht mehr besonders schön aber aus. Aber ich konnte das selektierte Item verändern und kann sogar die Animation dazu steuern. Und wieder ein Auftrag erfüllt.

image



Erstellt am: 27.08.2010 20:04:24 | Kommentare: | Erstellt von: Hannes Preishuber
Kategorien: Blend, Silverlight,


Visual Studio 2010 und Expression Blend Datenbindung mit Designer untersützung


Wenn man in Silverlight Projekten Datenklassen erstellt und dann bindet entsteht der Wunsch im Designer schon einen sinnvollen Preview zu haben. Für Expression Blend gibt es die Möglichkeit mit Designtime zu arbeiten. In diesem Silverlight Beispiel will ich aber direkt die DAL pimpen. Dafür muss einfach der Konstrukor herhalten, der für die verschiedenen Fälle unterschiedliche Daten generiert.

Public Class person
    Implements INotifyPropertyChanged
    public Sub New()
    If DesignerProperties.IsInDesignTool Then
        _name = "Hannes Preishuber ist ein Designer"
     Else
      If HtmlPage.IsEnabled Then
                _name = "Hannes Preishuber nuttzt den Webbrowser"
      Else
        _name = "Hannes Preishuber startet die Anwendung OOB"
      End If
  End If
End Sub

Die  Bindung wird voll deklarativ durchgeführt.

<UserControl.Resources>
  <local:person x:Key="personDataSource" d:IsDataSource="True"/>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White" 
DataContext="{Binding Source={StaticResource personDataSource}}"> <TextBox Height="23" Margin="151,23,12,0"
TextWrapping="Wrap" Text="{Binding name, Mode=TwoWay}">

In Visual Studio 2010 (cidder)
image

Im Webbrowser
image
Out Of Browser (OOB)

image



Erstellt am: 27.08.2010 19:22:39 | Kommentare: | Erstellt von: Hannes Preishuber
Kategorien: Blend, Silverlight,


Listbox einträge die die ganze Breite einnehmen


Diesesmal hat mein Silverlight Schulungsteilnehmer (Stephan) mir eine cooles Silverlight Sample gezeigt. Während der Schulung war wieder mal die Listbox ein Thema (darüber könnte ich schon ein Buch schreiben. Es sollte eine Liste mit Namen angezeigt werden und dabei das Itemtemplate verändert werden. Das geht eigentlich ganz einfach entweder mit Expression Blend oder direkt im XAML Code ala

<ListBox.ItemTemplate>
     <DataTemplate>
	<Border Margin="5" BorderBrush="#FF340CF9" CornerRadius="5"  Height="32">
	<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="Black" Offset="0"/>
<GradientStop Color="White" Offset="1"/>
</LinearGradientBrush>
 		</Border.Background>
	<TextBlock Text="{Binding}" Foreground="#FFF9F5F5" FontWeight="Bold" Margin="4,2"/>
      	</Border>
    </DataTemplate>
</ListBox.ItemTemplate>

image

Das ganze sieht allerdings mehr nach Balkengrafik aus. Der Wunsch ist das alle Listboxitems gleich breit sein sollen. Eigentlich ganz einfach. Die Width der Broder gesetzt und… Aber es soll genau so breit sein wie die Listbox.

Das geht indem man das HorizontalContentAlignment auf Stretch setzt. Da kommt man leider gar nicht so leicht ran. Entweder man nimmt Expression Blend und zerlegt die Listbox in sein Template. Contextmenü – Edit Template-Edit a copy.- und erhält 300 Zeilen XAML Code

image

Oder man nimmt die relevante Setter Stelle einfach raus und setzt sie sozusagen auf dem kurzen Dienstweg im ItemContainerstyle der Silverlight Listbox

<ListBox Margin="96,26,129,54" x:Name="listbox1"  >
  <ListBox.ItemContainerStyle>
     <Style TargetType="ListBoxItem" >
        <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
     </Style>
  </ListBox.ItemContainerStyle>

 

Perfektes Ergebnis im Browser

image



Erstellt am: 27.08.2010 19:05:01 | Kommentare: | Erstellt von: Hannes Preishuber
Kategorien: Silverlight, Blend,


Einen Silverlight Clipping Path Animieren


Aktuell habe ich in meiner Silverlight Schulung einen Teilnehmer, der wirklich interessante Fragen aufwirft, deren Antwort ich dann im Nachgang suche und hier in meinem Blog poste. Schließlich sind nur glückliche Silverlight Kurs Teilnehmer auch gute Teilnehmer. In diesem Silverlight 4 Beispiel soll ein Bild beschnitten werden. Das geht auch ganz einfach mit dem Clipping Path Attribut.

Mit Expression Blend nimmt man ein Bild, legt darüber eine Kurve (z.B. Kreis) und markiert beide. Dann wird im Context Menü Path- Make Clipping Path ausgewählt.

image

Im XAML sieht das wie folgt  aus und man sieht nur mehr den Hintern der hübschen Person vom Foto Zwinkerndes Smiley.

<Image Margin="30,41,-140,-124" Source="/maus[1].jpg" Stretch="Fill" 
Clip="M470.5,351.5 C470.5,387.3985 425.05692,416.5 369,416.5 C312.94308,416.5
267.5,387.3985 267.5,351.5 C267.5,315.6015 312.94308,286.5 369,286.5
C425.05692,286.5 470.5,315.6015 470.5,351.5 z"
/>

Leider lässt sich das so nicht mehr animieren. Viele Attribute eines UIElements lassen sich durch ein Unterelement aufsplitten. So auch das Clip Attribut zu Image.Clip. Der Pfad wird dann mit Geometry Elementen beschrieben. In unserem Beispiel eben eine Ellipse.

<Image x:Name="image" Source="/maus[1].jpg" Stretch="Fill" RenderTransformOrigin="0.5,0.5" >
  <Image.Clip>
    <EllipseGeometry RadiusX="50" RadiusY="50" Center="100,100">
    </EllipseGeometry> 		
  </Image.Clip>
</Image>
Insgesamt gibt es fünf solcher Geomtrien.
  • EllipseGeometry
  • GeometryGroup
  • LineGeometry
  • PathGeometry
  • RectangleGeometry

Jetzt bleibt nur mehr das Problem der Animation. Leider gibt es keine Unterstützung durch Expression Blend oder schon gar nicht Visual Studio 2010. Also ran per Hand. Da ich eine Punkt verschieben möchte ist die PointAnimation das passende. Recht Tricky ist die Adressierung des Center Propertys über die XAML Hierarchie.

<Storyboard x:Name="Storyboard1">
<PointAnimation BeginTime="0" Duration="0:0:01" From="0,0" To="200,200"
 Storyboard.TargetName="image" 
 Storyboard.TargetProperty="(UIElement.Clip).(EllipseGeometry.Center)">
</PointAnimation></Storyboard>

Gestartet wird die Animation per Expression Blend behavior. Am Ende eine Null Code Lösung.

<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<ei:ControlStoryboardAction Storyboard="{StaticResource Storyboard1}"/>
</i:EventTrigger>
</i:Interaction.Triggers>

Funktioniert. Ich bin wieder mal begeistert.

 

imageimageimage



Erstellt am: 26.08.2010 20:30:24 | Kommentare: | Erstellt von: Hannes Preishuber
Kategorien: Silverlight, .Net, Blend,


BusyIndicator in ObservableCollection einbinden


In meiner aktuellen Silverlight Schulung haben wir ein wenig auf Performance geschaut. Ein Ladevorgang einer sehr langen Liste dauert etwas länger und während dieser Zeit soll der eine Wartemeldung angezeigt werden. Im Silverlight Toolkit befindet sich auch passend ein entsprechendes Control der BusyIndicator.

BusyIndicator-Default

Dieser lässt sich auch in sein Template zerlegen und optisch anpassen. Während der Busyindicator läuft kann der User keine UI Elemente nutzen und so z.B. einen Button eben nicht zwei mal drücken.

Die entscheidende Frage ist, wie zeige ich den BusyIndicator nun an. Zunächst hat dieser eine Boolsche Eigenschaft IsBusys die man setzen kann. Manchmal läuft die Logik aber in einer Komponente dahinter von der man keinen Zugriff aufs UI hat.  In meinem Fall eben eine Liste die von ObservableCollection erbt. Diese Liste wird zur Laufzeit durch einen länger laufenden Download gefüllt, zur Design Zeit mit Dummy Daten.  Diese Entscheidung wird duchr HTMLPagel.Isenabled getroffen. Die Observeable Collection muss ich nehmen damit das gebundene UI Element ( z.B. Datagrid oder Listbox) automatisch und asynchron die Daten auch anzeigen sobald sie fertig geladen sind. Zusätzlich verpasse ich der personen Liste ein Property isBusy. Dieses wird gesetzt wenn der Download startet. In der OpenreadCompleted Methode wird dann der Wert wieder auf false gesetzt.

Public Class personen
    Inherits ObservableCollection(Of person)
    Public Sub New()
        If HtmlPage.IsEnabled Then
            Dim wc As New WebClient
            AddHandler wc.OpenReadCompleted, AddressOf fertig
            IsBusy = True
            wc.OpenReadAsync(New Uri("namen.txt", UriKind.Relative))
        Else
            Add(New person With {.alter = 27, .Firma = "ppedv ag", .Name = "Hannes"})
            Add(New person With {.alter = 32, .Firma = "ppedv ag", .Name = "Andreas"})
            Add(New person With {.alter = 23, .Firma = "ppedv ag", .Name = "Bernhard"})
            Add(New person With {.alter = 45, .Firma = "ppedv ag", .Name = "Stefan"})
            Add(New person With {.alter = 12, .Firma = "ppedv ag", .Name = "Arnold"})
        End If
    End Sub

    Private _IsBusy As Boolean
    Public Property IsBusy() As Boolean
        Get
            Return _IsBusy
        End Get
        Set(ByVal value As Boolean)
            _IsBusy = value
            OnPropertyChanged(New PropertyChangedEventArgs("IsBusy"))
        End Set
    End Property

Im XAML wird dann der BusyIndicator an die IsBusy Eigenschaft gebunden. Dies ist auch der Grund für die onpropertyChanged Codezeile im vorigen Beispiel. Damit kann das UI Änderung der Daten im Personen Object “abbonieren”. Damit wird die Anzeige eben sofort erneuert.

<toolkit:BusyIndicator Height="100" HorizontalAlignment="Left"  Name="BusyIndicator1" 
   IsBusy="{Binding IsBusy}" 
   VerticalAlignment="Top" Width="150" >
</toolkit:BusyIndicator>
   


Erstellt am: 11.08.2010 08:04:52 | Kommentare: | Erstellt von: Hannes Preishuber
Kategorien: Silverlight, XAML, .Net,


Liste 2x1 Itemscontrol


Letztes mal habe ich kurz beschrieben was man mit einer Listbox und Templating in Silverlight so machen kann. Wenn man allerdings keine Auswahl Möglichkeit braucht, kann man auch das schlankere Itemscontrol (übrigens erbt Listbox davon) verwendet werden.

Die Daten werden als Liste in einer Klasse erzeugt.

Public Class personen
    Inherits List(Of person)
    Public Sub New()
        Add(New person With {.alter = 27, .Firma = "ppedv ag", .Name = "Hannes"})
        Add(New person With {.alter = 32, .Firma = "ppedv ag", .Name = "Andreas"})
        Add(New person With {.alter = 23, .Firma = "ppedv ag", .Name = "Bernhard"})
        Add(New person With {.alter = 45, .Firma = "ppedv ag", .Name = "Stefan"})
        Add(New person With {.alter = 12, .Firma = "ppedv ag", .Name = "Arnold"})
    End Sub
End Class

Diese Daten werden deklarativ instanziert und gebunden. Nicht weil es nötig wäre, sondern schlicht weil es möglich ist. Das folgende passiert dann auch in der XAML Datei

...   xmlns:local="clr-namespace:KoelnSL">
<UserControl.Resources>
    <local:personen x:Key="personen"></local:personen>
</UserControl.Resources>

Ein positver Nebeneffekt ist, das die Bindung auch in Blend und Visual Studio 2010 zur Entwurfszeit voll sichtbar ist.

image

Im XAML werden dann die drei Templates definiert

 

<ItemsControl Width="100" 
ItemsSource="{Binding Source={StaticResource personen}}"> <ItemsControl.Template> <ControlTemplate TargetType="ItemsControl"> <Border BorderBrush="BlueViolet" BorderThickness="1" CornerRadius="10"> <ItemsPresenter/> </Border> </ControlTemplate> </ItemsControl.Template> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <StackPanel Orientation="Vertical" Background="SkyBlue" Margin="5"/> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding Name}" Height="20" Width="50" Margin="4">
</TextBlock> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl>


Erstellt am: 09.08.2010 21:38:52 | Kommentare: | Erstellt von: Hannes Preishuber
Kategorien: Silverlight,


IIS-Pickup-Verzeichnis kann nicht abgerufen werden bei SMTPClient.Send


Oder wie der Brite auch sagen würde “Cannot get IIS pickup directory”. Beim senden von EMails aus ASP.NET per SMTP Service kann ich immer nur raten, nicht die Network Methode zu wählen, sondern direkt ins Pickup Directory des IIS zu schreiben. Das geht schneller und ist ausfallsicher falls der SMTP Server mal nicht erreichbar ist. Ein typischer Anwendungsfall von asynchroner Architektur. Nun ist der SMTP Server beim IIS 7 (und 7.5) noch immer der alte aus dem IIS 6. Wenn man also WIndows Server 2008 oder 2008 R2 hat muss man den SMTP Server extra verwalten mit der alten MMC Console. Das heist die Metabase ist nach wie vor im Spiel und nicht die neuen Config Dateien. Übrigens war Microsoft auf so nett den POP3 Server rauszunehmen. Worauf mein Kollege Cosmin den kostenfreien VIsendo SMTP Extender programmiert hat.

Beim IIS7 7.5 wird per default der Benutzer ApplicationPoolIdentity verwendet um die Web Anwendung zu betreiben. Dieser Benutzer hat stark limiterte Rechte.

image

Ebenso fehlt wohl das Zugriffsrecht (ACL) auf die Einträge aus dem SMTP Bereich in der Metabase.

Wenn nun beim versenden einer Mail die Meldung kommt “IIS-Pickup-Verzeichnis kann nicht abgerufen werden” dann helfen folgende Lösungsansätze

1) In der Web.config den Namen des  Pickupdirectorys manuell setzen

http://blogs.ppedv.de/hannesp/archive/Mail-Sender-Klartextnamen-in-web.config-setzen

2) Man kann dem Beutzer auch die Rechte geben. Dazu sollte man den Metabase Editor verwenden. Dieser ist im IIS6 Resource Kit enthalten. Per Rechtsclick auf den Knoten im Tree (hier 1) kann man dann die benötigten Rechte setzen.

image

3) Den Benutzer in den Einstellungen des Application Pools ( Abbildung 1) auf System ändern. Mit entsprechenden Konsequenzen in der Sicherheit.


Erstellt am: 27.07.2010 14:24:10 | Kommentare: | Erstellt von: Hannes Preishuber
Kategorien: ASP.NET, Windows Server 2008,


Freigestellte Personen in Silverlight Video


Auf jedem guten TV Sender gibt es eine Wetter Fee. Diese meist sehr attraktive Person  choreographiert vor einer blauen oder heute meist grünen Wand. Die Clouds oder Sonnen werden Computer animiert eingespielt.

Dazu brauchen wir eine Wetterfee, eine Kamera, ein Aufnahmestudio, Expression Blend 4 und .. die Möglichkeit in einem  Video eine Farbe auf transparent zu schalten. Die Wetterfee ist meine entzückende Kollegin Lilly. Die Kamera eine Smartflip ( jetzt Cisco). Das Aufnahmestudio eines Fotografen der im gleichen Haus sitzt und eine grüne Rollwand besitzt. Diese rollt man ein Stück über den Boden so das auch keine Kanten sichtbar sind. Dann das ganze nach Expression Blend importiert und per Drag& Drop auf eine Seite ziehen.

image

Warum Lilly hier so seltsame Handbewegungen macht? Ich wollte später eine per Silverlight Animation eine Sonne durchs Bild schieben. Was man hier gut sehen kann ist, das der Hintergrund nicht homogen ist. Das ist mir bei unserem 30 Sekunden Shot nicht aufgefallen. Es liegt daran das Fotografen in der Regel einen Spot auf den Hintergrund legen um das Foto aufzulockern. Hier müsste der Spot abgeschalten werden. Dazu aber gleich mehr.

Seit Silverlight 3 gibt es Pixelshader. Diese helfen Bilder direkt in der Grafikkarte performant zu verändern( Wenn GPU Acceleration aktiviert ist). Per Standard ist Schatten und Unschärfe vorhanden. In Blend 4 noch ein wenig mehr Shader. Wir brauchen aber einen Pixelshader der aus Grün Transparent macht.

Dies nennt man fachspezfisch den ChromaKey fürs Alpha Blending. Entsprechend auch der Name ChromaKeyAlphaEffect. Der Download für die installierbare MSI findet sich hier

http://code.msdn.microsoft.com/SL3ChromaKeyEffect/Release/ProjectReleases.aspx?ReleaseId=3900

Leider ist der aktuelle Build 1.3 vom 9.Februar.2010 noch SL 3. Entsprechend ist Blend 4 und Visual Studio 2010 ein wenig mit der Aufgabe überfordert und man benötigt etwas Handarbeit. Zunächst setzt man eine Referenz im Silverlight Projekt auf Synergist.Effects.dll. Dann kann man in Expression Blend im Reiter Assets den Chroma Key Alpha Effect auf das Video ziehen.

image
Im Property Dialog sollte dann entweder direkt in den Eigenschaften des ChromaAlphaEffect (siehe Bild) oder in den Eigenschaften des Videos im Effect Reiter die Farbe ausgewählt werden können.

image

Am besten geht das mit dem Color Picker des üblichen Farbdialoges. Leider tritt hier der erste Bug zu Tage. Das zusätzliche Property Tolerance wird nicht angeboten. Damit kann man den Grünbereich etwas aufweiten. Mögliche Werte sind 0-1. Ganz gut trifft oft rund um 0,2.

Aktuell sieht dann Lilly so aus.

image

Wenn man im XAML Source dann Tolerance setzt,

<MediaElement   x:Name="lilly1_wmv" Source="lilly1.wmv" 
Stretch="Fill" AutoPlay="True"
MediaEnded="lilly1_wmv_MediaEnded" > <MediaElement.Effect> <Synergist_Effects:ChromaKeyAlphaEffect Tolerance="0.2" ColorKey="#FF9DE094"/> </MediaElement.Effect> </MediaElement

siehts in Blend so aus.

image

In Visual Studio 2010 ist es im Ergebnis das gleiche. Allerdings lauffähig ist das ganze schon. Also ab  in den Browser und staunen.

image

Noch nicht perfekt und ich habe deswegen auf die Animation verzichtet aber ich glaube wir machen noch einen zweiten Dreh mit besseren Hintergrund.



Erstellt am: 22.07.2010 21:51:30 | Kommentare: | Erstellt von: Hannes Preishuber
Kategorien: Silverlight, Blend,


Silverlight WCF Services 1x1


In den nächsten Blog Einträgen werde ich meine Gedanken zum Thema Services mit Silverlight zu ordnen beginnen. Es gibt einfach zu viele Wege um Daten mit der Client Server Technologie Silverlight hin und her zu schicken. Leider sind die recht einfachen ASMX Web Services obsolet und in  WCF aufgegangen. Der größte Unterschied ist das man WCF (Windows Communication Foundation) Dienste nicht mal so spaßeshalber im Browser aufrufen kann. Ergänzend der Hinweis auf das Blog meines Kollegen Bernhard, der ein wahres WCF Genie ist.

Zunächst einmal die Vorarbeit mit einer Datenklasse.

Imports System.Runtime.Serialization

<DataContract()>
Public Class person

    Private _FamName As String
    <DataMember()>
    Public Property FamName() As String
        Get
            Return _FamName
        End Get
        Set(ByVal value As String)
            _FamName = value
        End Set
    End Property

    Private _GebDat As Date
    <DataMember()>
    Public Property GebDat() As Date
        Get
            Return _GebDat
        End Get
        Set(ByVal value As Date)
            _GebDat = value
        End Set
    End Property

    Private _bild As String
    <DataMember()>
    Public Property bild() As String
        Get
            Return _bild
        End Get
        Set(ByVal value As String)
            _bild = value
        End Set
    End Property
End Class

Wenn DataMember nicht dekoriert wird, gibt es später beim aufrufen des Services einen deserialisierungsfehler in der Form InnerException: System.Runtime.Serialization.SerializationException. Das sind eben WCF Basics. Dann erstelle ich eine Business Objekt das mir eine Liste von Personen zurück gibt.

Public Class BO1
    Public Function getPersonen() As List(Of person)
        Dim lofP As New List(Of person)
        lofP.Add(New person With {.bild = "bild1.jpg", .FamName = "Maier", .GebDat = New Date(("01.13.1978"))})
        lofP.Add(New person With {.bild = "bild2.jpg", .FamName = "Huber", .GebDat = New Date("01.13.1978")})
        lofP.Add(New person With {.bild = "bild3.jpg", .FamName = "Müller", .GebDat = New Date("01.13.1978")})
        lofP.Add(New person With {.bild = "bild4.jpg", .FamName = "Gates", .GebDat = New Date("01.13.1978")})
        lofP.Add(New person With {.bild = "bild5.jpg", .FamName = "Heuer", .GebDat = New Date("01.13.1978")})
        lofP.Add(New person With {.bild = "bild6.jpg", .FamName = "Holesch", .GebDat = New Date("01.13.1978")})
        lofP.Add(New person With {.bild = "bild7.jpg", .FamName = "dela Rosa", .GebDat = New Date("01.13.1978")})
        lofP.Add(New person With {.bild = "bild8.jpg", .FamName = "Jobs", .GebDat = New Date("01.13.1978")})
        lofP.Add(New person With {.bild = "bild9.jpg", .FamName = "Hayat", .GebDat = New Date("01.13.1978")})
        lofP.Add(New person With {.bild = "bild10.jpg", .FamName = "Hatahet", .GebDat = New Date("01.13.1978")})
        lofP.Add(New person With {.bild = "bild11.jpg", .FamName = "Thyret", .GebDat = New Date("01.13.1978")})
        Return lofP

    End Function
End Class

Ein WCF Service wird im Silverlight Projekt per Template Silverlight-Enabled-WCF-Service erstellt. Dieser Service ruft dann die Funktion auf, die die Personenliste erstellt. Per Dafult findet sich da immer die DoWork Prozedur.

    <OperationContract()>
    Public Function GetAllPersons() As List(Of person)
        Dim bo As New BO1
        Return bo.getPersonen()
    End Function

Der Service ist im Browser aufrufbar. Mit dem Parameter WSDL erscheint auch die Beschreibung der Funktion und Objekte. Diese wird von Werkzeugen verwendet um Proxy Klassen erzeugen zu können. Das sollten Sie für einen ersten Test auf alle Fälle tun.

image

 

Dann wechseln wir in das Silverlight Projekt und erstellen eine Service Referenz im Projekt Baum per Context Menü Add Service.

image

In der Silverlight Anwendung wird dann eine Instanz der Proxy Klasse erzeugt, eine Rücksprung Methode definiert und der Service aufgerufen. Vergessen Sie nicht, das Silverlight nur Asynchron arbeitet und deswegen nicht auf eine Rückgabe wartet.  Die eigentliche Liste von Personen wird dann per e.Result in der Rücksprung Methode ausgelesen und einem Datagrid zugewiesen. Hier passiert eine wenig VB casting magic. Sie sollten wissen das  der Visual Studio Proxy Wizard immer aus Listen einen Typ ObservableCollection erzeugt. ich habe bereits hierzu ein paar Worte verloren, das das auch anders geht.

Private Sub WCF1_Loaded(ByVal sender As Object, 
ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded Dim svc As New ServiceReference1.Service1Client AddHandler svc.GetAllPersonsCompleted, AddressOf fertig svc.GetAllPersonsAsync() End Sub Private Sub fertig(ByVal sender As Object,
ByVal e As ServiceReference1.GetAllPersonsCompletedEventArgs) SVC1.ServiceReference1.person) DataGrid1.ItemsSource = e.Result End Sub


Erstellt am: 11.07.2010 10:23:58 | Kommentare: | Erstellt von: Hannes Preishuber
Kategorien: Silverlight, WCF,


RIA Services binary, Json, Odata und SOAP Endpunkte


Mit Hilfe des Silverlight RIA Services Toolkit lassen sich zusätzliche Optionen der RIA Services nutzen.

  • LinqToSql DomainService
  • SOAP Endpoint
  • JSON Endpoint 
  • ASP.NET DomainDataSource Control

    In diesem Blog Eintrag betrachte ich einmal die Möglichkeiten der serialisierung. Insgesamt kann man stand heute folgenden Formate wählen.

  • Binary
  • OData
  • SOAP
  • JSON

    Allerdings muss in der Web.Config manuell die Konfiguration erweitert werden.

     <domainServices>
          <endpoints>
            <add name="OData"
                 type="System.ServiceModel.DomainServices.Hosting.ODataEndpointFactory, 
    System.ServiceModel.DomainServices.Hosting.OData, Version=4.0.0.0, Culture=neutral,
    PublicKeyToken=31bf3856ad364e35"
    /> <add name="JSON" type="Microsoft.ServiceModel.DomainServices.Hosting.JsonEndpointFactory,
    Microsoft.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral,
    PublicKeyToken=31bf3856ad364e35"
    /> <add name="Soap" type="Microsoft.ServiceModel.DomainServices.Hosting.SoapXmlEndpointFactory,
    Microsoft.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral,
    PublicKeyToken=31bf3856ad364e35"
    /> </endpoints> </domainServices>

    Der Aufruf für eine JSon Rückgabe erfolgt in der Form

    http://localhost:[port]/ClientBin/[Projektname]-Web-[DomainServiceklasse].svc/Json/[Methode]

    Da die SVC Dateien nicht wirklich existieren sondern per IIS Modul Mapping behandelt werden kann der Pfad statt Clientbin auch z.B. Service lauten.

    Wenn man den Traffic mit Fiddler mitschneidet kann man sehr gut erkennen wie das Json Format aufgebaut ist.

    image

    Die Aufrufe der einzelnen Methoden und die Rückgabe Datenmenge in KB im Vergleich

    ..KoelnSL-Web-DomainServiceMD.svc/binary/GetOrdersDetails

    607K

    ..KoelnSL-Web-DomainServiceMD.svc/Json/GetOrdersDetails

    563K

    ..KoelnSL-Web-DomainServiceMD.svc/OData/GetOrdersDetails

    1109K

    ..KoelnSL-Web-DomainServiceMD.svc/Soap/GetOrdersDetails

    erzeugt 400er Error

    Soap Abrufe sind leider im Browser nicht direkt möglich. Deshalb auch die Fehlermeldung. Um den Service bzw die Methode testweise aufzurufen könnten man das Hilfstool WCFtestClient.exe verwenden. Leider unterstützt dieses keine Domainservices. Also bleibt nur der Weg über das Silverlight Projekt.

    image

  • Leider kompiliert meine Lösung anschliessend nicht mehr. Selbst auf Nachfrage bei Microsoft konnte man adhoc das Problem nicht lösen. Die einzige Antwort das es aktuellere Bits der RIA Services und Silverlight (GDR) gibt hilft nicht, da ich dafür alles neu installieren muss und dann mit RC Bits arbeite die nirgendwo laufen. Entsprechend werde ich die Lösung für SOAP in einem späteren Blog nachliefern.



    Erstellt am: 08.07.2010 07:27:10 | Kommentare: | Erstellt von: Hannes Preishuber
    Kategorien: Silverlight,


    Master Detail mit WCF RIA Services in 10 Sekunden


    Die Headline stimmt nur bedingt, aber schliesslich muss ich meinen Artikel ja verkaufen Winking smile. Am Ende ist es aber auch nicht ganz falsch. Wenn ein Silverlight Projekt mit RIA Services besteht, ist Master Detail tatsächlich nur 1 Codezeile und 2 clicks entfernt.

    Zunächst einmal nehme ich die gute alte Nordwind Datenbank und die Tabellen Orders und OrderDetails als Ausgangspunkt und erstelle im Web Projekt mit Entity Framework ein Modell.

    image

    Weiter geht es mit einer neuen Domain Service Klasse. Wie immer vorher kompilieren nicht vergessen und die Metadaten erzeugen lassen.

    image

    In der DomainService Klasse erzeuge ich per copy paste eine weitere Queryklasse. Per Standard findet sich nur die GetOrders. Da ich ja noch die Details mit liefern möchte nenne ich die Funktion GetOrdersDetails. Wichtig ist per LINQ Query und dem Kommando Include die Kind Tabelle Order_Details einzubinden. Mit dem Attribut <Query> stelle ich sicher das später im Data Designer die Query auch auftaucht.

     <Query()> _
        Public Function GetOrdersDetails() As IQueryable(Of Orders)
            Return Me.ObjectContext.Orders.Include("Order_Details")
        End Function

    Dann muss in den Metadaten (xxx.metadata.vb) noch der Schlüssel Property markiert werden. Dazu wird <Include()> vor den bereits vorhandenen Propertynamen vorgestellt.

        <Include()>
            Public Property Order_Details As EntityCollection(Of Order_Details)
    Seit VB 2010 braucht man dafür übrigens keinen Unterstrich mehr *like`*. Dann wieder kompilieren.
    In Visual Studio ins Silverligth Projekt wechseln und eine XAML Datei auswählen. Dann ist der Menüpunkt Data vorhanden. Dort einfach die Darstellungsform Datagrid einstellen und die Orders und die Order Details auf die Page ziehen.
     

    image

    Das fertige Ergebnis nach 9,67 Sekunden im Browser

    image



    Erstellt am: 04.07.2010 23:07:28 | Kommentare: | Erstellt von: Hannes Preishuber
    Kategorien: Silverlight,


    klare Regeln fürs tägliche Leben- Die Österreichische Ampel App mit Silverlight


    Ich habe mir einen Wunschtraum erfüllt. Eine österreische Ampel als mini App. Da Windows Phone noch kein Silverlight unterstützt, vorerst nur als Desktop Anwendung

    Was macht nun eine österreichische Ampel so einmalig. Sie blinkt 3 mal Grün bevor sie auf gelb schaltet! Diese Ampel kann uns nun den Arbeitsalltag versüssen, gibt uns klare Richtlinien vor. Sinnlosses Starren auf den  Fortschrittsbalken ist nun endgültig vorbei. Jetzt kommt sinnloses Starren auf die Ampel. Ich bitte um Überweisung von 3,99 € pro Download. Reklamation und Rückgabe ausgeschlossen.

    Zunächst einmal das technsiche Konzept. Ich implementiere die Ampel als Usercontrol und nutze den Visual Statemanager um die Statusinformation Rot, Gelb und Grün mit Animationen hinterlegen zu können.

    Startpunkt ist das UI Design mit Blend. Es beginnt relativ harmlos mit einer Border, Farbverlauf und wie immer runden Ecken.

     

    image

    Dann widme ich mich der ersten Lampe. Ein Kreis mit etwas dickerem Rand (Strockethickness 10) und zwei gegenläufige Farbverläufe im Graubereich erzeugen einen 3D Eindruck.

    image

    Da rein kommt dann nochmal ein kleinerer Kreis, der ein wenig Abstand zum äusseren Rahmen hat auf den ersten Kreis. So das man den Hintergrund am Rand noch ein wenig sehen kann. Dieser Kreis wird rot gefärbt und bekommt einen im Zentrum leicht versetzten runden Farbverlauf. Das GradientBrushtool ( dicker Pfeil) aus der linken Toolleiste hilft dabei ungemein.

    image

    Um die die Wölbung perfekt zu machen, wird Lichteinfall von oben simuliert. Dazu wird ein weiße, sehr transparente Elypse, darüber gelegt. Das gleiche machen Comic Zeichner z.B. mit den großen Heidi Augen um diese wässrig aussehen zu lassen. Ich verwende hier 30% alpha blending und versüse das mit einem Effekt um ein unscharfe Kontur zu haben.

    image

    Dann werden die Ui Element in ein Canvas gepackt, kopiert und umgefärbt.

    image

    Weiter gehts mit dem Visual State Manager. Dort erzeuge ich eine Gruppe mit dem Namen Phasen und darin die drei States: rot, gelb und gruen. Dann kann jeder in jedem State und Übergang  das UI animiert werden. Im wesentlichen werden die beiden anderen Kreise einfach schwarz gefärbt mit einem Delay von 0,2 Sekunden. Schliesslich leuchtet so eine antike Glühbirne ja nach. LED Ampeln gibts in Österreich noch nicht. Für die Phase Grün auf Gelb habe ich einen speziellen Übergang definiert. Diese Animation läuft drei Sekunden und wechselt dabei von abwechselnd drei mal von Grün nach Schwarz den SolidcolorBrush im Fill Attribut.

    image

    Als nächstes wird das Usercontrol in eine weitere XAML Seite eingepackt. Dort gehts dann nur mehr mit puren Code zur Sache. Ein Timer wirft die Statusänderungen an. Da die Ampelphasen ja unterschiedlich lang sind, brauch ich ein wenig Logik um die Timer Zeiten zu ändern.  Da die Grün Blink Phase 3 Sekunden dauert muss die Gelb Phase 5 Sekunden sein um in Summe 2 Sekunden Gelb zu sehen. Ich denke der Code spricht auch ohne refactoring für sich selbst

    Dim dp As New DispatcherTimer
    Dim status As Integer = 0
    private Sub page35_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
       dp.Interval = New TimeSpan(0, 0, 10)
       AddHandler dp.Tick, AddressOf ticking
       VisualStateManager.GoToState(Ampel1, "rot", True)
       status = 1
       dp.Start()
    End Sub
    Private Sub ticking(ByVal sender As Object, ByVal e As EventArgs)
       Select Case status
        Case 0
          VisualStateManager.GoToState(Ampel1, "rot", True)
          dp.Interval = New TimeSpan(0, 0, 10)
          status = 1
        Case 1
          VisualStateManager.GoToState(Ampel1, "gelb", True)
          dp.Interval = New TimeSpan(0, 0, 2)
          status = 2
        Case 2
          VisualStateManager.GoToState(Ampel1, "gruen", True)
          dp.Interval = New TimeSpan(0, 0, 10)
          status = 3
        Case 3
          VisualStateManager.GoToState(Ampel1, "gelb", True)
          dp.Interval = New TimeSpan(0, 0, 5)
          status = 0
       End Select
    End Sub

    Jetzt habe ich nur mehr das Problem, wie komme ich an Ihr Geld. Bzw wie können Sie ganz einfach die Anwendung starten?

    Dazu rufen Sie einfach folgende Website auf. Per rechtsclick können Sie diese auch lokal installieren.



    Erstellt am: 01.07.2010 07:31:17 | Kommentare: | Erstellt von: Hannes Preishuber
    Kategorien: Silverlight, Blend,


    Silverlight kann nun auch rechts click


    In meiner aktuellen Silverlight Schulung wurde heute das Thema Mouse Events besprochen. Seit Silverlight 4 gibt es ja bekannterweise auch Events zur rechten Maustaste.  Also sollte theoretisch auch eine Textbox per Rechstclick ein Context Menü anzeigen können. Die Idee des Schulungs Teilnehmers sah ungefähr so aus.

    <TextBox Height="111"  MouseRightButtonUp="textBox1_MouseRightButtonUp"  Name="textBox1" Width="180" />

    Allerdings funktioniert das nicht, weil die Textbox das Event als behandelt markiert und damit nicht mehr weiter reicht. Um ein Context Menü zu erstellen gibt es aber seit Silverligth 4 im seperat erhältlichen Toolkit eine passende Lösung. Mit dem ContectMenuService wird ala Tooltip die Textbox um zusätzliche Funktion erweitert.

    image

    Das Context Menü funktioniert genauso wie in WPF. Es besteht aus Menuitems. Pro Menüpunkt ein Item. Dieses wiederum aus einem Header, der üblicherweise den Menütext darstellt. Optisch aufgepeppt wird über ein Unterelement MenuItem.Icon per Image Element. Das Attribut Icon im MenuItem Element kann dafür nicht genutzt werden. Für den Trennstrich gibt es das Seperator Element.

    <TextBox Height="30"  HorizontalAlignment="Left" Margin="161,36,0,0" 
    Name="textBox1" VerticalAlignment="Top" Width="180" > <toolkit:ContextMenuService.ContextMenu> <toolkit:ContextMenu> <toolkit:MenuItem Header="Hyperlink" Click="MenuItem1_Click"> <toolkit:MenuItem.Icon> <Image Source="Images/link.png"></Image> </toolkit:MenuItem.Icon> </toolkit:MenuItem> <toolkit:Separator /> <toolkit:MenuItem Header="drucken" Click="MenuItem2_Click"> <toolkit:MenuItem.Icon> <Image Source="Images/print.png"></Image> </toolkit:MenuItem.Icon> </toolkit:MenuItem> <toolkit:MenuItem Header="speichern" Click="MenuItem3_Click" IsEnabled="True"> <toolkit:MenuItem.Icon> <Image Source="Images/save.png"></Image> </toolkit:MenuItem.Icon> </toolkit:MenuItem> </toolkit:ContextMenu> </toolkit:ContextMenuService.ContextMenu> </TextBox>


    In diesem Beispiel werden einzelne Events pro Menüpunkt deklariert. Denkbar ist auch per Commands zu arbeiten. Dann wird das Attribut Command bzw CommandParameter verwendet.



    Erstellt am: 29.06.2010 22:33:24 | Kommentare: | Erstellt von: Hannes Preishuber
    Kategorien: Silverlight,


    Silverlight Textbox mit Wasserzeichen


    Eben sind die neuen Programme aus der Live Serie erschienen. Ich schreibe dies auch auf dem neuen Windows Live Writer Beta. Den gibts aktuell leider nur in Englisch und so muss ich auf die deutsche Rechtschreibprüfung verzichten. Man verzeihe mir schon jetzt.

    Was seit Beginn der Zune Zeiten auffällt, ist die Reduktion auf weniger. Also vor allem kurzer Text statt bunter Icons. Apple geht hier aktuell einen anderen Weg. Microsoft hat das ganze sogar in seinem Metro UI Style Guide beschrieben. Dort steht auch, das man Oberflächen bewusst leer halten soll. Eine alte Designer Regel.  Ausserdem soll man alle Elemente dem Benutzer zugänglich machen. Als Beispiel dafür  möchte ich die klassische Windows XResult Fehlermeldung nennen, deren Text man nicht in die Zwischenablage kopieren kann, da es als Label implementiert ist. Um das klar zu sagen, ich stehe zu beiden Aussagen. Das macht Sinn und ist die Zukunft.

    Ich habe mir nun einen einfachen Silverlight Login Dialog vorgenommen um dieses Design Pattern umzusetzen. Textblock ist eigentlich obsolet und gehört verboten. Entsprechend kommt die Beschriftung in die Textbox und verschwindet, wenn der Benutzer etwas eingetippt hat. Davon ausgehend, das der Benutzer auch nachträglich erkennen kann was der Inhalt bedeutet. Wenn die Textbox wieder geleert wird, erscheint die Watermark in wieder in Grau.

    imageimage

    Realisiert habe ich das ganz einfach. Zunächst wird der Watermark Text der Textbox im Tag und Text Element abgelegt und der Foreground Grau gesetzt. Das Ziel ist es die Watermark wieder herstellen zu können. Dann brauche ich nur mehr die Events GotFocus und LostFocus um minimale Funktion zu implementieren.

    <TextBox Height="26" Name="txtUser" Width="63" Margin="10"
            MaxLength="3" Foreground="gray" 
            GotFocus="txt_GotFocus"  LostFocus="txt_LostFocus"
            Text="User" Tag="User">
    </TextBox>
    <TextBox Height="26" Name="txtPassword" Width="84"  Foreground="gray"
            GotFocus="txt_GotFocus"  LostFocus="txt_LostFocus" 
            Text="Passwort" Tag="Password">
    </TextBox>

    Die Methoden sind universell ausgelegt und erkennen das Sender Control.

    Private Sub txt_LostFocus(ByVal sender As System.Object, 
    ByVal e As System.Windows.RoutedEventArgs) Dim tb As TextBox = CType(sender, TextBox) If (tb.Text = String.Empty) Then tb.Text = tb.Tag tb.Foreground = New SolidColorBrush(Colors.Gray) End If End Sub Private Sub txt_GotFocus(ByVal sender As System.Object,
    ByVal e As System.Windows.RoutedEventArgs) Dim tb As TextBox = CType(sender, TextBox) If tb.Text = tb.Tag Then tb.Text = "" tb.Foreground = New SolidColorBrush(Colors.Black) End If End Sub

    Sieht doch schick aus, oder?



    Erstellt am: 25.06.2010 08:13:16 | Kommentare: | Erstellt von: Hannes Preishuber
    Kategorien: Silverlight, Design, XAML,


    das IPad - mein Test


    Das Gerät

    So da ist nun das neue IPad direkt aus dem Apple Store, drei Wochen nach Bestellung. Schick, etwas schwer, traumhaftes Display. Mir, als altem Bastler fällt natürlich sofort auf - keine Schrauben. Das heißt, wenn was kaputt, kann ich es nicht reparieren. Na gut- ich fahr auch Audi und nicht Käfer. Aber am Ende fehlt doch jede Erweiterungsmöglichkeit, die man allein durch externe Ports wie  USB bekommen würde. Viele Notebooks haben auch interne Möglichkeiten  für Speicher oder UMTS. Geht nicht. Der Aufpreis für UMTS liegt beim dreifachen, als man für ein internes Modul im freien Handel zahlen muss. Sehr positiv ist die Einschaltzeit und die  Akku Laufzeit. Der Preis entspricht den modernen Gesetzen der Preisbildung. Presse jeden Euro aus deinem Kunden.

    Das Geschäftsmodell

    Für mich ist es wichtig zu wissen, womit eine Firma Ihr Geld verdient, um Entwicklungen für die Zukunft abschätzen zu können. Eine Firma die Software verschenkt, muss am Service verdienen. Entsprechend ist “einfach” kein Feature das ich da erwarten werden. Apple verdient an den  Geräten und an der dauerhaften Nutzung, den sogenannten Long Tail. An Apps, Books und Musik. Entsprechend ist es für Apple gut, wenn ich öfter mal eine neues Gerät kaufe und den schlappen Akku nicht selber durch Drittanbieter tausche. Außerdem ist es gut, wenn ich das Gerät häufig nutze und dabei den ein oder anderen Cent an Apple spende.

    die Inbetriebnahme

    Ich habe geflucht. Es  geht nichts ohne Internet und Itunes. Also keine iPads für Eskimos. Man muss sein Gerät sozusagen freischalten. Das geht nur mit den persönlichen Daten. Der  Download beträgt ca 90 MB und ich frage mich warum die Software nicht auf dem Gerät ist. Auch liegt keine DVD oder Bedienungsanleitung bei. Ich denke entgegenen jeder Verbraucherschutzverordnung. In meinem Fall hatte ich Probleme mit dem Wlan. Der Apple Support ist… die Empfehlung auf der Website lautet. Bei  Wlan Problemen soll man den Access Point anders zu konfigurieren.

    Das Betriebsystem

    Nackt- nicht immer intuitiv. Manchmal nervig. Im Sinne von alles raus, nur was wirklich funktioniert bleibt drin. Ich musste feststellen das HEX Wlan Keys bei Apple Case sensitve sind (was ich für falsch halte). Jedenfalls gabs dafür keine passende Fehlermeldung und ich musste den  Wlan Key 10 mal eintippen. War jedes mal weg, keine Zwischenablage und es ist unlustig zwischen Buchstaben und Zahlen dauernd auf der Screen Tastatur hin und her zu schalten.  Es funktioniert im übrigen aber auch erstaunlich gut, auf eine echte Tastatur zu verzichten.

    Mein Sohn stellte als erstes die Frage, wo sind die Spiele? Es gibt keine Spiele auch nichts zum zeichnen.  Elementares fehlt wie z.B. drucken, Sicherheit, Backup.

    Flash? Hat mir bisher noch nicht gefehlt. Trotzdem habe ich Videos geschaut, was ehrlich ein tolle Sache ist, auch wenn ich nicht einen Spielfilm lang ein Brett in der Hand halten möchte.

    Die Bedienung per Multitouch ist angenehm und intuitiv. Für meinen Sohn aber ohne Erklärung nicht nutzbar. Ein Safari Browser ist dabei, der es aber nicht erlaubt, die Suche auf Bing umzustellen. Generell sind die IPad OS UI’s wenig spektakulär. Teilweise auch schlecht. So gibts Eingabe Formulare bei denen man scrollen muss um auf den entscheidenden Button drücken zu können.

    die Anwendungen

    Das ist der eigentliche Knüller. Es gibt wirklich unzählige (man sagt 150.000) nützliche Helferlein im Appstore. Allerdings erst nach Eingabe der Kreditkarte und Bestätigung der 67 Seiten AGB’s. Mit dem Ziel in Zukunft mit 2 Clicks und der Eingabe des AppStore Passwortes ganz schnell 4,99 ärmer zu sein. Test oder Rückgabe Möglichkeiten habe ich keine gesehen. Die Preise der Apps reichen von gratis bis über 20 Euro.

    Die Suche im Appstore ist rudimentär. Da könnte man von Google oder Bing einiges lernen. Das System ist closed. Geschlossener gehts kaum. Apple kann Dir sogar gekauften Content wieder von deiner kleinen Maschine rauben.

     

    Die Apps Entwickler

    Die Eigentliche Kreativität und Nutzen entsteht in den Köpfen von Millionen von Anwendern. Wer Geld für einen Mac hat und 100 Euro pro Jahr zahlt kann damit auch Programme für IPhone und Ipad schreiben. Zwar weit entfernt vom Komfort und Möglichkeiten von Visual Studio, aber auch nicht ganz kompliziert. Dabei kommt entgegen, das ohne jede Altlast,in kurzen Zyklen, entwickelt wird. Und Apple macht den Reibach damit. Einfaches oneclick, ala Amazon, System senkt die Hemmschwelle für den Käufer. Die alten IPhone Apps kann man hochzoomen, machen aber oft Problem bei Tastatur Eingaben.

    Ein Teil des Erfolges beruht auf dem Marketing für die APPs . Speziell die Medienkonzerne sehen ihr Heil darin, doch noch an payed  Content zu kommen über das closed App Konzept. So schaltet die Welt seit Wochen ganzseitige Anzeigen für die Welt APP, die natürlich nur auf dem IPad läuft. Kostenlose Werbung und große Reichweite.

    Ein anderer Teil des Erfolges sind die teils echt witzigen APP Ideen von Tausenden von Entwickler, die so hoffen doch noch Millionär zu werden. Ein Momentum das nur Kapitalismus in Reinkultur an den Tag bringen kann. Somit darf eigentlich kein Linker ein IPad besitzen.

     

    Die Liebe steigt

    Nachdem ich mich ein wenig in das System eingefunden habe, finde ich vieles wirklich gut. Ich habe Nutzen und manches macht echt Spaß. Ob ich privat zu den aktuell 3 Millionen iPad Benutzern gehören möchte, bezweifle ich allerdings. Man muss mal klar sagen, das von den 500 bis ca 800 Euro, die man fürs nackte Geräte zahlen muss, viele andere nützliche Dinge gekauft werden können. Eine Waschmaschine  oder ein Plasma TV. Vor allem da die voraussichtliche Nutzdauer im Bereich von ein bis zwei Jahren liegen wird und erhebliche Folgekosten zu erwarten sind. Mich stört wirklich das Monopol. Ich habe keine Möglichkeit ohne Totalverlust jemals das Apple Ecosystem wieder zu verlassen. Ich denke das mit fortschreitender Marktdurchdringung auch die Regierungen und Behörden drauf drängen werden das System zu öffnen. Das ist der Segen und Fluch von Apple. Noch sind sie nicht groß genug, wenn sie es aber sind ist ihr Geschäftsmodell hinfällig. Generell wird Apple mit diesem Vorgehen im Business Umfeld keinen Fuss in die Tür bekommen.



    Erstellt am: 23.06.2010 08:21:25 | Kommentare: | Erstellt von: Hannes Preishuber
    Kategorien: Konferenzen,


    Silverlight Themes


    Sind Sie ein Designer? Nein, aber möchten trotzdem schöne Oberflächen? Dann könnten die Silverlight Themes etwas für Sie sein. Es gibt aktuell drei Neue mit dem Namen Accent Color, Windows 7 und Cosmopolitan. Ursächlich sind diese für die sogenannte Silverlight Navigation oder Silverlight Business Application gedacht. Allerdings können die Styles auch anderwärtig verwendet werden. Dazu später mehr.

    Der Download für die Version 1.1 umfasst Style für die Silverlight Core, Silverlight SDK und Silverlight ToolkitControls.

    Es gibt drei einzelne Dateien

    •README_FIRST.txt –
    •SL4Themes-templates.zip –darin enthalten ein Ordner für Expression Blend und Visual Studio Templates.  Ebenso ist ein Unterordner für  RIA Services Templates.
    •SL4Themes-rawassets.zip – in dieser Datei stecken sozusagen die nackten Styles ohne Visual Studio Template. In der beigefügten Readme Datei ist beschrieben wie man ein SIlverlight Projekt mit manuell mit diesen Style versieht. Dies ist eigentlich recht einfach und für VB Entwickler der einzige Weg die Styles zu verwenden.

    SL4Themes-Templates

    Um die Themes für  Visual Studio 2010 zu installieren einfach die  *.vsix files im VS2010 Ordner starten. Um die Themes für Expression  Blend 4 muss man manuell die Dateien kopieren. Der Zielordner für Blend4 findet sich in  %ProgramFiles%\Microsoft Expression\Blend 4\ProjectTemplates\en\CSharp\Silverlight.

    image

    Beim starten von Blend stehen dann die Templates zur Verfügung.

    image

    In Visual Studio sieht das dann so aus

    image

    Für beide Fälle gilt das dies nur in C# Projekten zur Verfügung steht. Mir klingt noch in den Ohren “VB.net is a first class citicen”. Für VB.NETler geht dann eben nur der Weg über SL4Themes-rawassets.

    Eine Silverlight Navigation Application mit dem Cosmopolitian Theme sieht ein wenig aus wie im Metro UI Style Guide definiert. Zune Anwendungen und zukünftige Windows phone Anwendungen folgen diesem recht nüchternen Text orientieren Design.

    image

    Im Silverlight Projekt ist dies über den Assets Ordner zugeordnet. Dort finden sich in XAML Dateien die Styles. Die kann man natürlich nach eigenen Geschmack auch anpassen.

    image

    Die Zuweisung der Styles findet in der app.xaml statt.

     <Application.Resources>
            <ResourceDictionary>
                <ResourceDictionary.MergedDictionaries>
                    <ResourceDictionary Source="Assets/Styles.xaml"/>
                    <ResourceDictionary Source="Assets/CoreStyles.xaml"/>
                    <ResourceDictionary Source="Assets/SDKStyles.xaml"/>
                    <!--<ResourceDictionary Source="Assets/ToolkitStyles.xaml"/>
                    To extend this theme to include the toolkit controls:
                    1. Install the Silverlight Toolkit for Silverlight 4
                    2. Add a Toolkit control to your project from the toolbox. 
    This will add references to toolkit assemblies. 3. Change the "Build Action" for ToolkitStyles.xaml to "Page" 4. Uncomment the resource dictionary include above. If you do not intend to use toolkit controls,
    delete this comment and the ToolkitStyles.xaml file.-->
    </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources>

    Tim Heuer schreibt auch noch ein wenig in seinem Blog darüber. Komplette Beispielanwendungen als Design Muster

    http://www.silverlight.net/content/samples/sl4/themes/cosmopolitan.html

    http://www.silverlight.net/content/samples/sl4/themes/windows7.html

    http://www.silverlight.net/content/samples/sl4/themes/accent.html



    Erstellt am: 20.06.2010 19:03:47 | Kommentare: | Erstellt von: Hannes Preishuber
    Kategorien: Silverlight, Blend,


    Eingabe Validierung in WCF RIA Services


    Wenn man beim erstellen eines Domainservices die Metadaten dazu erstellt, kann man sehr einfach per die Eigenschaften des Geschäftsobjekte deklarativ im Code mit Informationen versehen, die später zur Laufzeit ausgewertet werden. Also per <Attribut> Syntax.

     image

    Dadurch erhält man dann im Web Projekt Klassen in der Konvention DomainService1.metadata.vb. Im Code dieser Klasse kann dann per Annotation  die Logik jeder Eigenschaft gesteuert werden. Folgendes lässt in einem Dataform das Feld Telefon erscheinen und es wird Fett dargestellt, da es ein muss Feld ist. Darüber erscheint es ziemlich weit oben.

    <Required()>
    <Display(Name:="Telefon", Order:=2)>
    Public Property Phone As String
     image        
    Was passiert nun wen Benutzer keine Telefonnummer angibt und das Feld leer lässt?
     

    image

    Natürlich kann man auch den Fehlertext noch ändern. Dazu einfach im Required ErrorMessage:= setzen. Diese Prüfung der Benutzereingabe findet Adhoc, also nach verlassen des Eingabefeldes statt. Ohne Interaktion zum Server.

    Für komplexere Validierungen stellt Silverlight ein Benutzerdefinierte Prüfung sowohl am Client als auch am  Server bereit. Dazu wird das entsprechende Property in der IRA DomainKlasse per Attribut Customvalidatiion dekoriert. Der erste Parameter stellt den Klassennamen dar und der zweite die Methode.

    <CustomValidation(GetType(regeln), "hannesValid")>

    Der Prüfcode muss eine gewissen Regelwerk folgen, sonst wird er schlicht nicht ausgeführt. Zunächst muss die Prüfroutine shared (c# static) sein. Die Rückgabe muss vom Typ Validationresult sein.

    Imports System.ComponentModel.DataAnnotations
    Public Class regeln
        Public Shared Function hannesValid(ByVal region As String) As ValidationResult
            If region.Length > 2 Then
                Return New ValidationResult("nur 2 Zeichen")
            End If
            Return ValidationResult.Success
        End Function
    End Class

    Das wird nun eine reine Prüfung am Server bewirken. Also erst wenn der Datensatz nach einer Änderung zurück geschrieben wird. Mit Hilfe von Shared Code kann diese Prüfung aber auch am Client sofort durchgeführt werden. Zeitpunkt ist wenn die Datenbindung aktualisiert wird, also bei LostFocus.

    Die Prüfungsklasse muss nun in der Web Anwendung in einer eigenen Datei erstellt werden die der Namens Konvention shared.vb oder shared.cs folgt.

    image

    Der Code wird dann automatisch von Visual Studio 2010 auch in die Silverlight Anwendung “repliziert”.

    image

    In meinem Beispiel validiert laut debugger zwar die Silverlight Anwendung aber der Benutzer sieht keine Fehlermeldung. Das muss man erst über einen optionalen Parameter im ValidationResult ansteuern. Dabei wird der Feldname als Parameter angegeben, hier eben Region.

    Public Shared Function hannesValid(ByVal region As String) As ValidationResult
            If region.Length > 2 Then
                Return New ValidationResult("nur 2 Zeichen", New String() {"Region"})

    Denkbar ist auch, da als Array vorhanden, mehrere Felder anzugeben in der Form New String() {"Region", "Phone"})

    image

    Sinnvoller ist meines Erachtens einen universellen Silverlight Fehlerchecker zu haben. Dazu wird der Context des auslösenden Controls mitgebeben.

    Public Class regeln
        Public Shared Function hannesValid(ByVal region As String, ByVal ctx As ValidationContext) As ValidationResult
            If region.Length > 2 Then
                Return New ValidationResult("nur 2 Zeichen", New String() {ctx.MemberName})

    Das alles und viel mehr lernt man in meine Silverlight Schulungen bei ppedv.



    Erstellt am: 19.06.2010 11:09:18 | Kommentare: | Erstellt von: Hannes Preishuber
    Kategorien: Silverlight, .Net, XAML,


    WCF Services in Silverlight einbinden


    Wieder einmal eine Frage aus meinem Silverlight Kurs. Der Teilnehmer will zwei WFC Services in ein Projekt einbinden. Dazu verwendet er das Werkzeug slsvcutil um die Proxy Klassen zu erzeugen. Ich würde das einfach per Visual Studio und durch hinzufügen einer Service Reference lösen.

    Im Silverlight Projekt Service Referenz hinzufügen.

    image

    Man erhält dann eine Menge Dateien. Der erzeugte Code enthält dann auch die Propertys:

     <System.Runtime.Serialization.DataMemberAttribute()>  _
            Public Property Region() As String
                Get
                    Return Me.RegionField
                End Get
                Set
                    If (Object.ReferenceEquals(Me.RegionField, value) <> true) Then
                        Me.RegionField = value
                        Me.RaisePropertyChanged("Region")
                    End If
                End Set
            End Property

    Zunächst also einmal der erste Versuch einen Proxy zu generieren. Das Tool befindet sich bei mir in C:\Program Files\Microsoft SDKs\Silverlight\v4.0\Tools. Der Aufruf für mich als VBler

    slsvcutil http://localhost:1892/Service2.svc?wsdl /language:VB

    Un dann schon die ernüchternde Fehlermeldung.

    Process is terminated due to StackOverflowException

    Liegt daran das ich kein US System habe. Workaround durch anlegen der config Datei beschrieben hier.

    http://blogs.msdn.com/b/silverlightws/archive/2010/04/30/workaround-for-stackoverflowexception-when-using-slsvcutil-exe.aspx

    Die Proxy Klasse weist aber leichte Unterschiede auf. So werden Arrays statt ObservableCollection erzeugt. Keine InotifyPropertychanged Interfaces Implementiert und es gibt keine automatischen Namensraum Anpassungen. Das kann durchaus erwünscht sein, da so die WCF Kommunikation etwas leicht gewichtiger wird. Der Code für ein Property sieht dann so aus im Vergleich zu vorher.

     <System.Runtime.Serialization.DataMemberAttribute()>  _
            Public Property Region() As String
                Get
                    Return Me.RegionField
                End Get
                Set
                    Me.RegionField = value
                End Set
            End Property

     

    Die erzeugte Klassendatei wird einfach dem Silverlight Projekt hinzugefügt.

    Wenn man das ursprüngliche Verhalten möchte dann führt folgende Syntax zum Erfolg.

    slsvcutil http://localhost:1892/Service2.svc?wsdl /edb
    /namespace:"*,SilverlightApplication1.ServiceReference1"
    /ct:System.Collections.ObjectModel.ObservableCollection`1
    /r:"%PROGRAMFILES%\Reference Assemblies\Microsoft\Framework\Silverlight\v3.0\System.Windows.dll"
    /language:VB

    Grundsätzlich sehe ich keine Grund, die Kommandozeilen Variante zu wählen.



    Erstellt am: 17.06.2010 21:35:26 | Kommentare: | Erstellt von: Hannes Preishuber
    Kategorien: Silverlight, WCF,


    Compact Docu zu Silverlight RIA Services DomainDatasource Control


    Mit den Silverlight Ria Services kommt auch wieder eine Drag&Drop Experience auf uns Entwickler zu. Egal was man davon halten will, einen Blick ist es allemal Wert. Ich setze voraus das der geneigte Leser Ahnung von den WCF RIA Services hat. Einstiegspunkt ist die fertige Domainservice Klasse mit dem Namen DomainService1.

    In Visual Studio 2010 ist dann per Menüpunkt Data, ein neuer Arbeitsbereich zu öffnen. In Datasources müssten sich dann die vorher z.B. per Entity Framework modellierten Datenobjekte befinden.

    clip_image001

    Per Drag und Drop kann man nun die ganze Tabelle auf das Silverlight Usercontrol gezogen werden. Dabei stehen die Optionen Datagrid oder Details zur Verfügung. Bei Detail werden alle Felder mit einem Label und Textbox Control dargestellt. Im Punkt Customize lässt sich auch jedes beliebige andere Silverlight Control festlegen. Auch einzeln können die Felder aufs Formular gezogen werden.

    clip_image002

    Im weiteren Beispiel habe ich ein Datagrid per Drag und Drop aus der Datasource erstellt. Der unaufregende Teil ist das Datagrid selbst.

    <sdk:DataGrid AutoGenerateColumns="False" Height="200"
    HorizontalAlignment="Left"
    ItemsSource="{Binding ElementName=CustomersDomainDataSource, Path=Data}"
    Margin="12,12,0,0" Name="CustomersDataGrid"
    RowDetailsVisibilityMode="VisibleWhenSelected" VerticalAlignment="Top" Width="400">

    <sdk:DataGrid.Columns>

    <sdk:DataGridTextColumn x:Name="AddressColumn"
    Binding="{Binding Path=Address}" Header="Address" Width="SizeToHeader" /> .....

    </sdk:DataGrid>

    Obwohl auch da schon ein wenig drinsteckt. So wird die Itemssource per Binding zugewiesen. Dazu gleich mehr. Die einzelnen Spalten werden ebenfalls per Binding Syntax gebunden. Aber an was eigentlich? An ein anderes Control, wie man im per ElementName definierten Element to Element Binding erkennen kann. Diese Control befindet sich im Ria Toolkit und wird in diesem Fall automatisch per Namensraum bekannt gemacht.

    xmlns:riaControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.DomainServices"

    Im Control DomainDataSource wird die Datenquelle definiert. Diese ist in diesem Fall als über einen Namensraum my auf die Klasse (hier eben Domainservice1 genannt) instanziert. 

    <riaControls:DomainDataSource AutoLoad="True" d:DesignData="{d:DesignInstance my:Customers, CreateList=true}"
    Height="0" Name="CustomersDomainDataSource" QueryName="GetCustomersQuery" Width="0">

    <riaControls:DomainDataSource.DomainContext>

    <my:DomainService1 />

    </riaControls:DomainDataSource.DomainContext>

    </riaControls:DomainDataSource>

    Zusätzlich wird per Queryname die Methode bestimmt die aufgerufen werden soll. Diese finden sich im eigentlichen Service und wird im Attribut mit dem Zusatz Query versehen. Für den aufmerksamen Leser noch kurz ein Hinweis: DesignData ist optional und hilft zur Entwurfszeit in Expression Blend und Visual Studio einen Preview auf die Daten zu bekommen.

    Wenn die Abfrage Methode Parameter erwartet, werden die mit dem Element Queryparamters bestimmt.

    <riaControls:DomainDataSource.QueryParameters>

    <riaControls:Parameter ParameterName="CustomerID" Value="ALFKI"
    /></riaControls:DomainDataSource.QueryParameters>

    Das Attribut Value kann auch Werte von anderen Controls per Element Binding erhalten. Also z.B. eine TextBox als Eingabemöglichkeit für einen Filterwert. Generell kann man mit einem Filterdescriptor flexibel filtern. Der Filterwert wird in meinem Beispiel aus einer Textbox per Element Binding eingesteuert. Der Operator entspricht einer LINQ ähnlichen Syntax.

    <riaControls:DomainDataSource.FilterDescriptors>

    <riaControls:FilterDescriptor Operator="StartsWith"

    PropertyPath="CompanyName"

    Value="{Binding ElementName=TextBox1, Path=Text}"

    </riaControls:FilterDescriptor>

    </riaControls:DomainDataSource.FilterDescriptors>

    Wenn mehrere Filterdescriptor angegeben sind, werden die logisch per AND verknüpft. Wie bei Element Binding üblich wirkt die Abfrage sofort bei Änderung des Wertes in der Textbox. Sehr spannend ist wenn man per httpfiddler auf den Traffic schaut.

    GET /ClientBin/KoelnSL-Web-DomainService1.svc/binary/GetCustomers?$where=
    (it.CompanyName.ToLower().StartsWith(%2522%2522)%253d%253dTrue)

    Man sieht eine typische Rest Query. Die Daten selbst Binär codiert um die Datenmenge zu reduzieren. Die RIA Services übertragen also auch wirklich nur die Daten die von Client benötigt werden.

    Im Browser sieht das dann so aus.

    clip_image003

    Die Query lässt sich aus noch ausbauen um z.B. eine Sortierung einzubauen.

    <riaControls:DomainDataSource.SortDescriptors>

    <riaControls:SortDescriptor PropertyPath="CompanyName" Direction="Ascending" />

    </riaControls:DomainDataSource.SortDescriptors>

    Im Datagrid wird die sortierung auch angezeigt.

    clip_image004

    Total abgefahren finde ich die Möglichkeit auch zu gruppieren. Das ist eine generelle Eigenschaft des Datagrid’s um auch z.B. Master Detail Szenarien zu lösen. In Zusammenarbeit mit der DomainDatasource geht das ganz einfach. Dazu gibt es das Element Groupdescriptor mit dem die Gruppierung festgelegt wird.

    <riaControls:DomainDataSource.GroupDescriptors>

    <riaControls:GroupDescriptor PropertyPath="Region" />
    </riaControls:DomainDataSource.GroupDescriptors>

    Das sieht dann so aus. Eine Region (hier leer mit 60 items) habe ich zugeklappt

    clip_image005

    Bei großen Datenmengen ist es natürlich besser nur wenige Datensätze zu holen. Dies ist der Benutzer gewohnt und kennt es als Paging. Das passende Control heist natürlich Datapager und befindet sich im Silverlight SDK. Ein Wermutstropfen ist, das zuerst im Dataservice eine sortierung in den Code eingebaut werden muss. Ansonsten kommt es zu seltsamen Fehlermeldungen zur Laufzeit.(The method skip is only supported for sorted input in Linq to entitys). In VB.NET sieht die Kurzform per Lambda Ausdruck.

    Public Function GetCustomers() As IQueryable(Of Customers)
             Return Me.ObjectContext.Customers.OrderBy(Function(t) t.CompanyName)
    End Function
    C# ungefähr so

    public IQueryable<User> GetCustomers()

    {

    return this.ObjectContext.Customers.OrderBy(b => b.CompanyName);

    }

    Also wie gesagt, das in dem Web Projekt passieren.

    So nun aber auf zum Pager im XAML Code dort wird angegeben wie groß der Bereich sein soll.

    <sdk:DataPager PageSize="5"
    Source="{Binding ElementName=CustomersDomainDataSource, Path=Data}"/>

    Allerdings kann bzw soll man auch im DomainDatasource Control einstellungen vorgenommen werden. Interesannt ist das man mit Loadsize quasi schon ein paar Seiten vorladen, also buffern kann.

    <riaControls:DomainDataSource PageSize="5" LoadSize="10"...

    Die Browser Ansicht 

    clip_image006

    Wichtig zu wissen: Das Paging wird per REST Querys durchgeführt. Es fließen also nur die benötigten Daten über die Leitung.

    Der Benutzer kann Daten auch ganz einfach editieren. Allerdings ist es dann mit dem Paging vorbei (hier plötzlich grau im Bild) und die Daten wandern auch nicht von ganz alleine über den Domainservice in die Datenbank.

    clip_image007

    Dafür braucht man doch einen Softwareentwickler, der eine Zeile Code schreibt und submitChanges aufruft. Wo man das tut, ist eine Entscheidung des Anwendungsfalles. In meinem Beispiel wird die Methode RowEditEnded des Datagrids verwendet.

    Private Sub CustomersDataGrid_RowEditEnded(ByVal sender As Object, ByVal e As System.Windows.Controls.DataGridRowEditEndedEventArgs)

    CustomersDomainDataSource.SubmitChanges()

    End Sub

    Was soll man sagen? Es funktioniert und ist ziemlich einfach. Allerdings ist es sozusagen die Version 1. Man wird sehen.



    Erstellt am: 15.06.2010 20:11:18 | Kommentare: | Erstellt von: Hannes Preishuber
    Kategorien: Silverlight, WCF, XAML,


    Twitter Search API mit Silverlight befragen


    Im Zuge der Österreichischen Sharepoint Konferenz, die wir von ppedv im Auftrag von Microsoft veranstaltet haben, habe ich eine Twitterwall geschrieben. Twitter besitzt drei API’s wovon die Search API die einfachste ist. Im folgenden Beispiel suchen wir alle Tweets mit dem Hashtag Silverlight.

    http://search.twitter.com/search?q=%23silverlight

    Um die Daten im Atom Format zu bekommen muss die Syntax leicht verändert werden mit dem ATOM Zusatz

    http://search.twitter.com/search.atom?q=%23silverlight

    Atom ist ein XML Format und entsprechend schwergewichtig. Wesentlich schlanker ist Json. Mit folgender Query erhält man diese Daten als JSon.

    http://search.twitter.com/search.json?q=%23silverlight

    Dabei reduziert sich der Traffic auf ein Drittel. Auch das Parsen müsste deutlich schneller sein. Aktuell habe  ich aber keine Performance Messungen vorgenommen.

    Nun laden wir diese Daten in einer Silverlight Anwendung mit einem WebClient.

    Private Sub Button1_Click(ByVal sender As System.Object, 
    ByVal e As System.Windows.RoutedEventArgs) Handles Button1.Click Dim wc As New WebClient AddHandler wc.DownloadStringCompleted, AddressOf fertig wc.DownloadStringAsync(New
    Uri("http://search.twitter.com/search.json?q=%23silverlight&lang=all&rpp=5", UriKind.Absolute)) End Sub

    In der asynchronen Methode Fertig werden dann die Daten bearbeitet. Da gibt es in Silverlight (und nur dort) eine nettes Assembly System.Json. Per JSonObject wird die Zeichenkette geladen und dann alle “Results” Elemente/Objekte in ein JsconArray gepackt. Per Linq könnte man dann noch filtern, was in diesem Beispiel nach der From Anweisung per Where codiert würde. Dann werden die Items dem Datagrid zugewiesen.

    Private Sub fertig(ByVal sender As Object, ByVal e As DownloadStringCompletedEventArgs)
            Dim js As JsonArray
            Dim jo As JsonObject
            jo = JsonObject.Parse(e.Result)
            js = jo("results")
            Dim items = From x In js
                          Select x
            DataGrid1.ItemsSource = items
     End Sub

    Um die deklarative Bindung durchzuführen muss man noch ein wenig in die Objekte reinsehen. Items ist ein Dictionary von JsonObject. Ein JsonObject wiederum ist eine unsortierte Collection von Key Value Paaren. Durch Twitter Json stehen da elf Werte drin über die der Debugger Auskunft gibt.

    image

    Neben ID ist das wichtigste der eigentliche Text. Entsprechend die Bindung in XAML per IndexBinding an den Key “text”.

    <sdk:DataGrid AutoGenerateColumns="False" Height="217" 
    HorizontalAlignment="Left" Margin="12,37,0,0" Name="DataGrid1"
    VerticalAlignment="Top" Width="379" > <sdk:DataGrid.Columns> <sdk:DataGridTextColumn Binding="{Binding Path=[text]}">
    </sdk:DataGridTextColumn> </sdk:DataGrid.Columns> </sdk:DataGrid>

     

     

     



    Erstellt am: 13.06.2010 19:03:22 | Kommentare: | Erstellt von: Hannes Preishuber
    Kategorien: Silverlight,


    Websites für alle Silverlight Fälle vorbereiten


    Aktuell habe ich das ppedv Logo auf der ppedv Startseite durch eine Silverlight Anwendung ersetzt um zu Marketing für unsere kommen Twittertage zu machen. Von Donnerstag bis Sonntag gibts per #ppedv Twittertag Hammeraktionen. Natürlich soll die Website für alle Kunden nach wie vor das Logo präsentieren.

    Silverlight 4 ist installiert.

    Da die Anwendung per Silverlight 4 entwickelt wurde ist das der einfachste Fall. Einfach den Object Tag in den HTHL Code einfügen. Da die Silverlight Anwendung über den HTML Inhalt liegen soll muss der Hintergrund in XAML transparent sein. Im Object Element braucht man zwei Attribute windowless und background.

    <object style="float: left;" data="data:application/x-silverlight-2," 
    type="application/x-silverlight-2" 
    width="400" height="100">
      <param name="source" value="/ClientBin/ppedvlogo.xap"/>
      <param name="windowless" value="true"/>
      <param name="background" value="transparent" />
      <param name="minRuntimeVersion" value="4.0.50401.0" />
    </object>

    Silverlight ist nicht installiert

    Um zu testen was passiert wenn Silverlight nicht installiert ist, kann man einfach aus dem Wert x-Silverlight-2 einen anderen z.B. x-silverlight-3 machen. Da Silverlight von Version 2-4 immer mit den gleichen Eintrag referenziert wird, wird so auf ein unbekanntes Plugin verwiesen. Was ident mit keinem installierten Silverlight ist. Dann kann man ein alternatives HTML Template innerhalb des Object Elements definieren. In meinem Fall das ppedv Logo als png. Um zu verhindern das ein Dialog hochkommt der den Benutzer zum installieren von Silverlight auffordert, habe ich autoupgrade auf false gesetzt. Ist ja schliesslich nicht unser Job Silverlight auszurollen.

    <object style="float: left;" data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="400" height="100">
     <param name="source" value="/ClientBin/ppedvlogo.xap"/>
     <param name="windowless" value="true"/>
     <param name="background" value="transparent" />
     <param name="minRuntimeVersion" value="4.0.50401.0" />
     <param name="autoUpgrade" value="false" />
     <img  src="http://www.ppedv.de/Images/ppedv_sternelogo.png" border="0" />
    </object>

    Silverlight ist in der falschen Version installiert

    image

    Der kompliziertere Fall ist wenn Silverlight vorhanden ist aber z.B. das Plugin Version 2 hat und die XAP Anwendung mit Silverlight 3 oder 4 geschrieben ist. Das kann man ganz nett simulieren indem man in das Attribute minRuntimeVersion einen Wert 5.0 reinschreibt. Silverlight 5 gibt es schlicht noch nicht. Dann kommt in einer Standard Anwendung ein JScript Exception. Auch dies unpassend für die ppedv Webseite.

    In diesem Fall habe ich den Object Tag in ein DIV gepackt und tausche dann schlicht per Jscript den Inhalt durch ein HTML Image Element aus. Silverlight kann per Attribut onError festlegen welche Jscript Methode im Fehlerfall aufgerufen werden soll.

    <div id="silverlightControlHost">
    <object style="float: left;" data="data:application/x-silverlight-2,"
     type="application/x-silverlight-2" width="400" height="100">
     <param name="source" value="/ClientBin/ppedvlogo.xap"/>
     <param name="windowless" value="true"/>
     <param name="background" value="transparent" />
     <param name="minRuntimeVersion" value="4.0.50401.0" />
     <param name="autoUpgrade" value="false" />
     <param name="onError" value="onSilverlightError" />
     <img  src="http://www.ppedv.de/Images/ppedv_sternelogo.png" border="0"/>
    </object>
    </div>

    Dann noch ein kurzes Stück JavaScript das den Fehler Code 8001 behandelt.

    <script type="text/javascript">
    function onSilverlightError(sender, args) {
         var iErrorCode = args.ErrorCode;
         if (iErrorCode==8001)
             {
            document.getElementById("silverlightControlHost").innerHTML = 
    '<img style="float: left;" src="http://www.ppedv.de/Images/ppedv_sternelogo.png" border="0" />'; } } </script>


    Erstellt am: 02.06.2010 19:39:16 | Kommentare: | Erstellt von: Hannes Preishuber
    Kategorien: Silverlight,


    Expression Blend 4 und Storyboards


    Mein Kollege Bernhard meint zwar das er Storyboards lieber in XAML Code tippt aber ich verlasse mich da besser auf das passende Werkzeug: Expression Blend. Dies ist ja nun in Version 4 verfügbar. Dieses mal möchte ich kurz zeigen wie man Storyboards steuern kann ganz ohne Code. Ich gehe mal davon aus das die grundlegende Kenntnisse vorhanden sind. Falls nicht einfach Mail an hannesp AT ppedv.de senden und ich werde ein Einführungs Post nachschieben. Hier geht es um das Starten einer Animation und was nachher passieren soll.

    ControlStoryBoardAction

    Aus den Bereich Assets finden sich einige Blend typische Behavoirs. Mit diesen kann ein Designer ohne Code das Verhalten einer Benutzer Schnittstelle steuern. Um ein Storyboard auf eine definierte Benutzer Aktion in Silverlight zu starten verwendet man ControlStoryBoardAction.

    image

    Diese Action zieht man per Drag Drop einfach auf das Control das als Steuerung dienen soll. In diesem Beispiel die ganze Silverlight Anwendung per Layoutroot.

    image

    Dann wird in dem Eigenschaft Dialog festgelegt welche Aktion ( hier MouseleftbuttonDown) welches Storyboard (hier Storyboard1) steuern soll und letztendlich welche Aktion ausgeführt werden soll.

    image

    Das war's schon. Keine Zeile Code nötig.

    In den Triggern gibt es auch noch ein paar ganz abgefahrene. So auch einen der das Event behandelt wenn das Storybord fertig ist.

    image

    RemoveElementAction

    Im nächsten Teil betrachten wir wenn ein Storyboard zu Ende ist, also ein finished Event feuert. In meiner Anforderung steht das ein neu erzeugtes UIElement eine Animation ablaufen lassen soll und dann anschliessen spurlos aus dem Controltree entfernt werden soll. Das kann man aufwendig per Code erledigen oder per Maus und Expression Blend.

    Dafür kommt das RemoveElementAction Behavior zum Einsatz. Einfach per Drag und Drop reinziehen.

    image

    Dann wird noch ganz ähnlich wie vorher beschrieben gesteuert was wann wie entfernt werden soll. In meinem Fall soll nach Ende der Animation das animierte Objekt (hier Ellipse) verschwinden.

    image

     

    Für mich einfach nur genial.



    Erstellt am: 31.05.2010 15:45:31 | Kommentare: | Erstellt von: Hannes Preishuber
    Kategorien: Silverlight, Blend,


    Das IPad die Gründe dagegen


    Mein geschätzter Kollege Torsten hat sich wohl gerade ins Ipad verlieb. Zugegebenermaßen ein reizvolles Gadget. Was spricht dagegen?

    Kein Mini USB Port

    Für mich unverzichtbar zum aufladen egal ob Auto oder Netzteil. Sowas habe ich immer griffbereit in der Nähe

    der Preis

    Hallo Apple gehts noch? Ein Netbook samt UMTS gibst für 279,-

    Der Closed Gedanke

    Nun kann man Microsoft ja viel nachsagen, aber im Gegensatz zu dem was Apple treibt ist Microsoft eine Open Source Company. Nicht nur das ich nur bei den Jungs mit dem angebissenen Apfel kaufen kann, sie können auch jederzeit ne App wieder deaktivieren. Wenn ich was kaufe will ich machen können was ich will, Backup, weitergeben ect.

    fehlendes Multitasking

    Das Argument ist, wer tut schon 2 Dinge gleichzeitig. Na ich z.B., Radio hören und Emails checken. Bin ich abartig?

    Fehlende Webcam

    das ist einfach nur traurig in heutigen Zeiten. Produktmehrkosten vermutlich 2$. Aber so kann man halt besser die nächste Version verkaufen. “Look, now we have a Webcaaaam”

    fehlender Stift

    Multitouch ist klasse aber in manchen Situationen ist ein Stift viel besser. Zb. Winter mit Handschuhen oder Handschrift Eingabe. Genauso ist eine Tastatur einfach besser als keine Tastatur.

    Hochglanz Display

    Das ist nicht unbedingt Apple anzulasten, aber glänzende “Glare” Displays sind draußen einfach nur Müll. Man sieht bestenfalls sicht selbst.

     

    Ich bin schon gespannt wenn auf der APPs konferenz Torsten Weber mit seinem IPad auftaucht und Karsten Samaschke was zur Programmierung desselben erzählt.



    Erstellt am: 26.05.2010 19:13:52 | Kommentare: | Erstellt von: Hannes Preishuber
    Kategorien: Konferenzen,


    © Copyright 2008 ppedv AG