Unified Messaging Tools von Visendo Software – Ein Überblick


 

Für alle, die neu hier sind: Ein kurzer Überblick über uns und unserer Produkte.

Wir stehen für höchstes technisches Know-How:

  • mehr als 13 Jahre Erfahrung im Bereich Electronic Communications
  • Microsoft Gold Partner mit 3 Microsoft Kompetenzen – ISV, Hardware Solutions, Unified Messaging
  • Technology Partner von Funkwerk, Lancom, Dialogic, TE-Systems, AASTRA
  • Visendo Software ist in Wikipedia - http://en.wikipedia.org/wiki/Fax_server#List_of_fax_servers

Alle unsere Produkte
  • bieten volle 64-Bit Unterstützung
  • 24 Monate kostenlosen Support
  • haben eine automatische Update-Funktion
  • können in virtuellen Umgebungen eingesetzt werden (Hyper-V, VMWARE, Virtual Box)
  • unterstützen die neuesten Betriebssysteme (Windows 7, Windows 2008 Server, Windows 2008 Server R2, Windows SBS 2011 ) und sind als “Designed for Windows” zertifiziert
  • können mit den neuesten SMTP-Servern betrieben werden (Exchange 2007, Exchange 2010, Postfix )
  • haben eine transparente Architektur und Backend-Unterstützung, so dass sie in jeder Umgebung eingesetzt werden können ( SQL, Oracle, MySQL)
  • bieten Enterprise Platform Integration mit Office 2010, SharePoint, Windows Azure und SAP
  • sind 100% Green IT: verringerter Energieverbrauch, um einen geringen Carbon Footprint zu erzeugen
  • können in 5-10 Minuten installiert oder migriert werden

 

Teil I: Fax-Software

Fax- und Dokumentmanagement-Lösungen (Produktübersicht)

  • Faxe empfangen/senden und per Mail, ins Dateisystem oder an den Drucker weiterleiten
  • Mächtiges Regelsystem für spezielle Weiterleitungsregeln
  • Elektronische Dokumente als Fax versenden
  • VoIP, Messaging Gateways, FOIP
  • Integration
    • Office 2007 / 2010
    • SharePoint 2007 / 2010
  • Clients: Fax Drucker, Web, Mobile (Android, I-Pad, I-Phone, Windows Phone 7
 

Weitere Informationen

Visendo Fax Server

Visendo Fax@Mail10



Erstellt am: 15.06.2011 16:26:10 | Kommentare: | Erstellt von: cosmin dumitru
Kategorien:


Ganzer Bildschirm Voller Screen


Es ist ein leichtes eine Silverlight Anwendung in den FullScreen Modus zu schalten.

Application.Current.Host.Content.IsFullScreen = True

Es gibt allerdings Einschränkungen. So kann der Benutzer keine Texteingaben mehr durchführen und man muss diese Codezeile in  ein vom Benutzer initiiertes Event legen. Button Click ist so eines.

Den FullScreen kann der Benutzer mit ESC wieder verlassen. Ausnahme ist wenn man per ALT TAB (oder auch sonst wie) die aktive Anwendung wechseln möchte. Dann ist der Fullscreen  Modus ganz von alleine weg. Wenn man dies verändern möchte hilft folgendes Silverlight Beispiel Code

Application.Current.Host.Content.FullScreenOptions =
        System.Windows.Interop.FullScreenOptions.StaysFullScreenWhenUnfocused

Der Silverlight User erhält nun einen Dialog ob er dieses Verhalten erlauben möchte und kann seine Antwort auch dauerhaft abspeichern.

image

Wenn die Silverlight Anwendung OOB ( Out Off Browser) mit elevated Priviliges läuft, kommt der Dialog nicht und der Benutzer kann sogar Tastatureingaben durchführen.

Der Zoom Faktor des Browser wird übrigens im Vollbild Modus ignoriert. Wenn man das wissen und nutzen möchte, gibt es im Content.ZoomFaktor den Vergrößerungswert als Double zurück. Dies und noch viel mehr lernen Sie bei den Silverlight Schulungen der ppedv.



Erstellt am: 17.11.2010 19:26:02 | Kommentare: | Erstellt von: Hannes Preishuber
Kategorien: Silverlight, .Net,


Anonyme Typen an ein Silverlight Datagrid binden


Was soll ich sagen, man lernt nie aus. In meiner aktuellen Silverlight Schulung saß ein Kurs Teilnehmer der es genau wissen wollte. Mein Silverlight Beispiel zeigt wie man mit minimalen Aufwand einen RSS Feed (hier n-tv) an ein Datagrid bindet. Dafür braucht man eine Klasse (hier rss) mit Eigenschaften (hier title) die Public sind. Struct geht schon mal nicht.

Der sehr einfache Silverlight Prototyp:

    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("xmlfile1.xml", UriKind.Relative))
    End Sub

    Private Sub fertig(ByVal sender As Object, ByVal e As DownloadStringCompletedEventArgs)
        Dim xml = XDocument.Parse(e.Result)
        Dim query = From x In xml.Descendants("item")
                    Select New rss With {.titel = x.<title>.Value}
        DataGrid1.ItemsSource = query
    End Sub

