Responsive Design / Layoutgestaltung für jede Bildschirmauflösung

Aufgabenstellung

Ein HTML-Layout soll sich automatisch an die Gegebenheiten des Endgerätes anpassen, egal ob mobiles Endgerät oder eine Großleinwand

Ansatz

Responsive Design funktioniert durch die Verwendung des @media-Tags von CSS. Das Layout richtet sich an der Bildschirmauflösung und der Orientierung des Endgerätes

Lösung

Aufbau der CSS-Datei:

@media (min-width: 950px) 
{
  /* Hohe Auflösung */
}

@media (min-width: 450px) and (max-width: 900px)
{
  /* Mittlere Auflösung */
}

@media (max-width: 450px) 
{
  /* Kleine Auflösung */ 
}

Quelle: www.mariofink.de

Workflow Patterns – Teil 1

Workflows

Was ist ein Workflow?

Grundsätzlich ist ein Workflow erstmal nichts technisches. Es geht hierbei meistens (so auch hier) um Formulare, die in einem Unternehmen mehrere Abteilungen und Stationen durchlaufen. Ob das Formular auf einem Papier oder in einer rechnergestützten Anwendung realisiert wurde, spielt dabei vorerst keine Rolle.

Mithilfe von Workflows können Personen gemeinsam an Dokumenten arbeiten. Organisationen können einheitliche Geschäftsprozesse einhalten und die Effizienz und Produktivität der Organisation verbessern, indem die Aufgaben und Schritte einzelner Geschäftsprozesse verwaltet und harmonisiert werden. Auf diese Weise können sich die Personen, die diese Aufgaben ausführen, auf die Arbeit selbst und nicht auf die Verwaltung des Workflows konzentrieren.

Papiergebundene Workflows haben im Vergleich zu rechnergestützten Workflows den Nachteil, dass sich die folgenden Fragen nicht beantworten lassen:

  • Wo befindet sich das Dokument?
  • Wer bearbeitet es?
  • Wer hat es schon bearbeitet?
  • Kann ich das Dokument schnell zurückholen?
  • Wann wurde es in Umlauf gebracht?
  • Wurde ein Datum überschritten?

Ein Workflow ist eine inhaltlich abgeschlossene, zeitlich und sachlogisch zusammenhängende Folge von Schritten, die zur Bearbeitung eines betriebswirtschaftlich relevanten Objektes notwendig sind und deren Funktionsübergänge von einem Informationssystem gesteuert werden.

Abgeschlossenheit: Ein Workflow definiert einen Arbeitsablauf mit einer Abfolge von Aktivitäten innerhalb einer Organisation. Die Abfolge beginnt an einem bestimmten Punkt und endet auch an einem solchem. Es gibt daher einen Initiator eines Workflows und eine Aktion, die am Ende definiert, was als nächstes passieren soll.

Zeitlicher Ablauf: Ein Workflow kann an einem Zeitpunkt 1 beginnen und an einem Zeitpunkt 5 aufhören. Wenn dies der Fall ist, existieren 5 Workflowpositionen.

Sachlogik:
Sachlogik dient dazu..

  • Aktionen zu validieren und Eingabefehler auszuschließen
  • den zeitlichen Ablauf anhand bestimmter Kriterien zu beeinflussen
  • Workflowpositionen nach Notwendigkeit wegfallen oder hinzukommen zu lassen
  • Schritte die automatisierbar sind durch definierte Logik durch den Workflow eigenständig erledigen zu lassen

In der Regel ist das betriebswirtschaftliche Objekt ein Formular, welches zum Einsammeln von Daten gedacht ist.

Wo werden Workflows verwendet und welchem Zweck dienen Sie?

Workflows werden überall dort verwendet, wo durch einen strukturierten Arbeitsablauf transparenz und Arbeitsersparnis erreicht werden kann. Arbeitsersparnis erhält man in der Regel durch den niedrigeren Koordinationsaufwand, die Transparenz hingegen durch die Möglichkeit den Status eines Workflows abzufragen (an welcher Workflowposition hängt es – wen muss ich ansprechen – wer ist verantwortlich?). Normalerweise würde man anfangen rumzutelefonieren, bei wem ein Dokument gerade liegt. Dies kann über eine Suchfunktion ínnerhalb des Informationssystems realisiert werden.

Wer braucht Workflows?

