Web- und Software Development

Neuerdings im Web (April 2012)

Written By: Mario Priebe - Mai• 02•12

Einen schönen Round-Up bringt uns NETTUTS über derzeitige Features und neuen nützlichen Javascript/jQuery Libraries für die Webentwicklung.

Gut finde ich jQuery Scroll Path

"jQuery Scroll Path is a plugin that lets you define your own custom scroll path. What this means exactly is best understood by checking out the demo. The plugin uses canvas flavored syntax for drawing paths, using the methods moveTo, lineTo and arc. To help with getting the path right, a canvas overlay with the path can be enabled when initializing the plugin."

und keymaster.js (analog jwerty).

"Keymaster is a simple (100 LoC or so) micro-library for defining and dispatching keyboard shortcuts. It has no dependencies."

Was ist dir im Monat April aufgefallen, was man unbedingt einmal ausprobieren sollte?

Sollte man jeden Monat aus den Bereichen Web und .NET eine solche Auflistung von Neuerungen machen? Was denkt Ihr?

Interaction Event-Trigger als Style auslagern

Written By: Mario Priebe - Apr• 23•12

In einem Caliburn.Micro Projekt setze ich den EventTrigger ein, um meine Commands an einem ViewModel zu binden.

Nun möchte ich gerne immer den selben EventTrigger an mehreren Stellen einsetzen und verhindern, dass der Code an “tausend” Stellen redundant eingesetzt wird. Aus diesem Grund, soll diese Interaktion als Style zu Verfügung gestellt werden.

Der folgende Code zeigt, wie der redundante Code aussehen würde:

<r:RibbonButton Label="{x:Static Helper:ViewModels.AlleKontaktGruppen}" LargeImageSource="/OCC.Resources;component/Images/32/kdm/Groups-Meeting-Dark-icon.png"> <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <cal:ActionMessage MethodName="Navigate"> <cal:Parameter Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type r:RibbonButton}, AncestorLevel=1},Path=Label}" /> </cal:ActionMessage> </i:EventTrigger> </i:Interaction.Triggers> </r:RibbonButton>

Wie gehen wir also vor? Wir leiten uns dazu eine Klasse namens “Triggers” von einer typisierten Liste des Typen System.Windows.Interactivity.TriggerBase ab und registrieren diese als DepedencyProperty:

using System.Collections.Generic; using System.Windows; using System.Windows.Interactivity; namespace OCC.WPF.Helper { public class Triggers : List<System.Windows.Interactivity.TriggerBase> { } public static class OCCInteraction { public static Triggers GetTriggers(DependencyObject obj) { return (Triggers)obj.GetValue(TriggersProperty); } public static void SetTriggers(DependencyObject obj, Triggers value) { obj.SetValue(TriggersProperty, value); } public static readonly DependencyProperty TriggersProperty = DependencyProperty.RegisterAttached("Triggers", typeof(Triggers), typeof(OCCInteraction), new UIPropertyMetadata(null, OnPropertyTriggersChanged)); private static void OnPropertyTriggersChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var triggers = Interaction.GetTriggers(d); foreach (var trigger in e.NewValue as Triggers) triggers.Add(trigger); } } }

Und in einem Ressourcenwörterbuch “Style.xaml” bauen wir uns den entsprechenden Trigger dann in zusammen:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Helper="clr-namespace:OCC.WPF.Helper" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:cal="http://www.caliburnproject.org" xmlns:Ribbon="clr-namespace:Microsoft.Windows.Controls.Ribbon;assembly=RibbonControlsLibrary"> <Helper:Triggers x:Key="ribbonBtnClickTrigger" x:Shared="False"> <i:EventTrigger EventName="Click"> <cal:ActionMessage MethodName="Navigate"> <cal:Parameter Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Ribbon:RibbonButton}, AncestorLevel=1},Path=Label}" /> </cal:ActionMessage> </i:EventTrigger> </Helper:Triggers> <Style x:Key="ribbonBtnClickBehavior" TargetType="FrameworkElement"> <Setter Property="Helper:OCCInteraction.Triggers" Value="{StaticResource ribbonBtnClickTrigger}"/> </Style> </ResourceDictionary>

Anschließend können wir unser Element an das Style-Attribute binden:

<r:RibbonButton Label="{x:Static Helper:ViewModelNames.AlleKontaktGruppen}" LargeImageSource="/OCC.Resources;component/Images/32/kdm/Groups-Meeting-Dark-icon.png" Style="{StaticResource ribbonBtnClickBehavior}"/>

Sieht doch gleich viel besser aus.

Viel Spaß beim entwickeln : )

Outlook als GTD Applikation

Written By: Mario Priebe - Apr• 18•12

GTD steht für Getting Things Done und beschreibt Methodiken, seinen täglichen Aufgaben produktiv und effizient zu erledigen. Lesenswerte Artikel zum Thema GTD stehen am Ende des Tutorials.

Zieldefinition

Ziel ist es, im Outlook ein Dashboard bereit zu stellen, welches einem alle Aufgaben, den Posteingang, den Kalender, Notizen und die Kontakte anzeigt. Das Besondere dabei ist, das die Aufgaben in (agiler) Form eines Scrum/Kanban Boards angezeigt werden.

image

image

image

image

image

Features

  • Innerhalb der Aufgabenlisten die man hier im Screenshot sieht, kann man via Drag & Drop die Aufgabe von einer "Pane" in eine andere "Pane" verschieben. 
  • Neue Mails werden automatisch als neue Aufgabe in das Backlog kopiert.

    Taskordner anlegen.

    Zu Beginn müssen wir unserer "Panes" anlegen, das machen wir, indem unter Aufgaben die entsprechende Ordner erstellt werden. Dazu geht man unter Aufgaben mit der rechten Maustaste auf Vorgangsliste und wählt hier "Neuer Ordner". Dies macht man für alle Ordner die man benötigt. In meinem Fall sind das die folgende drei: backlog, in progress und done.

     2012-04-17_14h50_19

  • Dashboard erstellen

    Nachdem wir nun die Aufgaben-Ordner erstellt haben, sollen diese im Dashboard angezeigt werden. Dazu müssen wir vorerst das Dashboard erstellen:
    Hier legen wir uns eine *.html-Datei an einem beliebigen (sicheren) Ort ab. Ich erstelle dazu in meinem Entwicklungsordner einen Ordner namens "#OutlookToday ". Das Pfad müsste nun so aussehen:  "D:\Dev\#OutlookToday\OutlookToday.html".

    In dieser Datei, designen wir nun unser DashBoard.
    Die Elemente die wir im Dashboard anzeigen wollen, werden mittels Object-Element eingebunden, hier kann man über den Parameter "Folder" das  jeweilige Outlook-Element anzeigen.

    Für den Posteingang sieht das wie folgt aus:

    2012-04-17_14h17_19

    Man kann jeden beliebigen Ordner anhand des Namens angeben. z.B. auch den Ordner "Gesendete Elemente"

    2012-04-17_14h18_40

    Nun baut man sich mit ein paar Html/jQuery Kenntnissen ein Design zusammen und bindet die entsprechenden Object-elemente an den Stellen ein, wo man diese benötigt. Mein Beispiel sieht wie folgt aus:

    <html> <head> <title>Dashboard</title> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.js"></script> <style type="text/css"> a:active, a:focus { outline: none; ie-dummy: expression(this.hideFocus=true); } h1{ font: bold italic 2em/1em "Times New Roman", "MS Serif", "New York", serif; margin: 5; padding: 0; color: #cc3300; border-bottom: dotted #cc3300 thin; } .thirds{ width: 33%; float:left; } #tabbed_box_1 { margin: 0px auto 0px auto; width:100%; } .tabbed_area { border:1px solid #494e52; background-color:#636d76; padding:8px; } ul.tabs { margin:0px; padding:0px; margin-top:5px; margin-bottom:6px; } ul.tabs li { list-style:none; display:inline; } ul.tabs li a { background-color:#464c54; color:#ffebb5; padding:8px 14px 8px 14px; text-decoration:none; font-size:9px; font-family:Verdana, Arial, Helvetica, sans-serif; font-weight:bold; text-transform:uppercase; border:1px solid #464c54; background-image:url(images/tab_off.jpg); background-repeat:repeat-x; background-position:bottom; } ul.tabs li a:hover { background-color:#ffffff; color:#282e32; border:1px solid #464c54; border-bottom: 1px solid #ffffff; background-image:url(images/tab_on.jpg); background-repeat:repeat-x; background-position:top; } ul.tabs li a.active { background-color:#ffffff; color:#282e32; border:1px solid #464c54; border-bottom: 1px solid #ffffff; background-image:url(images/tab_on.jpg); background-repeat:repeat-x; background-position:top; } .content { background-color:#ffffff; height: 400px; border:1px solid #464c54; font-family:Arial, Helvetica, sans-serif; background-image:url(images/content_bottom.jpg); background-repeat:repeat-x; background-position:bottom; padding: 20px 0px 40px 0px; } #content_2, #content_3, #content_4, #content_5 { display:none; } .content ul { margin:0px; } .content ul li { list-style:none; border-bottom:1px solid #d6dde0; padding-top:15px; padding-bottom:15px; font-size:13px; } .content ul li:last-child { border-bottom:none; } .content ul li a { text-decoration:none; color:#3e4346; } .content ul li a small { color:#8b959c; font-size:9px; text-transform:uppercase; font-family:Verdana, Arial, Helvetica, sans-serif; position:relative; left:4px; top:0px; } .content ul li a:hover { color:#a59c83; } .content ul li a:hover small { color:#baae8e; } </style> </head> <body> <!-- TabControl http://d2o0t5hpnwv4c1.cloudfront.net/001_Tabbed/site/jQuery.html# --> <div id="tabbed_box_1" class="tabbed_box"> <div class="tabbed_area"> <ul class="tabs"> <li><a href="#" title="content_1" class="tab active">Board</a></li> <li><a href="#" title="content_2" class="tab">Inbox</a></li> <li><a href="#" title="content_3" class="tab">Appointments</a></li> <li><a href="#" title="content_4" class="tab">Notes</a></li> <li><a href="#" title="content_5" class="tab">Contacts</a></li> </ul> <div id="content_1" class="content"> <div class="thirds"> <h1>BACKLOG</h1> <OBJECT classid=CLSID:0006F063-0000-0000-C000-000000000046 id=ViewCtlFolder width=100% height=500> <param name="Folder" value="Aufgaben\backlog"> <param name="Namespace" value="MAPI"> <param name="Restriction" value=""><param name="DeferUpdate" value="0"> </OBJECT> </div> <div class="thirds"> <h1>PROGRESS</h1> <OBJECT classid=CLSID:0006F063-0000-0000-C000-000000000046 id=ViewCtlFolder width=100% height=500> <param name="Folder" value="Aufgaben\in progress"> <param name="Namespace" value="MAPI"> <param name="Restriction" value><param name="DeferUpdate" value="0"> </OBJECT> </div> <div class="thirds"> <h1>DONE</h1> <OBJECT classid=CLSID:0006F063-0000-0000-C000-000000000046 id=ViewCtlFolder width=100% height=500> <param name="Folder" value="Aufgaben\done"> <param name="Namespace" value="MAPI"> <param name="Restriction" value><param name="DeferUpdate" value="0"> </OBJECT> </div> </div> <div id="content_2" class="content"> <h1>Inbox</h1> <OBJECT classid=CLSID:0006F063-0000-0000-C000-000000000046 id=ViewCtlFolder width=100% height=500> <param name="Folder" value="Posteingang"> <param name="Namespace" value="MAPI"> <param name="Restriction" value> <param name="DeferUpdate" value="0"> </OBJECT> </div> <div id="content_3" class="content"> <h1>Appointments</h1> <OBJECT classid=CLSID:0006F063-0000-0000-C000-000000000046 id=ViewCtlFolder width=100% height=500> <param name="Folder" value="Kalender"> <param name="Namespace" value="MAPI"> <param name="Restriction" value> <param name="DeferUpdate" value="0"> </OBJECT> </div> <div id="content_4" class="content"> <h1>Notes</h1> <OBJECT classid=CLSID:0006F063-0000-0000-C000-000000000046 id=ViewCtlFolder width=100% height=500> <param name="Folder" value="Notes"> <param name="Namespace" value="MAPI"> <param name="Restriction" value> <param name="DeferUpdate" value="0"> </OBJECT> </div> <div id="content_5" class="content"> <h1>Contacts</h1> <OBJECT classid=CLSID:0006F063-0000-0000-C000-000000000046 id=ViewCtlFolder width=100% height=500> <param name="Folder" value="Contacts"> <param name="Namespace" value="MAPI"> <param name="Restriction" value> <param name="DeferUpdate" value="0"> </OBJECT> </div> </div> </div> <script type="text/javascript"> $(document).ready(function(){ // When a link is clicked $("a.tab").click(function () { $(".active").removeClass("active"); $(this).addClass("active"); $(".content").hide(); // slide this content up var content_show = $(this).attr("title"); $("#"+content_show).show(); }); }); </script> </body> </html>

    In Outlook einbinden.

    Um die OutlookToday.html in Outlook einzubinden, geht man mittels Rechtsklick auf den Posteingang und wählt hier unter Eigenschaften den Reiter "Homepage" 
    2012-04-17_14h50_19 (1)

    und trägt hier den Pfad ein: D:\Dev\#OutlookToday\OutlookToday.html

    image 

    Neue Mails als Aufgabe in Backlog kopieren

    Nun kommen wir zum zweiten Feature. Wenn eine neue Mail eintrifft, wollen wir einer Regel erstellen, die die Mail als Kopie in den Aufgaben-Ordner "Backlog" kopiert.


    Dazu benötigen wir ein VBAScript, welches man im Visual Basic Editor erstellen kann. Diesen ruft man mit der Tastenkombination ALT F11 auf. Hier fügt man ein neues Modul ein


     2012-04-17_14h37_01

    In diesem Modul schreibt man folgenden Code


    2012-04-17_14h38_06

    (Das Copy() im Code ist ein Workaround, da sonst die Mail nicht mehr im Posteingang gelistet wird)

    Sub RulesScript(olItem As MailItem) Set copyitem = olItem.Copy Set myTasks = Application.GetNamespace("MAPI").GetDefaultFolder(olFolderTasks) Set backlog = myTasks.Folders("backlog") olItem.Move backlog End Sub

    Nach dem Speichern und Schließen des VBA Editors, müssen wir eine Regel erstellen, die diesen Code ausführt.

    Dazu gehen wir im Outlook unter Extras auf Regeln und Benachrichtigungen.

    2012-04-17_14h34_51

    Hier erstellen wir folgende neue Regel.

  • nur auf diesen Computer
  • die meinen Namen im Feld "An" oder "CC" enthält
  • Weiter
  • ein Script ausführen
  • Im unteren Bereich das RulesScript wählen
  • weiter
  • weiter
  • Der Regel einen Namen vergeben
  • Regel aktivieren 
  • Fertig stellen

    Die Regel empfehle ich natürlich entsprechend anzupassen, nicht jede Mail macht Sinn in das Backlog  geschoben zu werden.

    Nun sollte, wenn alles glatt gelaufen ist, die Regel auch aktiv sein. 

    In der  Board-Ansicht ist man in der Lage, die Aufgaben zwischen den einzelnen Aufgaben-Ordnern ("Panes") mit der Maus zu verschieben, um sich so den derzeitigen Aufgaben-Zustand zu visualisieren.

    So, das war es auch schon. Ich hoffe Ihr findet Verwendung mit dem Outlook-Dashboard und habt so etwas mehr Organisation in Eurer täglichen Arbeit.

    Wenn irgendwas nicht hinhaut, einfach einen Kommentar hinterlassen.

    Links:

  • Produktiver Arbeiten – Alle Tools und Techniken
  • GTD in einer Nußschale
  • GTD auf Google+
  • Unable to write * ‘obj\Release\

    Written By: Mario Priebe - Apr• 11•12

    Bekommt man diese, oder eine ähnliche Fehlermeldung “Unable to write * ‘obj\Release\”, löscht man am besten einmal den obj Ordner und prüft ob dieser eventuell im TFS mit eingecheckt wurde, was verhindert, das der Schreibschutz effektiv aufgehoben wird.

    Also dann einfach auf dem TFS löschen, einchecken und Projekt bauen.

     

    Viel Spaß beim entwickeln : )