End Class
Public Class rss
    Public Property titel As String
End Class

Die Ausgabe in der Silverlight Anwendung dann ungefähr so.

image

Der liebe Silverlight Kurs Teilnehmer war faul und wollte es mit anonymen Typen versuchen also ohne die RSS Klasse zu erstellen ala

 Dim query = From x In xml.Descendants("item")
                    Select New With {.titel = x.<title>.Value}
        DataGrid1.ItemsSource = query

Das Ergbebnis dann

image

Meine Antwort ist halt so. Anonym geht eben nicht da diese als internal deklariert sind und deshalb nicht sichtbar. Da mein Teilnehmer mit Testing ganz versiert war wusste er das man innen nach außen kehren kann mit InternalsVisibleTo. Dies muss man in der Datei AssemblyInfo.vb deklarieren. Üblicherweise befindet sich diese im Verzeichnis Properties der Silverlight Anwendung. Wenn nicht vorhanden einfach anlegen und folgendes reintippen.

<Assembly: System.Runtime.CompilerServices.InternalsVisibleTo("System.Windows")> 

Und schwupp gehts auch anonym.



Erstellt am: 17.11.2010 18:53:21 | Kommentare: | Erstellt von: Hannes Preishuber
Kategorien: Silverlight, .Net,


Silverlight MCP 71-506


So heute habe ich nun die Beta Prüfung zum Silverlight MCP gemacht. Habe ich bestanden? Will ich mal hoffen. Als Beta Tester erfährt man das erst später. Leider darf ich nichts zum Inhalt sagen. Ist alles NDA. War jedenfalls wirklich schwierig. So einen kürzen Überblick will ich Euch dennoch geben. Durchaus einige WCF Fragen und gar nichts zu RIA Services. Auch gar nichts zu Blend.  Animationen per Hand (wer macht das schon). In meinem Fall habe ich die VB.NET Variante gewählt. Schwierig waren vor allem die langen Fragen. Wenn man über zwei Bildschirme scrollen muss ist es recht mühsam den Überblick zu behalten. Auch war ein paar Tricks eingebaut, wo man die genaue Fragestellung lesen musste. Oft steht aber in der Frage auch überflüssiges Blabla und man schaut am besten gleich auf die Antworten ob da offensichtlich unsinniges dabei ist. Überrascht hat mich auch der Umfang zu iCommand und eine Routing Fragen (aus dem Navigation Application Template). Die Databinding Sache empfand ich wieder als leicht. Wenn dann die Frage zu leicht ist suche ich immer den Haken. Keine Ahnung on da einer ist. Da ich die Prüfung in Englisch machen musste war manchmal nicht ganz klar was die eigentliche Bedeutung ist. Ein Lexikon hilft da auch nicht.