Personen, die …

  • … über Dokumente wie Formulare Informationen/Daten über mehrere, in der Organisation verteilte einsammeln und nicht die Zeit haben hinter einem Dokument hinterherzutelefonieren.
  • … den Verbleib eines Dokumentes genau nachvollziehen müssen
  • … nicht das Gesamt-Know-How eines Arbeitsprozesses besitzen und auf andere Personen angewiesen sind.
  • … einen Prozess mit erheblichem Aufwand optimieren möchten
  • … gerne mehr Zeit haben.

Welche Realisierungsmöglichkeiten gibt es für Worfklows?

  • Papiergebundene Workflows
  • Web-Workflows
  • Native Workflows
  • Systemintegrierte Workflow (z.B. SAP Workflow)

Wie plant man einen Workflow?

  • Entscheidung für die Implementierung eines Workflows
  • Anforderungserfassung
  • Definition von Zielen und des Optimierungspotentials
  • Festlegung der Workflowinfrastruktur
    • Präsentationsformen: Web/Windows/Mobil
    • Kommunikationstechniken für Beachrichtigungen: z.B. eMail: SMTP-Server, personifizierter Posteingang kombiniert mit eMail-Nachricht …
    • Benötigte Services/Dienste: Z.B. Bestände bei SAP abrufen…
  • Festlegung der Workflowtechnologie
    • Client-Server-Lösung
      • Web-Anwendung: Three-Tier-Architektur mit: Adobe Flex 3/FluorineFX/MS SQL Server
      • Mobil-Anwendung: Android App und iPhone App
    • Stand Alone Lösungen
      • Office Dokumente die sich per eMail versenden
  • Festlegung der Workflowarchitektur
    • Aufgaben, bzw. Rollen
      • Was für Tätigkeiten werden in dem Geschäftsprozess erledigt? Hier leiten sich die Rollen ab…
      • Eine Rolle ist eine Aufgabe, die eine Person in einem Unternehmen hat.
    • Ablauf
      • Reihenfolge: Welche Informationen müssen vor dem Erreichen einer Aufgabe/Workflowposition erfasst sein?

Workflow-Patterns

Workflow-Patterns sind bestimmte Entwurfsmuster, die in Workflow-Projekten immer wieder anzutreffen sind. Workflow-Patterns bestehen aus Workflow-Positionen und Workflow-Abläufen.

Workflow-Positionen

Eine Workflowposition dient der Vorlage, Bearbeitung und Bestätigung von Daten, die über ein Formular eingesammelt werden. Die Workflowposition kann einer Person, oder einer Gruppe von Personen zugeordnet sein.

Zeitliche Abfolgen

Zeitliche Abfolgen legen fest, wann eine Person das Dokument erhält und zu welchem Zeitpunkt.

Logische Abfolgen

Eine logische Abfolge wird nur dann abgearbeitet, wenn ein vorheriges Ereignis / eine vorherige Logikprüfung erfolgreich war und durch eine optionale Workflowpositionen durch die Abfolge erreicht wird.

Vorgänger- und Nachfolgerbeziehungen

Benötigt eine Person Daten von einer anderen, ist die Person, die die Daten benötigt, der Nachfolger der Person, die die Daten in das Formular eingibt. Es gibt hier also eine zeitliche Abhängigkeit, die durch Vorgänger- und Nachfolgebeziehungen defniert werden. Man versucht dabei so viele Positionen parallel abzuarbeiten, wie das möglich ist.

Workflow-Abläufe

Serialisierte Workflowabläufe

Einer nach dem anderen (bsp. Excel-Dokument das bei Bearbeitung immer gesperrt wird).
Vorteile:
* Klarer strukturierter Ablauf.
Nachteile:
* Es geht viel Zeit während der Bearbeitung verloren, wenn keine Daten vom Vorgänger benötigt werden (informelle Abhängigkeit zum Vorgänger).
* Keine parallele Abarbeitung möglich, da immer gesperrt.

Parallele Workflowabläufe

Es können mehrere Personen gleichzeitig an einer Workflowposition auf den Workflow zugfreifen. Erst wenn alle Personen bestätigt haben, läuft der Workflow weiter.

Fortsetzung folget (Workflow Patterns – Teil 2 inklusive Codebeispiele)

Adobe Flex 3: Event-Reihenfolge mit Methode testen

Problem

Adobe Flex 3 definiert eine Reihe von Standard-Events, die über die Kontext-Hilfe bei der Quellcodeingabe mit einem gelbem Blitz gekennzeichnet werden. Häufig nutzt man die Kontext-Hilfe im Flex-Builder (STRG+SPACE ruft sie beim Deklarieren/in der Deklaration eines MXML-Tags auf) um die definierten Events anzuzeigen.