Inhalt ist aber ohnehin schon public. Allerdings nicht ganz komplett. Der Begriff CollectionViewSource fehlt auf der Seite Zwinkerndes Smiley.

Wer die Prüfung besteht hat nachgewiesen überdurchschnittliches Silverlight Know How. Kritik Punkt ist, das manche Fragen so exotisch sind (zb Assembly Caching Detail) das wenn ich das Feature mal alle 3 Monate brauche, ich einfach in der Doku nachlese.

Public Solls ab Anfang Januar 2011 sein.



Erstellt am: 15.10.2010 13:50:55 | Kommentare: | Erstellt von: Hannes Preishuber
Kategorien: Silverlight,


MP3 download mit Silverlight


Nein dies ist kein Filesharing Anleitung um illegale MP3 Musik zu downloaden. Ich schreibe grad einen Vokabeltrainer für meinen Sohn. Dabei soll auch die Aussprache trainiert werden. Leo.org bietet neben Übersetzung auch den Service den Englischen Text vorzulesen. Für meine Lernanwendung möchte ich aber gelernte Vokabel speichern. Also das MP3 per Download im Isolatedstorage speichern. Die Download URL ist relativ simpel das gesprochene Wort mit der Endung mp3. Mittels dem Webclient wird ein asynchroner Download gestartet. Da es sich um binäre Daten handelt macht ein Stream mehr Sinn. Diesen erhält man per Openreadcompleted.

Dim url As String = "http://www.leo.org/dict/audio_en/" + txtenglisch.Text + ".mp3"
Dim wc As New WebClient
        AddHandler wc.OpenReadCompleted, AddressOf mp3fertig
wc.OpenReadAsync(New Uri(url, UriKind.Absolute)))

Wenn nun der Download der MP3 Datei fertig ist, muss man sich überlegen wie man die Datei speichert. Da gibt's im wesentlichen nur die Methode im IsolatedStorage. Für möglichst kurzen Code hole ich mir die Länge des Streams über einen kleinen Umweg StreamResourceInfo. Dann muss man Binär lesen und schließlich Binär schreiben.

Private Sub mp3fertig(ByVal sender As Object, ByVal e As OpenReadCompletedEventArgs)
  Dim srInfo = New StreamResourceInfo(e.Result, Nothing)
  Dim sr As BinaryReader = New BinaryReader(srInfo.Stream)
  Dim iso As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication
  Using iosr As IsolatedStorageFileStream = iso.OpenFile(txtenglisch.Text + ".mp3", FileMode.OpenOrCreate)
     Using bw As BinaryWriter = New BinaryWriter(iosr)
        bw.Write(sr.ReadBytes(srInfo.Stream.Length))
     End Using
  End Using
 sr.Close()
End Sub

Schließlich noch der Hinweis. Wenn der Platz  (1 MB) nicht reichen sollte, kann dieser vergrößert werden. Der Benutzer muss das aber noch bestätigen. IncreaseQuotaTo(1000000)



Erstellt am: 04.10.2010 18:35:12 | Kommentare: | Erstellt von: Hannes Preishuber
Kategorien: Silverlight, .Net, VB,


die Zeichen mehren sich


Bill Gates kommt zurück. Zumindest in Outlook 2010 und dem social Connector.

image

Ich habs mit Expression Design vektorisiert.

 

image

Die Zeichen mehren sich, Bill Gates kommt zurück.



Erstellt am: 01.10.2010 15:31:37 | Kommentare: | Erstellt von: Hannes Preishuber
Kategorien: Design,


Silverlight Socket Client


In einem früheren Post habe ich beschrieben, wie man einen einfachen Socket Server baut. Dieses mal will ich den Service konsumieren. Eine Socket Service Kommunikation ist extrem effizient. Allerdings müssen die verwendeten Ports in allen beteiligten Firewalls auch frei geschalten sein. Silverlight auferlegt sich zudem eine künstliche Beschränkung auf den Bereich 4502-4534. Noch viel schwerwiegender ist, das man bei der TCP Socket Kommunikation sehr schnell in Cross Domain Szenarien landet. Dann erhält man Security Exceptions, außer die Anwendung läuft OOB full trusted. Für allen jene denen diese Beschreibung noch nicht verwirrend genug ist: Wenn die Anwendung im Browser läuft muss eine ClientAccessPolicy.XML Datei angelegt werden, die dann von Silverlight ungefragt angefordert wird. Format und Inhalt ungefähr so.

<?xml version="1.0" encoding="utf-8"?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from http-request-headers="*">
        <domain uri="*" />
      </allow-from>
      <grant-to>
        <socket-resource port="4502-4534" protocol="tcp" />
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy> 

Der vorläufige Höhepunkt ist, das Silverlight ab Version 4 versucht diese Datei auf Port 943 anzufordern. Dafür müsste man nun noch einen extra Socket Server schreiben der auf diesem Port lauscht und die Datei überträgt. Ist mühsam und deswegen gibt es wohl nun die Zweitmöglichkeit die Datei in das root des Webservers zu legen und per http auszuliefern. Allerdings muss man Silverlight das im Code noch mitteilen (SocketClientAccessPolicyProtocol.Http) wie wir gleich im folgenden Code sehen werden. Erlaubt sei noch der Hinweis das dies mit dem WebDev Server aus Visual Studio nicht geht, weil dieser auf einen zufälligen Port lauscht und nicht auf 80.

Weiter gehts mit der Initialisierung der Socket Verbindung.   Die Sache mit der IP Adresse ist ein wenig mühsam und muss über den DNS Endpoint gelöst werden um rauszukriegen auf welcher Website die Anwendung läuft. Am Ende wird versucht die Verbindung herzustellen.

Dim sock As Socket
Private Sub Button1_Click(ByVal sender As System.Object, 
ByVal e As System.Windows.RoutedEventArgs) Handles Button1.Click Dim ep As DnsEndPoint = New DnsEndPoint(Application.Current.Host.Source.DnsSafeHost, 4506) sock = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) Dim args As SocketAsyncEventArgs = New SocketAsyncEventArgs() args.RemoteEndPoint = ep args.SocketClientAccessPolicyProtocol =
SocketClientAccessPolicyProtocol.Http 'Clientaccesspolicy AddHandler args.Completed, AddressOf onSocketConnect sock.ConnectAsync(args) End Sub

Da das ganze asynchron läuft, wie bei Silverlight üblich, benötigt man die Funktion onSocketConnect, die aufgerufen wird sobald die Verbindung besteht. Jetzt wirds ein wenig Tricky. Um die eingehenden Daten zu erhalten, brauchen wir noch ein zweites Event OnSocketEmpfang. Da dies auch am Completed Event der SocketArgs hängt, habe ich die Events durch deregistrieren und registrieren ausgetauscht. Ob dies der beste Weg ist, ist mir nicht bekannt. Zumindest habe ich auf an anderer Stelle ähnliche Ansätze gefunden. Nun gehts ans Empfangen mit ReceiveAsync.

Private Sub onSocketConnect(ByVal sender As Object, ByVal e As SocketAsyncEventArgs)
  If sock.Connected Then
     RemoveHandler e.Completed, AddressOf onSocketConnect
     Dim resp(1024) As Byte
     e.SetBuffer(resp, 0, resp.Length)
     AddHandler e.Completed, AddressOf onSocketEmpfang
     sock.ReceiveAsync(e)
  End If
End Sub

Wenn dann ab und zu mal Sekunden in der Form 40 oder so eintrudeln, landen wir im OnSocketEmpfang. Die Daten stehen zwar freundlicherweise im e.Buffer, aber leider befinden wir uns im Background Thread. Entsprechend muss per BeginInvoke ein Delegate definiert werden die eine Methode aufruft die im UI Thread läuft.  Dabei werden die Argumente e als Parameter übergeben. Schlussendlich rufe ich wieder den ReceiveAsync Befehl auf, weil die Daten regelmäßig bis zum Sankt Nimmerleinstag kommen.