Bei Event-Namen wie creationComplete, applicationComplete, InitializationComplete usw… stellt sich häuft die Frage nach der Reihenfolge

Ansatz

Es werden alle Events, die mit einem gelben Blitz versehen sind, an die deklarierte Methode „eventListener“ übergeben. Diese Methode listet im Debug-Modus über die TRACE-Funktion die Reihenfolge und das Auftreten der Events auf.

Lösung

<?xml version="1.0" encoding="utf-8"?>
<mx:Application added="eventListener(event)"
  addedToStage="eventListener(event)"
  applicationComplete="eventListener(event)"
  creationComplete="eventListener(event)"
  initialize="eventListener(event)"
  preinitialize="eventListener(event)"
  layout="absolute"
  xmlns:mx="http://www.adobe.com/2006/mxml">
 <mx:Script>
    <!&#91;CDATA&#91;
      import flash.utils.getQualifiedClassName;
      import mx.events.FlexEvent;
      
      private function eventListener(event:Event):void 
      {
         if (
              (event.target == this) || 
              (event.target == this.myDataGrid) ||
              (event.target == this.myPanel)
          ) 
         {
            trace(getQualifiedClassName(this) + ".eventListener: " +
	       getQualifiedClassName(event) + "." + event.type);
            trace("\ttarget: " + getQualifiedClassName(event.target));
          }
    }
 &#93;&#93;>
  </mx:Script>
  <mx:Panel added="eventListener(event)"
      addedToStage="eventListener(event)"
      creationComplete="eventListener(event)"
      id="myPanel"
      initialize="eventListener(event)"
      preinitialize="eventListener(event)">
  <mx:DataGrid  added="eventListener(event)"
           addedToStage="eventListener(event)"
           creationComplete="eventListener(event)"
           id="myDataGrid"
           initialize="eventListener(event)"
           preinitialize="eventListener(event)"/>
  </mx:Panel>
</mx:Application>

Microsoft SQL Server: Führende Nullen bei alphanumerischem String abschneiden

Problem

Ein String (z.B. eine Materialnummer oder eine Artikelnummer) besteht aus alphanumerischen Zeichen (z.B. 00003j422a3) und hat führende Nullen, welche abgeschnitten werden sollen (Ergebnis: 3j422a3). Siehe auch „Führende Nullen bei numerischen Strings abschneiden“.

Ansatz

* Zuerst werden ALLE Nullen durch Leerzeichen ersetzt
* danach werden alle Leerzeichen auf der linken Seite mit LTRIM abgeschnitten
* anschließend werden alle Leerzeichen durch 0en ersetzt.

Prämissen / Vorraussetzungen

Es sind keine Leerzeichen in dem String

Lösung

SELECT REPLACE(LTRIM(REPLACE(artikelnummer, '0', ' ')), ' ', '0') FROM dbo.cube1

Adobe Flex 3: Drag and Drop API

Aufgabenstellung

UI-Komponenten sollen per Drag and Drop verschoben werden können.

Ansatz

Dieser Artikel beschreibt die notwendigen Flex-APIs (DragManager) für die Implementierung einer Drag and Drop-Funktionalität am Beispiel der (siehe Nachfolgeartikel) eLearning-Anwendung für das V-Modell.

Lösung

1.) Definition der verschiebbaren Komponenten und der Behälter-Komponenten.

<!-- WIRD VERSCHOBEN -->
<mx:Button dragComplete="dragCompleteHandler(event);" 
label="System-Entwurf" id="btnSystementwurf"  />
<mx:Button dragComplete="dragCompleteHandler(event);" 
label="Software-Entwurf" id="btnSoftwareentwurf"  />
..

<!-- WIRD HINEINGESCHOBEN -->
<mx:HBox verticalAlign="middle" verticalScrollPolicy="off" 
horizontalScrollPolicy="off" id="dropField1" />
<mx:HBox verticalAlign="middle" verticalScrollPolicy="off" 
horizontalScrollPolicy="off" id="dropField2" />

2.) Registrierung der Eventlistener


<mx:Application creationComplete="{onCreationComplete()} ...

public function onCreationComplete():void
{
   // Registrierung des Buttons "Anforderungsanalyse" für das Verschieben in ein Feld
   this.btnAnforderungsnanalyse.addEventListener( MouseEvent.MOUSE_DOWN, beginDrag );

   // Registrierung des Buttons "AbnahmeEntwurf" für das Verschieben in ein Feld
   this.btnAbnahmeEntwurf.addEventListener( MouseEvent.MOUSE_DOWN, beginDrag );

...

   // Die DropListener werden an die UI-Komponten, bzw. die Komponeten, in die 
   // die Objekte geschoben werden können, angehängt
   this.dropField1.addEventListener( DragEvent.DRAG_ENTER, acceptDrop );
   this.dropField2.addEventListener( DragEvent.DRAG_ENTER, acceptDrop );
   ..
   this.dropField1.addEventListener( DragEvent.DRAG_DROP, handleDrop );
   this.dropField2.addEventListener( DragEvent.DRAG_DROP, handleDrop );
}
&#91;/actionscript3&#93;

3.) Implementierung der Logik - Hier: Überprüfung ob alles richtig verschoben ist
&#91;actionscript3&#93;
private function dragCompleteHandler(event:DragEvent):void {
     var draggedButton:Button = event.dragInitiator as Button;
     var dragInitCanvas:HBox = event.dragInitiator.parent as HBox;

     var stimmt1:Boolean = getButtons(dropField1).indexOf('btnAnforderungsnanalyse')>-1;
     var stimmt2:Boolean = getButtons(dropField2).indexOf('btnSystemarchitektur')>-1;
               	
     if(stimmt1&&stimmt2) 
     {
          Alert.show('Congratulations you did it!'); 
     }                	 
}  

4.) Welche Buttons sind in den Container? (Hier HBOX)