Private Sub onSocketEmpfang(ByVal sender As Object, 
ByVal e As SocketAsyncEventArgs) Dispatcher.BeginInvoke
(New Action(Of SocketAsyncEventArgs)(AddressOf updateUI), e) sock.ReceiveAsync(e) End Sub

Der Vollständigkeit halber noch der Teil der letztendlich eine TextBox im Frontend aktualisiert.

Private Sub updateUI(ByVal e As SocketAsyncEventArgs)
   TextBlock1.Text = 
Encoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred) +
Environment.NewLine End Sub

Wer keine Erfahrung mit dem synchronsieren von Threads hat und das für Teufelszeug hält, soll mal in die app.xaml.vb oder app.xaml.cs blicken. Dort wird das globale Fehlerhandling genau so realisiert. Mit Hilfe einer Lambda Expression noch etwas eleganter codieren, obs lesbarer ist mag jeder selbst entscheiden.

Dispatcher.BeginInvoke(
 New Action(Of SocketAsyncEventArgs)(
Sub() TextBlock1.Text +=
Encoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred) + Environment.NewLine End Sub), e)


Erstellt am: 30.09.2010 23:03:32 | Kommentare: | Erstellt von: Hannes Preishuber
Kategorien: .Net, Silverlight, XAML,


Socket Server mit VB.NET


Um ein größeres Ziel zu verfolgen musste ich einen Socket Server schreiben. Tendenziell wird man bei Server an einen Lösungsansatz mit Service denken. Ich nehme aber eine einfach Winforms Anwendung, weil mein Server nur Sinn macht wenn ein Benutzer angemeldet ist. Im weitesten Sinn überwacht mein Socket Server ein Stück Hardware und meldet Daten in einer Art Event an eine Silverlight Anwendung. Die Implementierung erfolgt auf Alpha Prototyp Level. Also sicher noch erhebliches Refactoring Potential. Ich war wirklich faul und habe mich auch auf die vorhandenen Steuerelemente gestürzt und eben ein Timer Control (Timer1) auf das Formular gezogen.

Der Socket Server lauscht auf Port 5406, weil dies im Bereich der von Silverlight nutzbaren Ports liegt.

tcpL = New TcpListener(IPAddress.Parse("127.0.0.1"), 4506)
tcpL.Start()
tcpL.BeginAcceptSocket(AddressOf onConnect, Nothing)

Der Listener und auch der Client (es reicht eine Verbindung) wird global in der Forms Klasse definiert.

 Dim tcpL As TcpListener
 Dim tcpClient As TcpClient

Weil es später zur Laufzeit recht wenig Transparenz gibt, was das Programm gerade tut, schreibe ich in das Output Fenster von Visual Studio. Mit AcceptClient wird der Kanal geöffnet und gewartet bis sich ein Client meldet. Die eigentliche Kommunikation findet dann asynchron statt. Da ich die Daten die vom Silverlight Client gesendet werden nicht brauche, ist die Funktion der “ClientSpricht” leer.

Dim iasy As IAsyncResult
Private Sub onConnect(ByVal ia As IAsyncResult)
 Try
  tcpClient = tcpL.EndAcceptTcpClient(ia)
  iasy = tcpL.BeginAcceptTcpClient(AddressOf clientSpricht, Nothing)
  Trace.WriteLine("connected...")
 Catch ex As Exception
  Trace.WriteLine(ex.ToString())
 End Try
End Sub

Viel wichtiger ist, was der Server zum Server sagt. Dazu wird regelmäßig ein Timer Event gefeuert, das folgenden Code ausführt und die zur Demonstration Sekunden sendet.

If IsNothing(tcpClient) = False AndAlso tcpClient.Connected Then
  Dim networkStream As NetworkStream = tcpClient.GetStream
  Dim sendBytes As [Byte]() = Encoding.ASCII.GetBytesDate.Now.Second.ToString)
  networkStream.Write(sendBytes, 0, sendBytes.Length)
Trace.WriteLine("sending..." + Date.Now.Second.ToString)
End If

Wie kann man nun feststellen das dieser Server auch funktioniert? Ganz einfach mit Telnet4358. Zuerst wird das Kommando telnet localhost 4506 eingegeben und dann erscheinen die Zahlen wie im Bild ersichtlich regelmäßig.

image



Erstellt am: 30.09.2010 16:21:50 | Kommentare: | Erstellt von: Hannes Preishuber
Kategorien: .Net, VB, Silverlight,


Jscript Zauberei mit Silverlight


Wenn man nachfolgende Webentwicklern um den Verstand bringen will, arbeitet man mit dynamisch generierten JScript Code. Da gibt es nachher nichts im Browser zu sehen mit View Source. Um das ganze auf die Spitze zu treiben, erzeuge ich aus  einer Silverlight Anwendung den Code im Browser. Es gibt dazu auch durchaus Probleme, die zu dieser Lösung passen könnten. In früheren Silverlight Weblog Eintrag habe ich beschrieben wie man statt WebClient den Browser Stack direkt ansprechen kann. Basierend auf diesem Ansatz nun eine Jscript Lösung. Ist kein schöner Code, sondern eher nur konzeptionell. Basis ist eine XMLRPC Abfrage der Gültigkeit einer USTID beim Finanzamt.

Zunächst wird eine Callback Funktion mit Rufmichan im Browser erzeugt. Dann wird die Methode erzeugt die dann eine Instanz des XMLHTTP Objektes erzeugt und den Webservice aufruft. Dann muss diese Funktion (callws) aufgerufen werden. Dies passiert per Invoke.

Private Sub Button1_Click(ByVal sender As System.Object, 
ByVal e As System.Windows.RoutedEventArgs) Handles Button1.Click createRufmichan() createJSCall("http://evatr.bff-online.de/evatrRPC?UstId_1=
DE123456789&UstId_2=AB1234567890&Firmenname=
&Ort=&PLZ=&Strasse=&Druck="
) Dim r = HtmlPage.Window.Invoke("callWS") End Sub

Nun sehen wir uns den Code an der im Browser erzeugt werden soll und wie das geschieht. Um der nachfolgenden Rückruffunktion eine Möglichkeit zu geben auf dei INstnaz zuzugreifen wird w ausserhalb der Funktion callWS definiert. Das HtmlPage Objekt von Silverlight kann per Createlement auch JScript Elemente erzeugen und dann per AppendChild ans DOM des Browserwindows anhängen.

Public Sub createJSCall(ByVal url As String)
  Dim s As String = "w = new XMLHttpRequest();