private function getButtons(box:HBox):String
{
var btnString:String=“;
var numChildren:Number = box.numChildren;

for (var i:int = 0; i < numChildren; i++) { if(box.getChildAt(i)["id"]) { btnString=box.getChildAt(i)["id"]; } } return btnString; } [/actionscript3] 5.) Management der Drag and Drop Funktionalität [actionscript3] public function beginDrag( mouseEvent:MouseEvent ):void { // the drag initiator is the object being dragged (target of the mouse event) var dragInitiator:IUIComponent = mouseEvent.currentTarget as IUIComponent; // the drag source contains data about what's being dragged var dragSource:DragSource = new DragSource(); // add some information to the drag source dragSource.addData( "name", dragInitiator.name ); dragSource.addData( "parent", dragInitiator.parent.name ); // ask the DragManger to begin the drag DragManager.doDrag( dragInitiator, dragSource, mouseEvent, null ); } public function handleDrop( dragEvent:DragEvent ):void { var dragInitiator:Button = Button( dragEvent.dragInitiator ); var dropTarget:HBox = dragEvent.currentTarget as HBox; HBox(dropTarget).addChild(dragInitiator); } public function acceptDrop( dragEvent:DragEvent ):void { var dropTarget:IUIComponent = dragEvent.currentTarget as IUIComponent; var dragSource:DragSource = dragEvent.dragSource; // accept the drop DragManager.acceptDragDrop( dropTarget ); // show feedback DragManager.showFeedback( DragManager.MOVE ); } [/actionscript3]

OLE DB Zugriff: C# auf MDB (Microsoft Access Datenbank) mit JET Treiber

Selektionsanweisung mit Parametern

public ArrayList getWeekPlan(string kapno, string woche)
{
   ArrayList weekPlan = new ArrayList();

   OleDbConnection conn = new OleDbConnection(
   "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=\\\\pfad1\\db.mdb");

   try
   {

      conn.Open();
      OleDbCommand comm = new OleDbCommand();
      comm.Connection = conn;
      comm.CommandText = "SELECT [Datum],[KapazitätNo] "+
      "FROM [qry_TagesAnsichtMengen] WHERE [KapazitätNo]=@kapno "+
      "AND [DINKW]=@woche";

      comm.Parameters.AddWithValue("kapno", kapno);
      comm.Parameters.AddWithValue("woche", woche);
      
      OleDbDataReader reader = comm.ExecuteReader();
      
       while (reader.Read())
       {
          WeekPlanVO vo = new WeekPlanVO();
          vo.datum = reader.GetValue(0).ToString();
          vo.menge = reader.GetValue(1).ToString();
          weekPlan.Add(vo);
        }
   }
   catch (Exception e)
   {
     WeekPlanVO vo = new WeekPlanVO();
     vo.datum = e.Message;
     vo.menge = e.Message;
     weekPlan.Add(vo);
     return weekPlan;
   }
   finally
   {
      conn.Close();
   }
  return weekPlan;
}

Manipulationsanweisung ohne Parameter

public string updateDetailDate(DateTime neuesDatum, DateTime altesDatum, 
string neueKW, string alteKW, string kapazitaet, string material, string beleg)
{
  OleDbConnection conn = new OleDbConnection(
  "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=\\\\pfad1\\db.mdb");

  
  try
  {
     conn.Open();
     OleDbCommand comm = new OleDbCommand();
     comm.Connection = conn;
     comm.CommandText = "UPDATE qry_Details_Akt SET [changed]=Now(), DinkW=" + neueKW + 
      ", WEWA_C='" + DateWrapper.GetServerDate(neuesDatum) + "', WEWA_C_OLD='" +
     DateWrapper.GetServerDate(altesDatum) + "' WHERE Beleg='" + beleg + 
     "'AND DinkW=" + alteKW + " AND Material='" + material + "' AND KapazitätNo=" + 
     kapazitaet;

     comm.ExecuteNonQuery();
  }
  catch (Exception e)
  {
      return e.Message+' '+e.StackTrace;
  }
  finally
  {
      conn.Close();
  }

  return "ok";
}

Flex 3: Bemalbares mx:Canvas mit FluorineFX-Messaging (Montagsmaler)

Aufgabenstellung

Unter Verwendung der FluorineFX Messaging-API soll eine Montagsmaler-Anwendung implementiert werden. Dies bedeutet dass ein User auf eine Leinwand zeichnet und die anderen Seitenbesucher in Echtzeit eine Aktualisierung auf dem Bildschirm erhalten. Dies kann auch als Grundlage für weitere Kollaborationsanwendungen genutzt werden, in denen man gemeinsam ein Dokument konstruieren möchte.

Ansatz

Nachdem die Zeichnenfunktionalität implementiert ist, werden die Bildpunkte beim loslassen der Maustaste (MOUSE_RELEASE_EVENT) an alle Clients übertragen. Die Clients reagieren bei einer einkommenden Menge an Bildpunkten und zeichnen sofort auf die Leinwand. Es wird immer die komplette Leinwand mit allen Bildpunkten beim Mouse-Release gesendet.

Durch das Publisher/Subscriber-Prinzip abonniert die Flex-Anwendung beim Start sofort die Datenquelle „painter„. Die Datenquelle erhält Bildpunkte und verteilt sie an alle Abonennten, wenn diese nach dem zeichnen die Maus gesehn lassen.

Vorraussetzungen

Die FluorineFX-Konfigurationsdatei wird angepasst, so das es eine neue Messaging Quelle „painter“ existiert.

Konfiguration des Backends

services-config.xml:

<?xml version="1.0" encoding="utf-8" ?> 
<services-config>
    <services>
        <service-include file-path="remoting-config.xml" />
        <service-include file-path="messaging-config.xml" />
    </services>
    
    <!-- Custom authentication -->
    <security>
    </security>
    
    <channels>
        <channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
           <endpoint uri="http://{server.name}:{server.port}/{context.root}/Gateway.aspx" 
             class="flex.messaging.endpoints.AMFEndpoint"/> 
            <properties>
            </properties>
        </channel-definition>

        <channel-definition id="my-rtmp" class="mx.messaging.channels.RTMPChannel">
            <endpoint uri="rtmp://{server.name}:2037" 
            class="flex.messaging.endpoints.RTMPEndpoint"/>
            <properties>
                <idle-timeout-minutes>20</idle-timeout-minutes>
            </properties>
        </channel-definition>

    </channels>
</services-config>

messaging-config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<service id="message-service" class="flex.messaging.services.MessageService" 
    messageTypes="flex.messaging.messages.AsyncMessage">

     <!-- DO NOT CHANGE <adapters> SECTION-->
    <adapters>
	<adapter-definition id="messagingAdapter" 
             class="FluorineFx.Messaging.Services.Messaging.MessagingAdapter" 
             default="true"/>
    </adapters>
    <destination id="chat">
	<adapter ref="messagingAdapter"/>
        <properties>
            <network>
                <session-timeout>0</session-timeout>
            </network>
        </properties>
        <channels>
            <channel ref="my-rtmp"/>
        </channels>
    </destination>
    <destination id="textchat">
	<adapter ref="messagingAdapter"/>
        <properties>
            <network>
                <session-timeout>0</session-timeout>
            </network>
        </properties>
        <channels>
            <channel ref="my-rtmp"/>
        </channels>
    </destination>
    <destination id="painter">
	<adapter ref="messagingAdapter"/>
        <properties>
            <network>
                <session-timeout>0</session-timeout>
            </network>
        </properties>
        <channels>
            <channel ref="my-rtmp"/>
        </channels>
    </destination>
    <destination id="opminboxrefresher">
	<adapter ref="messagingAdapter"/>
    	<properties>
	    <network>
            	<session-timeout>0</session-timeout>
            </network>
    	</properties>
    	<channels>
         	<channel ref="my-rtmp"/>
    	</channels>
    </destination> 
</service>

Konfiguration des Frontends

Bei den Frontend Konfigurationsdateien kann einfach die Datei services-config.xml und die Datei messaging-config.xml kopiert werden. Es können aber absolute Pfade anstelle der Platzhalter wie {server.name},{server.port},{context.root} genutzt werden. Hierdurch ist eine lokale Entwicklung der Flex-Anwendungen mit einem entfernten IIS Server möglich.

Lösung

PaintMessaging.mxml (Projektdatei)

<?xml version="1.0" encoding="utf-8"?>
<mx:Application creationComplete="{init()}" xmlns:mx="http://www.adobe.com/2006/mxml" 
	layout="absolute" xmlns:components="components.*">
	<mx:Script>
		<!&#91;CDATA&#91;
			import models.ModelLocator;
			import mx.controls.Alert;
			import mx.messaging.events.MessageFaultEvent;
			import mx.messaging.events.MessageEvent;
			import mx.messaging.messages.AsyncMessage;
			import mx.managers.CursorManager;
			&#91;Bindable&#93;
            &#91;Embed(source="../assets/stiftklein.png")&#93;
            private var stift:Class;
            
            public var cursorID:int;
            
            public function init():void 
            {
            	consumer.subscribe();
            }
            
            public function mouseOverHandler(event:MouseEvent):void
            {
            	
            }
            
            public function downEvent(event:MouseEvent):void 
            {
            	
            } 
            
            public function upEvent(event:MouseEvent):void
            {
            	
            }
            
	private function messageHandler(event:MessageEvent):void
    	{
    	    ModelLocator.getInstance().lines=event.message.body as Array;
    	    dc_main.invalidateDisplayList();
    	}
   
   	private function messagefaultHandler(event:MessageFaultEvent):void
   	{ 
   	   Alert.show(event.faultCode+' '+event.faultDetail+' '+event.faultString); 
   	}     		
            
	&#93;&#93;>
	</mx:Script>
	<mx:Consumer id="consumer" destination="painter" 
		message="messageHandler(event)" fault="messagefaultHandler(event)"/>
    <mx:Producer id="producer" destination="painter" 
    	fault="messagefaultHandler(event)"/>		

    <mx:Panel mouseOver="{ cursorID = CursorManager.setCursor(stift); }" 
    	mouseOut="{CursorManager.removeCursor(cursorID);}" 
    	layout="absolute" 
    	title="Montagsmaler by Björn Karpenstein" 
    	backgroundColor="#ffffff" 
    	borderThicknessBottom="10" left="20" 
    	right="20" top="20" bottom="20">
       <components:DrawableCanvas id="dc_main" backgroundColor="#ffff80" 
       	backgroundAlpha="0" width="100%" height="100%" y="0" x="0">
       </components:DrawableCanvas>
    </mx:Panel>
		
</mx:Application>

DrawableCanvas.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="300" 
       creationComplete="init()">
    
    <mx:Script>
        <!&#91;CDATA&#91;
            
            public var lineWidth:Number = 5;
            
            public var lineColour:uint = 1;
            
            public var lineAlpha:Number = 1;
            
            
            private var enabler:DrawingEnabler;
            
            private function init():void
            {
                enabler = new DrawingEnabler(this);
            }            
            
            protected override function updateDisplayList(unscaledWidth:Number,
                            unscaledHeight:Number):void
            {
                super.updateDisplayList(unscaledWidth, unscaledHeight);
            
                if( enabler != null ) enabler.drawLines(graphics, lineWidth, 
                lineColour, lineAlpha);
            }
        &#93;&#93;>
    </mx:Script>
</mx:Canvas>

DrawingEnabler.as

package components
{
import flash.display.Graphics;
import flash.events.MouseEvent;

import models.ModelLocator;

import mx.core.Application;
import mx.core.UIComponent;
import mx.messaging.messages.AsyncMessage;

public class DrawingEnabler
{
private var _target:UIComponent;

private var _curentLine:Array;

public function DrawingEnabler( target:UIComponent ):void
{
_target = target;
_target.addEventListener(MouseEvent.MOUSE_DOWN, downEvent);
_target.addEventListener(MouseEvent.MOUSE_UP, upEvent);
_target.addEventListener(MouseEvent.MOUSE_OUT, upEvent);
}

public function sendMessage(stream:Array):void
{
var message:AsyncMessage = new AsyncMessage();
message.body = stream;
Application.application.producer.send(message);
}

public function newLine():void
{
_curentLine = new Array();
ModelLocator.getInstance().lines.push( _curentLine );

if( ModelLocator.getInstance().lines.length > 10 )
ModelLocator.getInstance().lines.shift();
}

public function addPoint(xIN:int, yIN:int):void
{
_curentLine.push( { x:xIN, y:yIN } );
_target.invalidateDisplayList();
}

public function drawLines(graphics:Graphics,lw:Number,lc:uint,la:Number):void
{
graphics.clear();
graphics.lineStyle(lw,lc,la);

for( var j:int = 0; j

Flex 3 und Google Maps API

Aufgabenstellung

In eine Flex-Anwendung soll Google Maps integriert werden.

Ansatz

1.) Aufruf der Seite http://code.google.com/intl/de/apis/maps/documentation/flash/
2.) Runterladen der Flash-Bibliothek (SWC-Datei) und einfügen in das LIBS-Verzeichnis der Flex-Anwendung
3.) Anfordern des Schlüssels unter „Wie beginne ich…“ und eintragen in den Code unten.

Lösung

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
	<!&#91;CDATA&#91;
		import com.google.maps.overlays.Marker;
		import com.google.maps.controls.ZoomControl;
		import com.google.maps.geom.Attitude;
		import mx.controls.Alert;
		import com.google.maps.*;
		import com.google.maps.geom.*;
		import com.google.maps.services.GeocodingEvent;
		import com.google.maps.services.ClientGeocoder;
		import com.google.maps.controls.NavigationControl;
		import com.google.maps.controls.MapTypeControl;
		import com.google.maps.MapEvent;
		
		public function onMapReady(event:MapEvent):void
		{
			// Die Bedienelemente der Karte hinzufügen
			map.addControl(new MapTypeControl());
			map.addControl(new NavigationControl());
			this.geocodeLocation('Fulda, Am Rinnweg 15');
		}
		
		public function onMapPreinitialize(event:MapEvent):void
		{
			var myMapOptions:MapOptions = new MapOptions();
			myMapOptions.viewMode = View.VIEWMODE_2D;
			myMapOptions.mapType=MapType.NORMAL_MAP_TYPE;
			//myMapOptions.zoom=0;
			map.setInitOptions(myMapOptions);
		}
		
		private function geocodeLocation(location:String=''):void
		{
			var geocoder:ClientGeocoder = new ClientGeocoder();
			geocoder.addEventListener(GeocodingEvent.GEOCODING_SUCCESS,
			geoCodeSuccess);
			geocoder.addEventListener(GeocodingEvent.GEOCODING_FAILURE, 
			geoCodeFailure);

			if(location!='')
			{
				geocoder.geocode(location);
			}
			else
			{
				geocoder.geocode(search.text);
			}
		}
		
		private function geoCodeSuccess(event:GeocodingEvent):void
		{
			var placemarks:Array = event.response.placemarks;
			map.flyTo(placemarks&#91;0&#93;.point, 18, new Attitude(35,60,35), 
			3);
			var marker:Marker = new Marker(placemarks&#91;0&#93;.point); 
			map.addOverlay(marker); 
		}
		
		private function geoCodeFailure(event:GeocodingEvent):void
		{
			Alert.show('Also wissense, das find ich einfach ned....',
                                       'Ähm...');			
		}		
	&#93;&#93;>
</mx:Script>
	<mx:TitleWindow layout="vertical" width="100%" height="100%" 
              title="Finde versteckte Schätze... 
             (c) die 1st-level-caches Schludi&amp;Mephi ">
		<maps:Map3D xmlns:maps="com.google.maps.*" 
			  id="map" 
			  mapevent_mapready="onMapReady(event)" 
			  mapevent_mappreinitialize="onMapPreinitialize(event)"
			  width="100%" 
			  height="100%"
    		  key="HIER KOMMT DER BEANTRAGTE GOOGLE KEY REIN"/>
    	<mx:HBox horizontalAlign="center" width="100%" height="30">
			<mx:Label x="70" y="524" text="Da will ich hin:" 
                                        width="120" fontWeight="bold"/>
			<mx:Button x="421" y="520" label="Suchen ..." 
                                        click="{geocodeLocation()}"/>
			<mx:TextInput id="search" x="167" y="520" 
                                       width="246"/>
    	</mx:HBox>
	</mx:TitleWindow>
</mx:Application>

Beispiel

http://baugebiete.fulda.de

FluorineFX: Standard Authentifizierung über die Session

Aufgabenstellung

Im Internet sollen sich Benutzer an einer Anmeldemaske einer Flex-Anwendung anmelden. Die Berechtigungen sollen anhand des Benutzernamens festgelegt werden.

Ansatz

1.) FLEX: Erstellen der Anmeldemaske mit User/Passwort
2.) C#: Überprüfung ob die User/Passwort-Kombination in der Datenbank vorhanden ist
3.) C#: Falls JA: Benutzer in die sessionvariable USERNAME schreiben / Falls NEIN: Tue nichts
4.) C#: Überprüfung der Backend-Services: Ist USERNAME leer?
NEIN: Darf der User die Daten aufrufen?? (Dem Benutzer kann eine ROLLE zugewiesen sein, siehe Artikel „FluorineFX: Windows Authentifierung… Single Sign On“, und anhand der Rolle kann ermittelt werden ob sie berechtigt ist die Daten abzurufen).
JA: Keine Daten ausliefern!!!
5.) FLEX: Falls user authentifziert: Maskenaufbau in der Flexanwendung entsprechend Rolle

Lösung

Hier die wichtigsten Auszüge aus meiner Lösung:

FLEX:

...
<mx:Script>
public function getAuthenticationHandler(event:ResultEvent):void
{
   if( (event.result as Boolean) )
   {
     // Schalte ViewStack um (keine Loginmaske mehr)
     loginStack.selectedChild=tarzanScreen;

     // Speichere Username in Modellocator (evtl. auch Rolle holen)
     ModelLocator.getInstance().myUser=txtUsername.text;
   }
   else
   {
      Alert.show('Wrong username or password!');
    }						
}
</mx:Script>
...
<mx:TextInput id="txtUsername" />
<mx:TextInput id="txtPasswort" displayAsPassword="true"/>
...
<mx:RemoteObject id="authenticationService" destination="GenericDestination"  
                                          source="TarzanServices.AuthenticationService" 
                                          showBusyCursor="true" 
                                          fault="faultHandler(event)" >
    <mx:method name="getAuthentication" result="getAuthenticationHandler(event)"/>
</mx:RemoteObject>

C#: Benutzername ermitteln: Falls „none“ einfach nix in Maske/Service machen:

using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Data.SqlClient;
using System.Web;
using FluorineFx;
using System.Security.Principal;
...
public string getSessionUser()
{
    if (FluorineFx.Context.FluorineContext.Current.Session["username"]==null) 
    return "none";

    return FluorineFx.Context.FluorineContext.Current.Session["username"].ToString();
}

C#: Überprüfe ob User/Kennwort-Kombination in der Datenbank vorhanden ist, falls JA, schreibe USERNAME in Sesseion und liefere TRUE zurück, damit Flex weiß das es von der Login-Maske weg darf.. (REAKTION IN FLEX).

public bool getAuthentication(string username, string password)
{
   SqlConnection conn = new SqlConnection(MyConfigurationManager.msSqlServerString);

   try
   {
      conn.Open();
      SqlCommand comm = new SqlCommand();
      comm.Connection = conn;
      comm.CommandText = "SELECT * FROM [users] WHERE [username]=@username "+
                                     "AND [password]=@passwort";
      comm.Parameters.AddWithValue("username", username);
      comm.Parameters.AddWithValue("passwort", password);

      int i = 0;
      SqlDataReader reader = comm.ExecuteReader();

       while (reader.Read())
       {
              i++;
       }

       if (i > 0)
       {
           // Schreibe USER in die Datenbank
           FluorineFx.Context.FluorineContext.
           Current.Session["username"] = username;
       }

       return i > 0;
   }
   catch (Exception e)
   {
        return false;
   }

   return false;
}

by Björn Karpenstein