w.onreadystatechange=rufmichan;
w.open('GET', url; w.send(null);"
Dim js = HtmlPage.Document.CreateElement("script") js.SetAttribute("type", "text/javascript") js.SetAttribute("text", "var w;function callWS() {" + s + " }") HtmlPage.Document.DocumentElement.AppendChild(js) End Sub

Wenn dann der Callback zurück kommt wird folgende Funktion benötigt.

Public Sub createRufmichan()
  dim js = HtmlPage.Document.CreateElement("script")
  js.SetAttribute("type", "text/javascript")
  js.SetAttribute("text", "function rufmichan() 
{if (w.readyState == 4) {alert(w.responseText);}}"
) HtmlPage.Document.DocumentElement.AppendChild(js)

Das wars schon. Wie kann ich aber feststellen das alles passt? Natürlich wenn die Messagebox mit dem Ergebnis kommt. Auch sehr hilfreich sind seit IE8 die Entwiclertools zu starten mit F12 Taste.

image



Erstellt am: 24.09.2010 22:45:22 | Kommentare: | Erstellt von: Hannes Preishuber
Kategorien: ASP.NET, JScript, Silverlight,


ppedv Konferenzen


Ich versuche mein Blog Werbefrei zu halten. Insofern auch mehr zur Info, weil ich weis das viele Leser meines Blogs auch gerne mal auf Konferenzen sprechen.

Also was ist am Plan

SQLdays  Rosenheim 19.-20.Oktober

http://www.sqldays.net/

Highlights: schaut euch mal die Sprecher an. Ist ein sehr kommunikativer Rahmen. Als ne echte Chance für die BI und SQL Spezialisten sich zu treffen.

ADC Advanced Developer Conference

Bonn 25.-26.Oktober

http://www.adc10.de/

Die älteste Konferenz (seit gut 15 Jahren)  für professionelle Entwickler. Keine Einstieg oder Einführung Sessions, Level 300 und up. Cooles Sprecherboard!

GUI&Design

Nürnberg 8.-9. Dezember

http://gui-design.ppedv.de

Weg vom grauen Rechteck im oberen Bildschirmeck. Hin zu Anwendungen die die Benutzer lieben. Auf allen Geräten von kleinsten Windows Phone 7 bis zu Surface Formfaktor. Eben die Mischung von Usablity und Design die der Entwickler in Zukunft braucht. Call for papers ist offen.

VSone und Sharepoint konferenz

16.-17.Februar 2011 München

Neue bessere Location! Das Key Event der Branche mit 10 parallelen Tracks und allen Themen. Hier trifft sich die gesamte Community im Microsoft Eco System. Call for papers ist nicht eröffnet.

www.vsone.de

Geheim Projekt- coming soon

18.-19 Februar München…



Erstellt am: 22.09.2010 13:00:17 | Kommentare: | Erstellt von: Hannes Preishuber
Kategorien: .Net, Konferenzen,


Unbutu auf Virtual PC installieren


Weil es nichts gibt was man nciht probieren könnte, installiere ich heute mal Unbutu auf Windows 7 und dessen virtual PC. Leider geht das nicht problemlos. Deshalb hier eine Schrittweise Anleitung. Nachdem man das ISO runtergeladen wurde muss der VPC in Windows 7 eingerichtet werden. in meinem Beispiel habe ich eine virtuelle VHD mit einer Größe von 10G vorformatiert. Dann muss die ISO Datei als DVD Laufwerk eingerichtet werden.

image

Dann kann wird der VPC gestartet und man muss öfter auf F4 drücken.

image

Der Dialog wird mit ESC geschlossen und dann durch drücken von F6 die Kommando Zeile fürs Booten angezeigt. Nach einmaligen drücken von ESC kann die Zeile direkt bearbeitet werden.

image

Da muss dann vga=791 noreplace-paravirt eingefügt werden statt splash –.

Nach installation nicht rebooten. ESC drücken

Dann das Programm Terminal öffnen.

image

Dort müssen folgende vier Zeilen eingetippt werden. Wobei recht mühsam die GUID aus dem oberen Menübereich abgetippt werden muss (2x).

sudo mount -o bind /dev /media/GUID/dev
sudo chroot /media/GUID/ /bin/bash
mount -t proc none /proc
nano /etc/default/grub

image

Dort wird dann im Editor die änderung durchgeführt "quiet splash" zu VGA=788. Gespeichert wird mit STRG –X. Bestätigen mit Ja und Dateinamen bestätigen.

Als nächstes folgende Datei editieren per Kommando

nano /etc/grub.d/10_linux 

image

Auch hier mit STR X speichern.

Neustart mit roten Button i rechten oberen Eck. Im Command Fenster Fehlermeldung mit Casper mit ESC ignorieren

Während ich mir in mehren Blogs diesen Weg zusammengesucht habe, bin ich, nachdem schon fast fertig über  Scott Hanselman’s Blog gestolpert.

 

http://www.hanselman.com/blog/InstallingUbuntu104LTSOnWindowsVirtualPCOnWindows7.aspx?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+ScottHanselman+%28Scott+Hanselman+-+ComputerZen.com%29



Erstellt am: 20.09.2010 21:45:51 | Kommentare: | Erstellt von: Hannes Preishuber
Kategorien:


Cross Domain und die drei tapferen Network Stacks


Folgende Zeichnung zeige ich immer in meinen Silverlight Kurs. (Tablet PC sei Dank)

image

Damit soll der Silverlight Schulung Teilnehmer lernen, das es per Definition verboten ist, auf einen zweiten Webserver zuzugreifen (Stichwort crossdomain.xml und clientaccesspolicy.xml). Diese Grundlagen werde ich vielleicht wann anders beschreiben. Wer es nachschlagen möchte “Crossdomain”.

Das folgende Szenario ist nicht ganz trivial. Läuft die Anwendung OOB ( Out of Browser) mit elevated Priviliges werden crossdomain limitierungen ignoriert. Wenn die Anwendung im Browser läuft wird erstens per default ein anderer Network Stack verwendet und es gibt eine Fehlermeldung. Außer der Web Server hat im Root Directory eine der beiden vorher erwähnten XML Dateien liegen.

Das bedeutet das eine Silverlight Anwendung ,abhängig wo sie läuft, unterschiedlichen Code ausführt. Also folgenden Zeilen Code benutzen effektiv zwei unterschiedliche Network Stacks.

Dim wc As New WebClient
AddHandler wc.DownloadStringCompleted, AddressOf fertig
wc.DownloadStringAsync(...

Der eine Stack wird Network Stack genannt, weil er echte Netzwerk Funktion implementiert. Der andere Stack heißt Browser Stack weil er das XMLHTTP Objekt des Browser kapselt.

Nun gibt es die Anforderung das ein solcher Cross Domain Zugriff (zb auf die Twitter API) durchgeführt werden soll

  • aus dem Browser
  • unter Ignoranz der crossdomain policys

Das geht mit dem “dritten Netzwerk” Stack. Dem XMLHttp Objekt direkt z.B. aus JScript. Silverlight bietet dafür eine HTMLPage Helper Klasse mit der man ziemlich einfach direkt im Browser arbeiten kann. So lässt sich per eval beliebig dynamisch generierter JScript Code ausführen oder mit Invoke eine Jscript Funktion aufrufen. Noch besser ist aber das Silverlight ScriptObject. Damit lassen sich unter Semi Intellisense Unterstützung JScript Objekte instanzieren. Mit Invoke werden dann die Methoden aufgerufen.

Ausgehend von folgendem Jscript Beispiel

var w = new XMLHttpRequest();
w.onreadystatechange = function () 
{
if (w.readyState == 4) {
    alert(w.responseText);
 }}
w.open("GET", "http://...", true);
w.send(null);

Lässt sich so mit managed Code in VB.NET die Silverlight Anwendung ausprogrammieren.

Dim url As String = "http://..."
Dim req As ScriptObject
req = HtmlPage.Window.CreateInstance("XMLHttpRequest")
req.Invoke("open", "GET", url, False)
req.Invoke("send")
TextBlock1.Text = req.GetProperty("responseText")

Ein erster Test mit Chrome und Firefox funktioniert ohne Probleme. Mit Internet Explorer 9 kommt eine Sicherheitsabfrage die der Benutzer bestätigen muss.

image

Abgesehen von dieser kleinen Hürde kann so die Crossdomain Limitierung von Silverlight mit wenigen Code Zeilen umgangen werden. Darüber hinaus bietet der XMLHTTP JScript Network Stack auch mehr Funktionen, da der Silverlight Wrapper nur das nötigste implementiert hat.



Erstellt am: 19.09.2010 18:27:36 | Kommentare: | Erstellt von: Hannes Preishuber
Kategorien: .Net, VB, Silverlight, JScript,


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,


    © Copyright 2008 ppedv AG