.
Anmeldung | Registrieren | Hilfe

.NET-Blogs Archiv März 2010

Seit heute bei der VSTO Taskforce vertreten

31.03.2010 23:10:00 | Jan Christian Selke

Meine Blogeinträge mit dem Schwerpunkt auf Office Themen werden seit heute auf der Webseite der VSTO Taskforce gelistet.

Meinen herzlichen Dank an dieser Stelle an Lars Keller für das an meiner Arbeit entgegengebrachte Interesse. Ich freue mich darauf, mit meinen Posts einen Beitrag leisten zu können.

dotnet Cologne 2010: Die ersten Vorträge und Sprecher stehen fest

31.03.2010 21:01:37 | Albert Weinert

Es gabe viele Diskussionen, haben um Themen gekämpft, festgestellt dass 18 Slots viel zu wenig sind. Haben alles unternommen um 24 Slots hinzubekommen, wir haben es geschafft und jetzt haben wir das Ergebnis dieser anstrengungen Online gestellt.

Die Liste der Vorträge und Sprecher findet ab sofort sich unter:

http://dotnet-cologne.de

Noch ist diese Liste nicht vollständig oder zeitlich geordnet, geplant ist eine 2. Runde. Wir haben aktuell noch 4 Slots frei für Themen die uns noch fehlen. Auch kann es sein dass sich der eine oder andere Vortrag noch ändert wenn wir denken dass dies die dotnet Cologne 2010 bereichert.

Durch den zusätzlichen Raum haben wir natürlich auch mehr Platz für Teilnehmer und konnten das Teilnehmerlimit auf 300 Personen anheben. Davon sind jedoch nur noch 47 frei! Also es ist also ein wenig Eile geboten bei der Anmeldung, sofern man sicher dabei sein möchte.

Windows 7 .NET User Group Tour im Frühjahr

31.03.2010 15:27:19 | Peter Kirchner

EN-w7_rgb_L Es ist mir eine besondere Freude anzukündigen, dass wir im Frühjahr eine Tour durch zahlreiche .NET User Groups in Deutschland zum Thema Windows 7 machen werden. Da ich selbst Sprecher auf diesen Veranstaltungen sein werde, freue ich mich darüber natürlich umso mehr.

In den folgenden User Groups darf ich Ihnen die Entwicklung mit .NET für Windows 7 näher bringen. Ich würde mich freuen, Sie dort begrüßen zu dürfen!

Braunschweig Dienstag, 20. April 2010
Ulm Mittwoch, 21. April 2010
Paderborn Montag, 3. Mai 2010
Köln Dienstag, 4. Mai 2010
Bremen Mittwoch, 5. Mai 2010
Berlin Donnerstag, 6. Mai 2010
München Dienstag, 18. Mai 2010
Augsburg Donnerstag, 20. Mai 2010
Stuttgart Mittwoch, 26. Mai 2010

Beschreibung der Themen

Der Hauptfokus bei Windows 7 wurde auf die weitere Verbesserung der Sicherheit, Zuverlässigkeit und Performance des Betriebssystems gelegt - und auf die größtmögliche Kompatibilität zu Windows Vista , damit bereits bestehende Anwendungen auch in Zukunft laufen. Für Entwickler bietet Windows 7 viele neue Schnittstellen, um Anwendungen mit umfassenderen Funktionen zu versehen, die dem Endbenutzer eine neue Erfahrung im Umgang mit Software ermöglichen.

In diesem Vortrag erfahren Sie, wie Sie sich nahtlos ins Betriebssystem integrieren, indem Sie z.B. die neue Taskbar nutzen, die Preview-Ansichten steuern, Status-Informationen ausgegeben oder die Sprunglisten nach Ihren Wünschen anpassen. Wir demonstrieren u.a. die Verwendung der in Windows 7 eingeführten Bibliotheken, um den Zugriff auf Dokumente Ihrer Anwendung zu vereinfachen und auch die neuen Multitouch-Funktionen, die eine neue Interaktion zwischen Mensch und System ermöglichen.

Zusätzlich erfahren Sie, welche Punkte zu beachten sind, um die Kompatibilität Ihrer Anwendung mit Windows 7 sicherzustellen, wenn diese bereits auf Windows XP oder Windows Vista laufen.

Updates

Auf den Veranstaltungen werde ich jeweils eine Version von Windows 7 Ultimate (NFR) verlosen. Ebenso ist geplant, noch Sponsoren ins Boot zu holen, damit wir auch noch ein paar weitere schöne Preise verlosen können.

Und fürs leibliche Wohl werden wir ebenfalls sorgen. :-)

Windows Phone 7 Series: Netflix

31.03.2010 08:51:00 | Oliver Scheer

In den USA ist der Begriff “netflixen” so gängig wie bei uns das Wort “googlen”. Es bedeutet soviel wie das Ausleihen von Videos.

Netflix ist seit Jahren regelmäßiger Gast auf der MIX und stellt dort ihre aktuellen Lösungen vor, die inzwischen vollständig auf .NET, Silverlight und jetzt auch Windows Phone 7 basieren.

Meine Kollegin Laura Foy stellt in diesem Video auf Channel 9, die aktuelle Lösung von Netflix vor, so wie sie auf der Mix gezeigt wurde. Sehr beeindruckend, und meiner Meinung nach der absolut erste gute Video-Ausleih-Client für mobile Geräte.

Mehr Informationen

Bing die Datenkrake, Urlaub und Neuigkeiten

31.03.2010 07:59:53 | Kay Giza

Die letzten zwei Wochen war ich tatsächlich im Urlaub (ich weiß - Urlaub ist zwar überbewertet - war trotzdem nett ;-)). Zwei Wochen Sonne, blauer Himmel, Entspannung = einfach toll. Was waren die Learnings der letzten zwei Wochen? Ohne E-Mail und Internet geht's auch! Spanischer Wein ist echt lecker, das Essen spitze! Entspannung tut gut! Meine E-Mail Outlook-Regeln haben bestens funktioniert! :-) Outlook 2010 EMail-Infos helfen, dass man nach zwei Wochen keine E-Mails bekommen hat, die unnötig wären - na gut - fast ;-) Es gibt jetzt eine Menge Infos, E-Mails und Hinweise hier im Blog nachzuarbeiten. Es gibt nie eine gute Zeit in den Urlaub zu gehen, es ist eine Menge passiert. Daher mal einfach ein paar Dinge, Fakten und Interessantes, einfach unsortiert. Bing - die Datenkranke: Ich weiß, das ist wieder... [... lesen Sie den vollständigen Artikel auf Giza-Blog.de...]

This post is powered by www.Giza-Blog.de | Giza-Blog.de: RSS Feed
Visit:  MSDN Online | Follow MSDN Online on Twitter | Follow Kay Giza on Twitter
Daily News on MSDN:  MSDN Aktuell
© Copyright 2006-2010 Kay Giza. All rights reserved. Legal
Subscribe

Windows Photo Gallery Gelbstich im Hintergrund bei diversen TFT Monitoren

30.03.2010 18:59:12 | Peter Bucher

Wer im Hintergrund von Windows Photo Gallery (Foto Vorschau von Windows) einen Gelbstich im Hintergrund hat, kann dies durch ein anderes Farbprofil ausbessern.

Speziell Samsung Monitore scheinen dafür anfällig zu sein. Bei mir hat die erste Lösung geklappt:

Erster Workaround:

The first workaround is by removing any existing ICC or WCS color profiles that are been associated with all display devices or monitors. Else, you can also try to change the default color profile for your system’s monitor to sRGB IEC61966-2.1, simply by clicking on Add, and then select sRGB IEC61966-2.1 from the list of profiles installed on system. After adding, click Set as Default Profile button. Exit from all dialogs and reboot your computer, and the color problem on Windows Photo Gallery is fixed.

Zweiter Workaround:

If your system doesn’t have sRGB IEC61966-2.1 profile under the ICC Profiles, you can download the color profile from Adobe. Unpack the zip file, the right click on each of the .icc files in the RGB Profiles and CMYK Profiles folders (or simply just the one you need to use) and click “Install Profile” on context menu to install the color profile to system.

Quelle: mydigitallife.info

Microsoft Research Project Gustav

30.03.2010 15:47:00 | Oliver Scheer

Vor der zweiten Keynote auf der MIX10 stand ein Kollege auf der Bühne und hat Project Gustav live auf der Bühne verwendet um sehr realistische Zeichnungen zu erstellen.

Typische Zeichenprogramme haben den Nachteil, das sie keinen echten Pinsel und dessen natürlichen Eigenschaften nachahmen können. Das Project Gustav von Microsoft Research ist ein Prototyp für realistisches Zeichnen am Computer. Es kann mit mehreren Eingaben gleichzeitig umgehen (Multitouch mit mehr als vier gleichzeitigen Berührungen des Bildschirms). Darüber hinaus werden modernste Modelling- und Pinselsimulations-Algorithmen angewendet, die selbst das Überzeichnen von Farbe realistisch darstellen können und anschließend auch noch ein Verwischen erlauben.

image

Mehr Informationen

msdn tv Spezial - Interview mit Jean Paoli

30.03.2010 13:56:35 | Jan Schenk

Get Microsoft Silverlight

In diesem Interview hat msdn tv die Chance bekommen, mit Jean Paoli, Co-Creator von XML und mittlerweile Chef-Interop-Stratege bei Microsoft, zu sprechen.
Interoperabiltät ist einer der Schlüssel für erfolgreiche Geschäftsideen im Internet und im besten Fall unsichtbar. Was aber nicht bedeutet, dass Interop auch immer unproblematisch ist. Entwickler haben oft einen schweren Stand, wenn es darum geht, mehrere Technologien zu verheiraten. Warum das gerade bei Cloud Computing wichtig ist, und wie die Windows Azure Plattform mit der Interop-Strategie im Blick gestaltet wurde, erklärt Jean Paoli, der beim Entwurf der Plattform massgeblich beteiligt war.


msdn tv took the chance to interview Jean Paoli, co-creator of XML and chief interoperability strategist at Microsoft.
Interoperability is one of the keys to success in internet business. Assuming an ideal case, interop is invisible. Which doesn't mean that it is always easy to implement. Developers often face certain difficulties in combining different technologies, which is, regarding cloud computing, more crucial than ever to building applications. Jean Paoli was one of the key persons, when it came to designing the Windows Azure Platform, which was then, by design, built to be interoperable from its first day. In this interview, he tells us how and why.

msdn tv ist ein neues Video-Nachrichtenformat, und hat seinen Ursprung auf MSDN Online (http://www.msdn-online.de/msdntv/). Alle zwei Wochen präsentiert Ihnen Jan Schenk, Developer Evangelist mit Hut, die wichtigsten Neuigkeiten für Entwickler, Hintergrundberichte und Interviews zu aktuellen Technologien sowie Highlights von Messen und Konferenzen. Das ganze kompakt, in ca. 15 Minuten erfrischend jung verpackt , und sowohl als Download für Ihren Rechner oder im Online-Player per Streaming verfügbar.

msdn tv is a German-speaking new and innovative video news series, and has originally been featured exclusively on the German MSDN Online Platform (http://www.msdn-online.de/msdntv/). Hatted Developer Evangelist Jan Schenk biweekly presents latest news for developers, background-stories and interviews concerning current and upcoming technologies, as well as video-highlights from fairs and conferences. Packed into 15 minutes, these news videos feature a fresh informative style, and are downloadable as well as available as online streaming video.

   _MG_0408

Bing Maps integriert WorldWide Telescope

30.03.2010 10:03:00 | Oliver Scheer

Vor zwei Jahren wurde das WorldWide Telescope Projekt von Microsoft Research vorgestellt. Vor wenigen Tagen, wurde diese nun in Bing Maps integriert. Damit hat man nun die Möglichkeit von jedem beliebigen Ort der Welt von der Street Side View (die noch nicht überall erhältlich ist), in das Weltall zu blicken und das Sternensystem zu erkunden.

Es ist sogar möglich dies zu verschiedenen Tagen und Uhrzeiten zu tun, damit lassen sich z.B. der Sternenhimmel an seinem Geburtstag simulieren.

image

Video

Link: www.bing.com/maps/explore –> Map Apps

ASP.NET Webforms Anwendungen und Ajax (Teil 7) - AjaxPro

29.03.2010 21:12:04 | Andre Kraemer

In Teil 5 meiner ASP.NET Webforms und Ajax Serie wies René Drescher-Hackel mich darauf hin, dass ich einen Big Player vollkommen außer acht gelassen habe: AjaxPro von Michael Schwarz.

Das wollte ich natürlich nicht auf mir sitzen lassen. Daher befassen wir uns heute mit:

AjaxPro :-)

AjaxPro ist eine freie Library von Michael Schwarz, die Ajax unter ASP.NET ohne Postbacks ermöglicht. Vergleichbar ist AjaxPro somit am ehesten mit den in Teil 4 vorgestellten PageMethods. Ein großer Vorteil gegenüber diesen ist jedoch die Möglichkeit, AjaxPro auch unter ASP.NET 1.1 einsetzen zu können (ja - ich kenne wirklich noch aktive ASP.NET 1.1 Projekte ;-)). Angemerkt werden sollte noch, dass AjaxPro keiner Weiterentwicklung mehr unterliegt. Michael Schwarz schrieb in in seinem Blog, dass er die Arbeit an der Library einstellt. Als Alternative empfiehlt er den Einsatz von PageMethods.

Lost gehts

AjaxPro ist relativ einfach eingebunden. Es genügt einen Verweis auf die Datei AjaxPro.2.dll hinzuzufügen.

01addreference

Weiter muss AjaxPro in der Datei web.config des Webprojekts bekannt gemacht werden. Dies geschieht über das Hinzufügen eines entsprechenden Http-Handlers:

<httpHandlers>
   ...
   <add verb="POST,GET" path="ajaxpro/*.ashx" type="AjaxPro.AjaxHandlerFactory, AjaxPro.2"/>
</httpHandlers>

Anschließend müssen die Methoden einer Seite, die später via Ajax aufgerufen werden sollen, mit dem Attribut AjaxMethod annotiert werden. Dies funktioniert also ähnlich wie die bereits vorgestellten PageMethods. Der Quellcode dieses Beitrags basiert übrigens wieder auf dem Quellcode der vorherigen Teile dieser Serie.

public partial class Teil7 : Page
{
    [AjaxPro.AjaxMethod]
    public string ReadStaticFile()
    {
        string fileContent;
        using (var reader = 
            new StreamReader(
                System.Web.HttpContext.Current.Server.MapPath("~/static.html")))
        {
            fileContent = reader.ReadToEnd();
        }
        return fileContent;
    }
}

Ein netter Nebeneffekt im Vergleich zu Pagemethods ist übrigens, dass die entsprechende Methode zwar statisch sein kann, dies aber nicht muss. Außerdem muss sich die Methode noch nicht einmal zwingend innerhalb einer Webseite (ASPX-Datei) befinden. Stattdessen kann Sie Mitglied einer beliebigen öffentlichen Klasse sein.

Um diese Methode nun komfortabel per JavaScript aufrufen zu können, muss die zugehörige Klasse noch als AjaxTyp registriert werden. Dies geschieht in der Methode Page_Load der Klasse Teil7.

protected void Page_Load(object sender, System.EventArgs e)
{
    AjaxPro.Utility.RegisterTypeForAjax(typeof(Teil7));
}

Der Aufruf innerhalb der Seite kann nun wie folgt erfolgen:

<a href="#" id="StaticFileLink" onclick="Teil7.ReadStaticFile(ajaxdemo_callback)">Hier klicken zum Request einer statischen Datei</a><br />

Bei dem übergebenen Parametger ajaxdemo_callback handelt es sich um eine Callback Funktion, die die Antwort des Servers verarbeitet. In unserem Beispiel sieht sie wie folgt aus:

<script type="text/javascript">
    function ajaxdemo_callback(result) {
       var content = document.getElementById('content');
       content.innerHTML = result.value;
    }
</script>

Die Seite ist nun funktionsfähig und kann gestartet werden. Ein Blick in die Firebug Ausgabe zeigt, dass neben der eigentlichen Seite automatisch noch 4 JavaScript Dateien geladen wurden. Diese sind für die Serverkommunikation zuständig und haben eine Gesamtgröße von nur 25 kb! Im Vergleich zu den zuvor vorgestellten Lösungen ist dies das beste Ergebnis!

02_initialesladen

Auch beim Aufruf der serverseitigen Methode schlägt sich AjaxPro gut. Hier gehen lediglich 111 Byte über die Leitung:

03_ajaxcall

Der Aufruf selbst hat eine Datei mit der Endung *.ashx innerhalb des Pfads /ajaxpro zum Ziel. In meinem Beispiel lautet die URL: http://localhost:2800/AjaxDemo/ajaxpro/Teil7,App_Web_mke8f-yp.ashx. Er wird somit durch den zuvor in der web.config eingetragenen Http-Handler behandelt. Außerdem ist innerhalb der URL, wie man sehen kann, der Name der Klasse in der sich die entsprechende Methode befindet kodiert. Die Methode selbst wird im Header des Aufrufs als Attribut X-AjaxPro-Method übergeben.

Webservices

Nachdem sich PageMethods relativ einfach aufrufen ließen, stellt sich nun natürlich die Frage, wie die Methoden eines Webservices aufgerufen werden können.

Eine Variante wäre es, die Methoden innerhalb des Webservices nicht nur mit dem Attribut [WebMethod] zu anotieren, sondern zusätzlich auch mit [AjaxPro.AjaxMethod] zu versehen. Diese Variante ist selbstverständlich nur für eigene und nicht für externe Webservices möglich.

Ein allgemeingültiger Ansatz besteht darin, händisch Proxy-Methoden innerhalb der Seite für die gewünschten Webservice Methoden anzulegen.

[AjaxPro.AjaxMethod]
public string CallHelloWorldService()
{
    return new AjaxDemoService().HelloWorld();
}

[AjaxPro.AjaxMethod]
public string CallEchoService(int value)
{

    return new AjaxDemoService().Echo(value);
}

Auf dem Client birgt der zusätzliche Code keine Überraschungen. Der Aufruf der serverseitigen Methoden erfolgt analog des ersten Beispiels. Die einzige Besonderheit ist der Aufruf der Methode CallEchoService, da diese einen Parameter erwartet.

<script type="text/javascript">
    function callEchoService() {
        var echoTextBox = document.getElementById('EchoTextBox');
        var value = echoTextBox.value;
        Teil7.CallEchoService(value, ajaxdemo_callback);
    }

    function ajaxdemo_callback(result) {
        var content = document.getElementById('content');
        content.innerHTML = result.value;
    }
</script>

Wie der Beispielcode zeigt, wird der erwartete Parameter einfach vor die Angabe der JavaScript Callback Funktion gepackt.

Fazit

AjaxPro ist eine kleine und leichtgewichtige Ajax Library, die ohne unnötigen Ballast daher kommt. Durch die Ähnlichkeit zu Pagemethods und Scriptservices fiel mir die Einarbeitung ziemlich leicht und nahm kaum mehr als eine halbe Stunde in Anspruch.

Trotz dieser Vorteile kann ich mir nicht vorstellen, AjaxPro als Standardwerkzeug in aktuellen Projekten zu nutzen. Stattdessen werde ich wohl weiterhin auf jQuery setzen. Der Grund für diese Entscheidung liegt ganz einfach darin, dass ich jQuery zu UI Manipulationszwecken meist sowieso schon auf meinen Seiten referenziert habe. Daher ist es naheliegend für AjaxRequests auch zu jQuery zu greifen.

Sehr gut vorstellen könnte ich mir jedoch, AjaxPro in ASP.NET 1.1 Projekten zu nutzen, die sich noch in Pflege befinden. In diesen fehlt die Möglichkeit, PageMethods und Scriptservices einzusetzen, so das AjaxPro dort das perfekte Werkzeug wäre.

An dieser Stelle auch noch einmal vielen Dank an René für den hilfreichen Tipp.



blog.codemurai.de © André Krämer |Impressum | Abonieren

Einladung zum Treffen der SharePoint Usergroup Dresden am 12.05.2010

29.03.2010 19:05:00 | Martin Hey

Zum offiziellen Start von SharePoint 2010 und Office 2010 am 12.05.2010 wird es quer durch die deutschsprachige SharePoint-Community ein Public Viewing der Keynote von Stephen Elob zum SharePoint Community SharePoint 2010 Launch Event geben. An diesem Event beteiligt sich auch die Sharepoint Usergroup Dresden.

Aus diesem Grund findet das Treffen diesmal auch etwas früher als gewohnt statt: Wir treffen uns am 12.05. 16:30 bei der T-Systems MMS. Nähere Informationen zum Termin findet man immer im Xing. Dort gibt es auch einen Link zur Anmeldung.

Nachlese zum Treffen der .NET Usergroup Dresden am 24.03.2010

29.03.2010 18:53:00 | Martin Hey

Vergangenen Mittwoch fand das März-Treffen der .NET Usergroup Dresden statt. Wie bereits in der Einladung angekündigt, ging es diesmal rund um das Thema Silverlight.

Nachdem Gregor mit uns gemeinsam eine Reise durch die Geschichte von Silverlight machte und dabei auch auf die Vereinfachungen einging, die Silverlight 4 bringt, zeigte uns René im Anschluss daran in einer sehr eindrucksvollen Präsentation sein SLAR-Toolkit und wie man mit Hilfe von Markern und einer Webcam in Silverlight Realität und virtuelle Objekte miteinander verschmelzen lassen kann.



Für mich war es wieder ein sehr spannender Abend, auch wenn mich Renés Teil mehr fasziniert hat als Gregors - was aber wohl auch damit zusammenhängt, dass ich mich mit Silverlight 4 schon vorher beschäftigt hab, aber bisher noch keine Berührungspunkte mit Augmented Reality hatte.

Internet Explorer 9 und HTML5 – Die Videos von der Mix

29.03.2010 10:01:00 | Oliver Scheer

Daily Demo: Weekly Summary

29.03.2010 09:00:00 | Oliver Scheer

Last week I did it again, five nice demos for Silverlight 3 usage, with live Previews and Sourcecode.

22.03.2010 – Silverlight 3 Deep Zoom Mouse Zoom Features Behavior // Preview

23.03.2010 – Silverlight 3 Deep Zoom Navigate Home Behavior // Preview

24.03.2010 – Silverlight 3 Deep Zoom Randomizing Images // Preview

25.03.2010 – Silverlight 3 Deep Zoom Slide Show Behavior // Preview

26.03.2010 – Silverlight 3 Mouse 3D Behavior // Preview

If you have any suggestions for nice Daily Demos, please comment ..

Best regards,
The-Oliver

Recent demos:

15.03.2010 – Silverlight 3: Text Tipping Control // [Preview]

16.03.2010 – Silverlight 3: Image Spindle // [Preview]

17.03.2010 – Silverlight 3: Image Stack // [Preview]

18.03.2010 – Silverlight 3: Behavior – 3D Hover Effect // [Preview]

19.03.2010 – Silverlight 3: Trigger Action – Fullscreen // [Preview]

Daily Demo: Silverlight Install out of browser & Check for Update Behaviors

29.03.2010 08:15:00 | Oliver Scheer

A great feature in Silverlight 3 is the capability to install applications out-of-browser. For those applications it is very useful to check, whether there is an update at the original location, where they are coming from.

My simple application checks this using behaviors, which can be reused for any applications. Just one feature is very important to enable –> The Out-Of-Browser Feature in your application.

The install-Behavior checks the Install-State of the application, and hide the control which contains the Install-Feature, if it is already installed.

Live Preview

image

The in-browser version, with an Install button.

image

The same application after installing it local.

image

The out-of-browser-application without the install button (because, it is already installed Wink)

image

The Update Dialog, when an update is available. You will not see this feature in the preview, because I will not update it regularly.

No code needed in your application

XAML-Code

<UserControl
    x:Class="SmallTextEditor.MainPage"
    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"
    mc:Ignorable="d"
    d:DesignHeight="300"
    d:DesignWidth="400"
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    xmlns:TheOliver="clr-namespace:TheOliver.Controls">
    
    <Grid
        x:Name="LayoutRoot"
        Background="White">

        <i:Interaction.Triggers>
            <i:EventTrigger
                EventName="Loaded">
                <TheOliver:CheckForUpdateBehavior />
            </i:EventTrigger>

        </i:Interaction.Triggers>

        <Grid.RowDefinitions>
            <RowDefinition
                Height="28*" />
            <RowDefinition
                Height="272*" />
        </Grid.RowDefinitions>
        <RichTextBox
            x:Name="_textbox"
            Grid.Row="1"
            IsEnabled="False" />
        <StackPanel
            HorizontalAlignment="Left"
            Name="stackPanel1"
            Orientation="Horizontal">
            <Button
                Content="New"
                Height="23"
                Name="_new"
                IsEnabled="False" />
            <Button
                Content="Open"
                Height="23"
                Name="_open"
                IsEnabled="False" />
            <Button
                Content="Save"
                Height="23"
                Name="_save"
                IsEnabled="False" />

            <Button
                Content="Install Local"
                Height="23"
                Name="_install">
                <i:Interaction.Triggers>
                    <i:EventTrigger
                        EventName="Click">
                        <TheOliver:InstallOutOfBrowserBehavior />
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </Button>
        </StackPanel>
    </Grid>
</UserControl>

Sourcecode for Install-Out-Of-Browser-Behavior

 

// Copyright © Microsoft Corporation.  All Rights Reserved.
// This code released under the terms of the 
// Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)

using System.Windows;
using System.Windows.Interactivity;
using System.Windows.Controls;

namespace TheOliver.Controls
{
    public class InstallOutOfBrowserBehavior  : TargetedTriggerAction<FrameworkElement>
    {
        UIElement _element;

        protected override void OnAttached()
        {
            _element = this.Target as UIElement;

            if (!Application.Current.IsRunningOutOfBrowser)
            {
                 Application.Current.InstallStateChanged += (s, e) =>
                    {
                        CheckInstallState();
                    };

                CheckInstallState();

                if (_element is Button)
                {
                    (_element as Button).Click += (s, e) =>
                        {
                            InstallOOB();
                        };
                }
                else
                {
                    _element.MouseLeftButtonDown += (s, e) =>
                    {
                        InstallOOB();
                    };
                }
            }
            else
            {
                _element.Visibility = Visibility.Collapsed;
            }
            base.OnAttached();
        }

        private void InstallOOB()
        {
            if (Application.Current.InstallState != InstallState.Installed &&
                Application.Current.InstallState != InstallState.Installing)
            {
                Application.Current.Install();
            }
        }

        private void CheckInstallState()
        {
            if (Application.Current.InstallState == InstallState.Installed ||
                Application.Current.InstallState == InstallState.Installing)
            {
                _element.Visibility = Visibility.Collapsed;
            }
            else
            {
                _element.Visibility = Visibility.Visible;
            }
        }

        protected override void Invoke(object o)
        {
            
        }
    }
}

Sourcecode for CheckForUpdateBehavior

// Copyright © Microsoft Corporation.  All Rights Reserved.
// This code released under the terms of the 
// Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)

using System.Windows;
using System.Windows.Interactivity;

namespace TheOliver.Controls
{
    public class CheckForUpdateBehavior  : TargetedTriggerAction<FrameworkElement>
    {
        UIElement _element;

        protected override void OnAttached()
        {
            // Works only out-of-browser
            if (Application.Current.IsRunningOutOfBrowser)
            {
                _element = this.AssociatedObject as UIElement;
            }
            base.OnAttached();
        }

        protected override void Invoke(object o)
        {
            if (_element != null)
            {
                Application.Current.CheckAndDownloadUpdateCompleted += (s, e) =>
                {
                    if (e.UpdateAvailable)
                    {
                        MessageBox.Show(UpdateIsAvailableMessageText);
                    }
                };
                Application.Current.CheckAndDownloadUpdateAsync();
            }
        }

        public string UpdateIsAvailableMessageText
        {
            get { return (string)GetValue(UpdateIsAvailableMessageTextProperty); }
            set { SetValue(UpdateIsAvailableMessageTextProperty, value); }
        }

        public static readonly DependencyProperty UpdateIsAvailableMessageTextProperty =
            DependencyProperty.Register(
                "UpdateIsAvailableMessageText", 
                typeof(string), 
                typeof(CheckForUpdateBehavior), 
                new PropertyMetadata("Update is available. Please restart your application"));

        
    }
}

Solutiondownload

 

Best regards,
The-Oliver

Visual Studio 2010: Windows-Programme mit Visual C++ erstellen

26.03.2010 16:36:21 | Oliver Scheer

In der MSDN Library stehen sechs neue Artikel zur Verfügung, die demonstrieren, wie man mit Visual Studio 2010 Windows-Programme mit einer grafischen Benutzeroberfläche in Visual C++ erstellen kann. Alle Artikel von Richard und Alexander Kaiser basieren auf dem Fachbuch "C++ mit Microsoft Visual C++ 2008". Folgende Themen sind verfügbar:

· Erste Schritte: Einfache Windows .NET Programme mit Visual C++: Dieser Artikel zeigt an sehr einfachen Beispielen, wie man mit Visual Studio 2010 und C++ Windows-Programme mit einer grafischen Benutzeroberfläche entwickeln kann.

· Steuerelemente für die Benutzeroberfläche: Ein Überblick über einige der wichtigsten Steuerelemente von Windows-Programmen. Dabei werden am Beispiel eines Labels, einer TextBox und eines Buttons einige der wichtigsten Eigenschaften, Methoden und Ereignisse vorgestellt. Im Vordergrund steht, wie man diese unter C++ anspricht.

· Windows Forms-Anwendungen mit Standard-C++: Beschreibt ein allgemein einsetzbares Programmschema, mit dem Windows Forms-Anwendungen mit Anweisungen in Standard-C++ geschrieben werden können.

· C++/CLI-Erweiterungen: Visual C++ verwendet in Windows Forms-Anwendungen eine Erweiterung von Standard-C++, die als C++/CLI bezeichnet wird. Die C++/CLI-Erweiterungen integrieren einige C#-Konzepte in C++ und ermöglichen die Nutzung der.NET-Bibliothek auch unter C++.

· .NET-Klassen in C++ Windows Forms-Anwendungen: In einer C++ Windows Forms-Anwendung steht im Wesentlichen die gesamte .NET-Bibliothek zur Verfügung. An einigen einfachen Beispielen wird gezeigt, wie .NET-Klassen in C++ verwendet werden können.

· Win32-DLLs und Win32-API-Funktionen in Windows Forms-Anwendungen verwenden: In einer C++ Windows Forms-Anwendung können auch Win32-DLLs verwendet werden. Das wird am Beispiel von Win32-API-Funktionen gezeigt.

Die verwendeten Beispiele stehen als Visual Studio-Projekt zum Download zur Verfügung. Alle Artikel und Beispiele sind auch für Visual Studio 2005 und Visual Studio 2008 in der MSDN Library zu finden.

Bing Maps Twitter App für die eigene Website

26.03.2010 14:09:03 | Oliver Scheer

Gerade wurde eine neue Aktualisierung der Twitter Maps Application in der Bing Maps Application Gallerie eingestellt. Jetzt hat man die Möglichkeit diese App auch in seine eigene Webseite einzubinden.

Das Ganze geschieht in nur vier Schritten:

  1. Map-Position einstellen.
  2. Größe der Map definieren
  3. Suchkriterien hinzufügen
  4. HTML-Snippet kopieren und in eigene Webseite einbinden.
image

 

Link: http://www.bing.com/maps/explore –> Map Apps –> Twitter

Synthesizer Library für Silverlight

26.03.2010 13:37:45 | Oliver Scheer

Auf Codeplex ist jetzt eine sehr coole Synthesizer-Bibliothek für Silverlight veröffentlich worden.

Mit der können sich die Depeche Mode und Silverlight-Fans mal so richtig austoben und den nächsten Super-Synthie-Hit coden.

Eine Demo gibt es hier.

image

Die Codeplex-Bibliothek ist hier zu finden.

Daily Demo: Silverlight Mouse 3D Behavior

26.03.2010 08:00:00 | Oliver Scheer

A very cool new feature in Silverlight 3 is the support of perspective 3D. And now image what you can do with 3D, your Mouse and Behaviors. Apply 3D capabilities to every control you like.

Ta da … the Silverlight Mouse 3D Behavior 

image

Livepreview

 

XAML-Code

<UserControl
    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"
    mc:Ignorable="d"
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    xmlns:TheOliver_Controls="clr-namespace:TheOliver.Controls"
    x:Class="Mouse3DBehavior.MainPage"
    d:DesignHeight="300"
    d:DesignWidth="400">

    <Grid
        x:Name="LayoutRoot"
        Background="White">

        <Image
            Source="20080815_114932.jpg"
            Stretch="Fill">
            <i:Interaction.Behaviors>
                <TheOliver_Controls:Mouse3DBehavior />
            </i:Interaction.Behaviors>
        </Image>

    </Grid>
</UserControl>

 

Sourcecode

// Copyright © Microsoft Corporation.  All Rights Reserved.
// This code released under the terms of the 
// Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)

using System.Windows;
using System.Windows.Input;
using System.Windows.Interactivity;
using System.Windows.Media;

namespace TheOliver.Controls
{
    public class Mouse3DBehavior : Behavior<UIElement>
    {
        PlaneProjection _planeProjection;
        bool _buttonPressed = false;
        Point _originPoint;
        UIElement _target;
        FrameworkElement _control;
        UIElement _targetParent;
        double _controlHeight;
        double _controlWidth;

        protected override void OnAttached()
        {
            base.OnAttached();

            _target = this.AssociatedObject;
            _control = _target as FrameworkElement;

            _control.LayoutUpdated += (s, e) =>
                {
                    _targetParent = _control.Parent as UIElement;

                    _planeProjection = new PlaneProjection();
                    _target.Projection = _planeProjection;

                    _targetParent.MouseLeftButtonDown += new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonDown);
                    _targetParent.MouseLeftButtonUp += new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonUp);
                    _targetParent.MouseMove += new MouseEventHandler(AssociatedObject_MouseMove);
                    _targetParent.MouseLeave += new MouseEventHandler(AssociatedObject_MouseLeave);

                    _controlHeight = (_targetParent as FrameworkElement).ActualHeight;
                    _controlWidth = (_targetParent as FrameworkElement).ActualWidth;
                };
        }

        void AssociatedObject_MouseLeave(object sender, MouseEventArgs e)
        {
            _buttonPressed = false;
        }

        void AssociatedObject_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            _target.CaptureMouse();
            _originPoint = GetPoint(e);
            _buttonPressed = true;
        }

        void AssociatedObject_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            _buttonPressed = false;
            _target.ReleaseMouseCapture();
        }

        void AssociatedObject_MouseMove(object sender, MouseEventArgs e)
        {
            if (_buttonPressed)
            {
                PlaneProjection pp = _target.Projection as PlaneProjection;
                Point pt = GetPoint(e);

                double widthPixPerAngle = _controlWidth / 720;
                double heightPixPerAngle = _controlHeight / 720;

                double diffY = (pt.X - _controlWidth / 2) * widthPixPerAngle;
                double diffX = (pt.Y - _controlHeight / 2) * heightPixPerAngle;

                _originPoint = pt;

                if (YEnable)
                {
                    pp.RotationY = diffY;
                }

                if (XEnable)
                {
                    pp.RotationX = diffX;
                }
            }
        }

        private Point GetPoint(MouseEventArgs e)
        {
            Point point = e.GetPosition(_targetParent);
            return point;
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
            this.AssociatedObject.Projection = null;

            _targetParent.MouseLeftButtonDown -= new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonDown);
            _targetParent.MouseLeftButtonUp -= new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonUp);
            _targetParent.MouseMove -= new MouseEventHandler(AssociatedObject_MouseMove);
            _targetParent.MouseLeave -= new MouseEventHandler(AssociatedObject_MouseLeave);
        }

        public double MoveFactor
        {
            get { return (double)GetValue(MoveFactorProperty); }
            set { SetValue(MoveFactorProperty, value); }
        }

        public static readonly DependencyProperty MoveFactorProperty =
            DependencyProperty.Register(
                "MoveFactor",
                typeof(double),
                typeof(Mouse3DBehavior),
                new PropertyMetadata(1.0));

        public bool XEnable
        {
            get { return (bool)GetValue(XEnableProperty); }
            set { SetValue(XEnableProperty, value); }
        }

        public static readonly DependencyProperty XEnableProperty =
            DependencyProperty.Register(
                "XEnable",
                typeof(bool),
                typeof(Mouse3DBehavior),
                new PropertyMetadata(true));

        public bool YEnable
        {
            get { return (bool)GetValue(YEnableProperty); }
            set { SetValue(YEnableProperty, value); }
        }

        public static readonly DependencyProperty YEnableProperty =
            DependencyProperty.Register(
                "YEnable",
                typeof(bool),
                typeof(Mouse3DBehavior),
                new PropertyMetadata(true));
    }
}

 

Solutiondownload

Coding Camp: Entdeckt die Welt von Windows Phone 7 Series!

25.03.2010 11:04:49 | Oliver Scheer

Das eigene App auf dem neuen Windows Phone 7 Series? Für Studenten kann aus diesem Traum beim Windows Phone 7 Series Coding Camp auf der Burg Freusburg Wirklichkeit werden!

Unter dem Motto „Entdecke die neue Welt des Mobile Developments!“ zeigt Microsoft Studenten vom 7.-9. Mai auf der alten Ritterburg in einem unvergleichlichen Ambiente, was diese neue Welt alles zu bieten hat. Gemeinsam mit den Microsoft Experten Frank Prengel, auch bekannt als Dr. Mobile, Oliver Scheer alias Mr. deep zoom und Tom Wendel alias the ant man erwartet die Studenten die ultimative Coding-Erfahrung! Ziel ist es zudem, die fertigen Apps zusätzlich beim Windows Phone 7 "Rockstar" Award“ des Imagine Cups einzureichen. So haben die Studenten zusätzlich die Chance auf eine Reise zum internationalen Finale in Warschau und auf Preise im Wert von $8.000!

Wer kann dabei sein?

Studenten, die sich für Mobile Development interessieren und für die XNA und Silverlight keine Fremdwörter sind, können sich auf einen der begehrten Plätze bewerben:

Hierzu müssen sie eine Begründung, warum gerade sie einen der 30 Plätze im Coding Camp bekommen sollten, an youdream@microsoft.com schicken:  

z.B. Schildere uns kurz und knapp Deine Erfahrungen mit Mobile Entwicklung. Was reizt Dich an Mobile Development? Welche Apps wolltest Du schon immer mal bauen?

Studenten, die einen der begehrten Plätze ergattern, müssen lediglich die Anreise selbst übernehmen, Übernachtung, Verpflegung etc. übernimmt Microsoft!

Daily Demo: Silverlight Deep Zoom Slide Show Behavior

25.03.2010 08:00:00 | Oliver Scheer

Deep Zooms are very useful for catalog systems or holiday photos. You can get a big impression of all your images, but when you want to step through each single picture, navigation could get a little bit challenging … until now. Here is a small behavior to step through each single photo in a deep zoom collection.

image

Live Preview

XAML Code

<UserControl
    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"
    mc:Ignorable="d"
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    xmlns:TheOliver_Controls="clr-namespace:TheOliver.Controls"
    x:Class="DeepZoomMouseBehavior.MainPage"
    d:DesignHeight="300"
    d:DesignWidth="400">

    <Grid
        x:Name="LayoutRoot"
        Background="White">
        <TextBlock
            Text="Deep Zoom Sample" />
        <MultiScaleImage
            x:Name="_msi"
            Source="Images/dzc_output.xml"
            Margin="0,19,0,0">
            <i:Interaction.Behaviors>
                <TheOliver_Controls:DeepZoomBehavior />
            </i:Interaction.Behaviors>
        </MultiScaleImage>
        <Button
            x:Name="_home"
            HorizontalAlignment="Right"
            VerticalAlignment="Top"
            Width="53"
            Content="Home">
            <i:Interaction.Triggers>
                <i:EventTrigger
                    EventName="Click">
                    <TheOliver_Controls:DeepZoomNavigateHomeBehavior
                        TargetName="_msi" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>
        <Button
            x:Name="_shuffle"
            HorizontalAlignment="Right"
            VerticalAlignment="Top"
            Width="53"
            Content="Shuffle"
            Margin="0,0,57,0">
            <i:Interaction.Triggers>
                <i:EventTrigger
                    EventName="Click">
                    <TheOliver_Controls:DeepZoomRandomImageArrangeBehavior
                        TargetName="_msi"
                        XOffset="1"
                        YOffset="1" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>
        <Button
            x:Name="_slideShow"
            HorizontalAlignment="Right"
            VerticalAlignment="Top"
            Width="68"
            Content="Slideshow"
            Margin="0,0,114,0">
            <i:Interaction.Triggers>
                <i:EventTrigger
                    EventName="Click">
                    <TheOliver_Controls:DeepZoomSlideShowBehavior
                        TargetName="_msi" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>
    </Grid>
</UserControl>

 

Sourcecode

// Copyright © Microsoft Corporation.  All Rights Reserved.
// This code released under the terms of the 
// Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)

using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;

namespace TheOliver.Controls
{
    public class DeepZoomSlideShowBehavior : TargetedTriggerAction<MultiScaleImage>
    {
        private MultiScaleImage _msi;
        private int _count = 0;
        private int _totalImages;

        protected override void Invoke(object o)
        {
            if (this._msi == null)
            {
                this._msi = this.Target;
                _totalImages = _msi.SubImages.Count;
            }

            if (_count < _totalImages)
            {
                ZoomOnImage(_count);
            }
            else
            {
                _count = 0;
                ZoomOnImage(_count);
            }
        }

        private void ZoomOnImage(int subImageIndex)
        {
            _count++;

            MultiScaleSubImage subImage = _msi.SubImages[subImageIndex];

            double scaleBy = 1 / subImage.ViewportWidth;

            Rect subImageRect =
                new Rect(-subImage.ViewportOrigin.X * scaleBy,
                    -subImage.ViewportOrigin.Y * scaleBy,
                    scaleBy,
                    (1 / subImage.AspectRatio) * scaleBy);

            if ((this._msi.Width / this._msi.Height) > subImage.AspectRatio)
            {
                double targetViewportWidth = subImageRect.Height * this._msi.AspectRatio;
                double targetPointX = (targetViewportWidth - subImageRect.Width) / 2;

                this._msi.ViewportOrigin = new Point(subImageRect.X - targetPointX, subImageRect.Y);
                this._msi.ViewportWidth = targetViewportWidth;
            }
            else
            {
                this._msi.ViewportWidth = subImageRect.Width;
                this._msi.ViewportOrigin = new Point(subImageRect.X, subImageRect.Y);
            }
        }
    }
}

 

Solutiondownload

Transportsystem alla SAP mit TFS und ASP.NET

25.03.2010 07:11:43 | Andre Kraemer

Von Administratoren geliebt, von Entwicklern verflucht: Das Transportsystem von SAP. Prinzipiell kann man sich das so vorstellen, dass dieses System vorsieht, dass der Quellcode nur an einer Stelle, nämlich im SAP Entwicklungssystem erstellt und modifiziert wird.

Anschließend wird ein sogenannter Transport (so was ähnliches wie ein Setuppaket) erstellt. Dieses kann dann je Konfiguration erst mal nur in das Testsystem eingespielt werden. Dort wird das Paket auf seine Funktionstüchtigkeit getestet. Wurden diese Tests bestanden, wird es in das Integrationssystem "transportiert". Dort wird das Zusammenspiel mit anderen Anpassungen getestet, es wird also geprüft, ob das Paket nichts anderes kaputt macht ;-)

War auch dieser Test erfolgreich, wird der Transport aus dem Integrationssystem in das Produktionssystem transportiert. Ein direktes Einspielen von Transporten in das Produktionssystem beziehungsweise sogar ein direktes Ändern der Quellcodes ist nicht vorgesehen.

Auch wenn diese Vorgehensweise zunächst recht streng, bürokratisch und viel zu aufwändig wirkt, hat sie durchaus ihren Sinn. Dieser zugegeben etwas starre Prozess sorgt dafür, dass SAP Produktionssysteme normalerweise immer stabil und möglichst fehlerfrei sein sollten. Er trägt also Maßgeblich zu SAPs gutem Ruf bei!

Warum erzähle ich das eigentlich?

Ok, nette Einführung, aber ist das hier nicht eigentlich ein auf .NET fokussierter Blog? Ja :-) Also keine Sorge, ich bin nicht ins Lager der SAP Consultants gewechselt ;-) Allerdings habe ich von ungefähr 2005 bis 2008 die SAP Schnittstelle meines ehemaligen Arbeitgebers gemeinsam mit einem Kollegen weiterentwickelt. Da blieb der ein oder andere Blick unter die Haube diverser SAP Systeme nicht aus.

Nun aber zurück zum Thema:

In meiner beruflichen Laufbahn war ich an einigen (ASP).NET Projekte beteiligt, die von einem SAP transportähnlichen System sehr profitiert hätten. Überspitzt gesagt sah es dort nämlich häufig so aus, dass ein Entwickler nach einer Quellcodeänderung Visual Studio genutzt hat um einen neuen Releasestand zu erstellen und diesen dann schnell auf den produktiven Webserver gepackt hat. Selbstverständlich wurde das ganze vorher nicht in einem Test- oder Integrationssystem installiert und unter Umständen wusste der Kunde und/oder Projektleiter sogar nichts von dem adhoc Update.

Agil != Chaos !!!

Der Entwickler handelte unter dem Deckmantel der agilen Entwicklung nach dem Prinzip "nach mir die Sinnflut", einfach drauf damit, wird schon klappen. In diesem Zusammenhang finde ich es übrigens immer wieder äußerst verwunderlich, wie viele Entwickler unkoordiniertes und schlampiges Vorgehen einfach als agil bezeichnen, um ihr Chaos damit zu entschuldigen. Agil ist allerdings alles andere als chaotisch, unprofessionell, unkoordiniert oder schlampig. Aber gut, dass ist ein anderes Thema - ich schweife schon wieder aus ;-)

In einem meiner aktuellen Projekte wollte ich einer solchen Vorgehensweise direkt einen Riegel vorschieben. Nicht dass die Entwickler dieses Projekts chaotisch wären, das ist ganz und gar nicht der Fall, aber wir wollen ja auch niemanden in Versuchung führen ;-)

Ich hatte einen Traum ...

Meine Ziele lautete also wie folgt:

  1. Releasestände einer Software sollen automatisch auf einem dedizierten Buildrechner und nicht auf einem Entwickler-PC erstellt werden.
  2. Jedes Release hat eine eindeutige Versionsnummer. Kompilate auf dem Entwicklerrechner haben jedoch immer die Nummer 1.0.0.0 (dazu später mehr)
  3. Jedes Release soll ein Set an Unit Tests durchlaufen haben.
  4. Jedes Release soll mit einer bestimmten Qualität als Metadatum versehen werden.
  5. In Abhängigkeit von dieser Qualität und der vorherigen Qualität soll die Software bei bestimmten Statusübergängen automatisch auf bestimmte Systeme verteilt werden.
  6. Das Qualitätsmetadatum wird durch einen dedizierten Personenkreis gesetzt (zum Beispiel QM-Manager oder Projektmanager, Softwarearchitekt oder Chefentwickler)

Realisiert werden sollte das ganze mit Visual Studio 2008 und dem Team Foundation Server. Die Punkte 1 - 3 stellen in einer solchen Umgebung kein Problem dar.

Punkt Nr. 1 erledigen wir durch Teambuild. Hier läuft ein Buildagent auf einem dedizierten Rechner. Durchgeführt werden sowohl Continuous Integration Builds, als auch Nightly Builds.

Punkt Nr. 2 haben wir durch ein einfaches Build Target in unserem Buildscript erledigt. Die Versionsnummer haben wir wie folgt aufgebaut:

  • Major: Fixer Wert
  • Minor: Fixer Wert
  • Build: Aktueller Changeset des Teamprojekts im TFS
  • Revision: Fortlaufende Nummer

Diese Nummer wird nur während des Builds durch Teambuild erzeugt. Entwicklerbuilds haben immer die Version 1.0.0.0. So fange ich ab, dass ein Entwickler doch einfach mal auf seinem Rechner eine Version baut und versucht zu deployen. Natürlich ist dies nur ein weicher Schutz. Mit ein wenig Aufwand lässt sich das System natürlich leicht umgehen indem ein Entwickler eine korrekte Versionsnummer erzeugt. Allerdings ist der Aufwand schon wieder so hoch, dass sich dann doch lohnt, den vorgesehenen Prozess einzuhalten ;-)

Sollte jemand Interesse an diesem Teil des Buildscripts haben: Einfach einen Kommentar posten.

Punkt Nr. 3 ist natürlich auch kein Problem. Aufgrund der guten VS Integration haben wir uns für MS Test für dieses Projekt entschieden. Diese Tests als Bestandteil des Buildprozess laufen zu lassen war demnach kein Problem.

Punkt Nr. 4 ist auch bereits von Haus aus mit dem TFS möglich. Jeder Build der durch Teambuild durchgeführt wird hat ein Metadatum Buildqualität. Die möglichen Werte der Buildqualität lassen sich frei definieren. Auch lässt sich über entsprechende Rechte einschränken, wer diese Qualität setzen darf. Wir haben bei uns die Werte "Entwicklung", "Test", "Integration", "Produktion" und "Abgelehnt" definiert.

Punkt Nr. 5 kann mit TFS Bordmitteln erst mal nicht realisiert werden. Hier kommt nun das Open Source Projekt TFS Deployer ins Spiel. TFS Deployer installiert man als Windowsdienst. Nach entsprechender Konfiguration lauscht er nun auf eine Änderung der Buildqualität. Dazu muss der Benutzer unter dem der Dienst läuft allerdings in der TFS Gruppe Valid Users sein und für das entsprechende Temaprojekt zumindest Leserechte haben. Bemerkt TFS Deployer nun einen Statusübergang, für den er ein Deploymentscript hat, führ er dieses automatisch aus.

Angelehnt an die Einführung von Dave Comfort und Scott Colestock kann man sich das ganze nun wie folgt vorstellen:

tfsdeployer

Konkret sieht dies so aus, dass innerhalb der TFS Quellcodeverwaltung unterhalb des Verzeichnisses der Builddefinition ein Verzeichnis Deployment angelegt wird, also zum Beispiel $/TeamProjekt/TeamBuildTypes/MeinProjektNightlyBuild/Deployment. In diesem Verzeichnis wird nun die Datei DeploymentMappings.xml angelegt. In dieser Datei wird für jeden gewünschten Statusübergang festgelegt, welches Powershellscript auf welchem Computer ablaufen soll. Die Datei DeploymentMappings kann zum Beispiel wie folgt aussehen:

<DeploymentMappings xmlns="http://www.readify.net/TFSDeployer/DeploymentMappings20061026">
  <Mapping xmlns=""
           Computer="tfsbuildserver"
           OriginalQuality="*"
           NewQuality="Entwicklung"
           Script="EntwicklerDrop.ps1"
           RunnerType="PowerShell"
           NotificationAddress="someone@mycompany.com;someoneelse@mycompany.com" />
  <Mapping xmlns=""
           Computer="tfsbuildserver"
           OriginalQuality="Entwicklung"
           NewQuality="Test"
           Script="EntwicklungNachTest.ps1"
           RunnerType="PowerShell"
           NotificationAddress="someone@mycompany.com;someoneelse@mycompany.com" />
  <Mapping xmlns=""
           Computer="tfsbuildserver"
           OriginalQuality="Test"
           NewQuality="Integration"
           Script="TestNachIntegration.ps1"
           RunnerType="PowerShell"
           NotificationAddress="someone@mycompany.com;someoneelse@mycompany.com" />
  <Mapping xmlns=""
           Computer="tfsbuildserver"
           OriginalQuality="Integration"
           NewQuality="Produktion"
           Script="TestNachIntegration.ps1"
           RunnerType="PowerShell"
           NotificationAddress="someone@mycompany.com;someoneelse@mycompany.com" />
</DeploymentMappings>

In diesem Script werden vier Statusübergänge definiert. Erst vom leeren Zustand nach Entwicklung, dann weiter nach Test, Integration und Produktion. Jeder dieser Status entspricht einem Build-Quality Eintrag im TFS. Diese sind wie angemerkt frei definierbar. Über die Eigenschaft Script wird nun definiert, welches Powershellscript ausgeführt werden soll. Diese Powershellscripte müssen übrigens im selben Ordner liegen, wie die Datei DeploymentMappings.xml.

Tritt nun einer der definierten Statusübergänge auf, ruft TFS Deployer das gewünschte Script im Kontext des Service Users auf und übergibt ein BuildData Objekt. Die verschiedenen des Eigenschaften BulidData Objekts können dann über die Variable $TfsDeployerBuildData zugegriffen werden.

In unserer Umgebung nutzen wir übrigens eine modifzierte Variante des Beispiels der Seite Team Foundation Server Build Recipes.

function publish-site( [string] $sourcepath, [string] $destinationpath, [bool] $renameconfig, [bool] $deleteexisting) {
	$droplocation = $TfsDeployerBuildData.DropLocation
	
	$websourcepath = $droplocation + $sourcepath
	$webdestinationpath = $destinationpath
	
	new-item -force -path $webdestinationpath -itemtype "directory"
	if ($deleteexisting) {
		get-childitem $webdestinationpath | remove-item -force -recurse
	}
	get-childitem $websourcepath | copy-item -force -recurse -destination $webdestinationpath

	if ($renameconfig) {
		$configFile = $webdestinationpath + "web.production.config"
		remove-item $configFile -force
		$configFile = $webdestinationpath + "web.development.config"
		remove-item $configFile -force
		$configFile = $webdestinationpath + integration.config"
		remove-item $configFile -force


		$configFile = $webdestinationpath + "web.test.config"
		$configFileDest = $webdestinationpath + "web.config"
		move-item $configFile $configFileDest -force
	}
}

publish-site "\Release\_PublishedWebsites\MyWebApplication\" "\\MeinWebServer\MeineFreigabe\" 1 1

Dies funktioniert in unserer Umgebung recht gut, da wir vom Build Server direkten Zugriff auf die verschiedenen Web Server (Entwicklung, Test, Integration, Produktion) haben. Für jede Webapplikation besteht auf den Servern eine Windows Freigabe, die direkt auf das Wurzelverzeichnis der Applikation zeigt. Zugriffsrechte hat hier nun der Benutzer, unter der TFS Deployer Dienst läuft. So stellen wir sicher, dass keiner der Entwickler "mal schnell" etwas patcht ;-) Noch sicherer wäre es natürlich gewesen, den TFS Deployer Dienst direkt auf dem Web Server laufen zu lassen, und ihm lesenden Zugriff auf die erstellen Binaries des Buildprozesses zu geben.

Als Erweiterung zum Standardscript wärmen wir nach dem Deployment Vorgang die Applikation noch auf, indem wir einige Seiten ansurfen. Somit ist sichergestellt, dass der Workerprozess beim ersten Zugriff durch einen Benutzer schon da ist und die entsprechenden Seiten auch schon kompiliert wurden.

Den Übergang von "Nichts" zu "Entwicklung" machen wir übrigens automatisch als letzten Schritt unseres Buildscripts. Somit wird der Nightly Build Automatisch in die Entwicklungsumgebung gejagt.

Und was hat man nun davon?

Mit dem TFS Deployer haben Nutzer des TFS eine einfache Möglichkeit, benannte Softwarestände automatisch in verschiedene Umgebungen zu verteilen. Die dadurch entstehende Nachvollziehbarkeit lässt aus meiner Erfahrung Kunden und somit auch die Projektverantwortlichen im internen Team besser schlafen.

Ein wenig schade ist, dass man innerhalb des TFS zwar verschiedene Buildqualitäten, jedoch keine Regeln für gültige Übergänge anlegen kann. Da unsere Scripte jedoch auf festen Übergängen definieren bedeutet dies, dass derjenige, der die Buildqualität setzt, genau wissen muss welche Übergänge gültig sind. Schaltet er nämlich zum Beispiel von Test direkt auf Produktion passiert nämlich nichts.

Angeregt zu diesem Blog Post hat mich übrigens Robert Mühsigs Posts Build / Deployment / WTF.



blog.codemurai.de © André Krämer |Impressum | Abonieren

Ihre Meinung zum Windows 7 Logo Programm ist gefragt!

24.03.2010 22:06:44 | Peter Kirchner

win7_compat_smDies ist Ihre Chance, Einfluss auf das Windows 7 Logo Programm zu nehmen! Sie haben auch bereits Ihre Software Windows 7 Logo getestet oder sind gerade im Begriff dies zu tun, dann nehmen Sie diese Gelegenheit wahr, an dieser kurzen Umfrage teilzunehmen!

Noch bis zum 2. April haben Sie unter dem folgenden Link, die Möglichkeit Ihre Meinung abzugeben. Am besten Sie machen gleich mit. Die Umfrage dauert keine fünf Minuten!

Zur Umfrage: http://www.zoomerang.com/Survey/?p=WEB22AC5Z28EFX

Auf die Plätze, fertig, Anmelden: Die xtopia[kompakt] Roadshow 2010!

24.03.2010 13:22:54 | Jan Schenk



tweetmeme_url = 'http://blogs.msdn.com/jansche/archive/2010/03/24/auf-die-pl-tze-fertig-anmelden-die-xtopia-kompakt-roadshow-2010.aspx'; tweetmeme_source = 'jansche';

Xtopia-kompakt-Logo-schwarzDie xtopia[kompakt] Roadshow geht in die nächste Runde und Sie können dabei sein! Erleben Sie einen spannenden Abend mit interessanten Vorträgen zu Webdesign, RIA, Silverlight, User Experience und vieles, vieles mehr – und das Ganze kostenlos!

In insgesamt sechs Städten in Deutschland haben Sie die Möglichkeit an einer der Abendveranstaltungen teilzunehmen. Beginn ist jeweils 17 Uhr, Ende gegen 22.30 Uhr. Neben den Sessions wird es Gelegenheit geben, bei Getränken und Snacks sich untereinander auszutauschen und zu “networken”.

Die Sprecher

imageimageimageimage

Es erwartet Sie ein bunter Mix an Themen. In verschiedenen Sessions werden Microsoft-Sprecher über alle Innovationen aus dem Bereich Web, Design, Usability und RIA sprechen. Darüberhinaus werden Kreativagenturen, wie Ergosin, UID, Designaffairs, UCD Plus und Neon Red vom Praxis-Einsatz neuester Technologien berichten. Das Usability Team der Nero AG wird des weiteren über den Einsatz von Microsoft Expression Studio im Entwicklungsprozess der neuen Version ihrer Brennsuite sprechen. 

image imageimage

Themengebiete

Jan Schenk (Microsoft): Heiter trotz wolkig - Cloud Computing mit Windows Azure

Cloud Computing ist in aller Munde. Das Konzept und die Philosophie hinter Windows Azure sehen Sie hier im Schnelldurchlauf: Für welche Einsatzbereiche macht Cloud Computing wirklich Sinn? Wann rechnet sich Windows Azure? Gehen Sie in dieser Session auf Tuchfühlung mit der Wolke!

Frank Prengel (Microsoft): Windows Phone – neue Ansätze, neue Möglichkeiten

Kurzinhalt: Das Jahr 2010 wird viele signifikante Neuerungen für Windows Phones bringen – für Anwender, Entwickler und Designer. Diese Session vermittelt Ihnen in komprimierter Form, wie Microsoft seine mobile Plattform auffrischt und Maßstäbe im Smartphone-Bereich setzen wird.

Oliver Scheer (Microsoft): Silverlight 4 – Die Highlights

Rich Internet Applications mit Microsoft Silverlight: Einfach, Schnell und Beeindruckend. Silverlight 4 bringt eine Fülle von neuen Möglichkeiten mit und macht das Entwickeln und Designen von interaktiven Webanwendungen noch einfacher. Dieser Vortrag zeigt die Highlights der neuen Version von Silverlight.

Tom Wendel (Microsoft): SharePoint 2010 spricht Silverlight

Mit der Einführung von SharePoint 2010 wächst zusammen, was zusammen gehört. Mit Hilfe von Silverlight lassen sich Daten in SharePoint perfekt visualisieren. Eine nahtlose Integration der beiden Technologien verschafft völlig neue Möglichkeiten – sei es direkt als Webpart oder als eigenständige Silverlight-Anwendung.

Clemens Lutsch & verschiedene Kreativagenturen: Silverlight & WPF in der Design-Praxis

Führende Design-Agenturen berichten von Erfahrungen mit WPF & Silverlight in aktuellen, innovativen Projekten. So erfahren Sie aus erster Hand, wie moderne UX mit modernen Tools entsteht.

Georg Christoph, Nero AG: Microsoft Expression im Einsatz bei Nero

Wie Expression dabei hilft, Brücken zwischen Usability, Design und Entwicklung zu bauen.

Zur Anmeldung 

Jetzt heißt es schnell sein: Suchen Sie sich Ihre Lieblingsstadt aus und reservieren Sie sich sofort einen der begehrten Plätze.

Montag, 19.04.2010

München

Hilton München Park, Am Tucherpark 7, 80538 München

Zur Anmeldung

image

 

Dienstag, 20.04.2010

Karlsruhe

Best Western Karlsruhe, Ettlingerstr. 23, 76137 Karlsruhe

Zur Anmeldung

image

 

Mittwoch, 21.04.2010

Frankfurt / Bad Homburg

Maritim Bad Homburg, Ludwigstraße 3, 61348 Bad Homburg

Zur Anmeldung

image

 

Montag, 26.04.2010

Köln

Leonardo Hotel Köln, Waldecker Straße 11-15, 51065 Köln

Zur Anmeldung

image

 

Dienstag, 27.04.2010

Hamburg

Baseler Hof Hamburg, Esplanade 11, 20354 Hamburg

Zur Anmeldung

image

 

Mittwoch, 28.04.2010

Berlin

Mövenpick Berlin, Schöneberger Straße 3, 10963 Berlin

Zur Anmeldung

 image

 

Weitere Informationen zu den einzelnen Sessions, detaillierte Agendas, News zu den Sprechern und vieles mehr finden Sie exklusiv hier im Silverlight & Expression Team Blog. Also am Besten direkt den Feed abonnieren und immer auf dem Laufenden bleiben.

PC-WELT-Interview mit Oliver Scheer zum Thema Internet Explorer 9

24.03.2010 10:30:55 | Jan Schenk



tweetmeme_url = 'http://blogs.msdn.com/jansche/archive/2010/03/24/pc-welt-interview-mit-oliver-scheer-zum-thema-internet-explorer-9.aspx'; tweetmeme_source = 'jansche';

Ein nettes Interview des PC-WELT-Redakteurs Panagiotis Kolokythas mit meinem Evangelisten-Kollegen Oliver Scheer. Im Fokus: die Technologie-Vorschau des Internet Explorer 9 (IE9). Eine interessante Vorstellung der neuen Features, vor allem bezüglich der Standardkonformität und der GPU-Unterstützung.

Daily Demos: Silverlight Deep Zoom Randomizing Images

24.03.2010 08:00:00 | Oliver Scheer

Deep Zooms in Silverlight are great. On key feature is, that you have access to every sub image. So … why don’t we use this with animations?

image

Live Preview

XAML-Code

<UserControl
    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"
    mc:Ignorable="d"
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    xmlns:TheOliver_Controls="clr-namespace:TheOliver.Controls"
    x:Class="DeepZoomMouseBehavior.MainPage"
    d:DesignHeight="300"
    d:DesignWidth="400">

    <Grid
        x:Name="LayoutRoot"
        Background="White">
        <TextBlock
            Text="Deep Zoom Sample" />
        <MultiScaleImage
            x:Name="_msi"
            Source="Images/dzc_output.xml"
            Margin="0,19,0,0">
            <i:Interaction.Behaviors>
                <TheOliver_Controls:DeepZoomBehavior />
            </i:Interaction.Behaviors>
        </MultiScaleImage>
        <Button
            x:Name="_home"
            HorizontalAlignment="Right"
            VerticalAlignment="Top"
            Width="53"
            Content="Home">
            <i:Interaction.Triggers>
                <i:EventTrigger
                    EventName="Click">
                    <TheOliver_Controls:DeepZoomNavigateHomeBehavior
                        TargetName="_msi" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>
        <Button
            x:Name="_shuffle"
            HorizontalAlignment="Right"
            VerticalAlignment="Top"
            Width="53"
            Content="Shuffle"
            Margin="0,0,57,0">
            <i:Interaction.Triggers>
                <i:EventTrigger
                    EventName="Click">
                    <TheOliver_Controls:DeepZoomRandomImageArrangeBehavior
                        TargetName="_msi"
                        XOffset="1"
                        YOffset="1" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>
    </Grid>
</UserControl>

Sourcecode

// Copyright © Microsoft Corporation.  All Rights Reserved.
// This code released under the terms of the 
// Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;
using System.Windows.Media.Animation;

namespace TheOliver.Controls
{
    public class DeepZoomRandomImageArrangeBehavior : TargetedTriggerAction<MultiScaleImage>
    {
        private List<MultiScaleSubImage> _randomList = new List<MultiScaleSubImage>();

        int _totalColumns = 0;
        int _totalRows = 0;

        private MultiScaleImage _msi;

        public double XOffset
        {
            get { return (double)GetValue(XOffsetProperty); }
            set { SetValue(XOffsetProperty, value); }
        }

        public static readonly DependencyProperty XOffsetProperty = 
            DependencyProperty.Register(
                "XOffset", typeof(double), 
                typeof(DeepZoomRandomImageArrangeBehavior), 
                new PropertyMetadata(1.25, XOffsetChanged));

        private static void XOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {

        }

        public double YOffset
        {
            get { return (double)GetValue(YOffsetProperty); }
            set { SetValue(YOffsetProperty, value); }
        }

        public static readonly DependencyProperty YOffsetProperty = 
            DependencyProperty.Register(
                "YOffset", 
                typeof(double),
                typeof(DeepZoomRandomImageArrangeBehavior), 
                new PropertyMetadata(1.25, YOffsetChanged));

        private static void YOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {

        }

        public int Speed
        {
            get { return (int)GetValue(SpeedProperty); }
            set { SetValue(SpeedProperty, value); }
        }

        public static readonly DependencyProperty SpeedProperty = 
            DependencyProperty.Register(
                "Speed", 
                typeof(int),
                typeof(DeepZoomRandomImageArrangeBehavior), 
                new PropertyMetadata(1000, SpeedChanged));

        private static void SpeedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {

        }

        protected override void Invoke(object o)
        {
            _msi = this.Target;
            ArrangeIntoGrid();
        }

        private void ArrangeIntoGrid()
        {
            _randomList = RandomizedListOfImages();

            int totalImagesAdded = 0;
            double totalWidth = 0;
            double xoffset = XOffset;
            double yoffset = YOffset;
            double margin = .1;

            if (_randomList.Count > 1)
            {
                int numberOfImages = _randomList.Count;
                _totalColumns = 0;
                _totalColumns = (int)Math.Ceiling(Math.Sqrt(numberOfImages));
                _totalRows = numberOfImages / (_totalColumns - 1);
                totalWidth = _totalColumns * xoffset;

                Storyboard moveStoryboard = new Storyboard();

                for (int row = 0; row < _totalRows; row++)
                {
                    for (int col = 0; col < _totalColumns; col++)
                    {
                        if (numberOfImages != totalImagesAdded)
                        {
                            MultiScaleSubImage currentImage = _randomList[totalImagesAdded];
                            currentImage.ViewportWidth = 1;

                            Point currentPosition = new Point(0, 0);
                            Point futurePosition = new Point(-xoffset * col, -yoffset * row);

                            // Create Animation
                            PointAnimationUsingKeyFrames moveAnimation = new PointAnimationUsingKeyFrames();

                            // Create Keyframe
                            SplinePointKeyFrame startKeyframe = new SplinePointKeyFrame();
                            startKeyframe.Value = currentPosition;
                            startKeyframe.KeyTime = KeyTime.FromTimeSpan(TimeSpan.Zero);

                            startKeyframe = new SplinePointKeyFrame();
                            startKeyframe.Value = futurePosition;
                            startKeyframe.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(Speed));

                            KeySpline ks = new KeySpline();
                            ks.ControlPoint1 = new Point(0, 1);
                            ks.ControlPoint2 = new Point(1, 1);
                            startKeyframe.KeySpline = ks;
                            moveAnimation.KeyFrames.Add(startKeyframe);

                            Storyboard.SetTarget(moveAnimation, currentImage);

                            Storyboard.SetTargetProperty(moveAnimation, new PropertyPath("ViewportOrigin"));

                            moveStoryboard.Children.Add(moveAnimation);

                            totalImagesAdded++;
                        }
                        else
                        {
                            break;
                        }
                    }
                }

                if (!_msi.Resources.Contains("myAnim"))
                {
                    _msi.Resources.Add("myAnim", moveStoryboard);
                }

                this._msi.ViewportOrigin = new Point(-margin, -margin);
                this._msi.ViewportWidth = totalWidth + margin;

                // Play Storyboard
                moveStoryboard.Begin();
            }
            else
            {
                MultiScaleSubImage currentImage = _randomList[0];
                currentImage.ViewportWidth = 1 + 2 * margin;
                currentImage.ViewportOrigin = new Point(0, 0);
                this._msi.ViewportOrigin = new Point(-margin, -margin);
                this._msi.ViewportWidth = 1;
            }
        }

        private List<MultiScaleSubImage> RandomizedListOfImages()
        {
            List<MultiScaleSubImage> imageList = new List<MultiScaleSubImage>();
            Random ranNum = new Random();

            // Store List of Images
            foreach (MultiScaleSubImage subImage in _msi.SubImages)
            {
                subImage.Opacity = 1;
                imageList.Add(subImage);
            }

            int numImages = imageList.Count;

            // Randomize Image List
            for (int a = 0; a < numImages; a++)
            {
                MultiScaleSubImage tempImage = imageList[a];
                imageList.RemoveAt(a);

                int ranNumSelect = ranNum.Next(imageList.Count);

                imageList.Insert(ranNumSelect, tempImage);
            }

            return imageList;
        }
    }
}

 

Solutiondownload

CSS File Size Limit in Internet Explorer 6 / 7 / 8

24.03.2010 07:16:00 | Andreas Mehl

The last days I have encountered a problem in IE where it seemed as if some parts of my CSS was not loaded.

I pursued the issue down. So it seems to be a size limit of ~ 288Kb for a CSS file.

In IE only the first in a 288Kb file will be read and processed. Each CSS to 288Kb will be ignored.

In this particular case I was loading a CSS file of 347Kb.

Firefox and other browsers seem to have no limit.

The border seems to be a "per-file limit. You can use the CSS divided into two files and it will work.

You might ask yourself why you would ever have a CSS file, 347Kb is? Good question ... But we have a large file to use in our website design application.

The CSS ends up being gzipped and is only 45kb, when you download it when loading the designer.

MSDN TV - Interview meinerseits bei DNUG München

24.03.2010 05:54:00 | Gregor Biswanger

Am 15.02.2010 hielt ich den Vortrag: „Zurück in die Zukunft mit Silverlight 4“, bei der .NET User Group München. MSDN TV mit Jan Schenk (Der Evangelist mit dem Hut, www.der-evangelist.de) interviewte mich zum Thema Silverlight und meinen Community Aktivitäten.

Die Folge kann sich hier jederzeit kostenfrei angesehen werden:

(http://www.microsoft.com/germany/msdn/video/show.mspx?id=msdn_de_39167)

Hier nochmal ein paar Impressionen von der gut besuchten Veranstaltung: 
http://www.der-evangelist.de/2010/02/dnug-mnchen-msdn-tv-war-dabei-15-02-2010/ 

Vielen Dank nochmal an Jan Schenk und Cortessa Kostis, es hatte mir sehr viel Spaß gemacht mit euch.

Artikel auf der offiziellen Microsoft ASP.NET Seite

23.03.2010 15:20:14 | Andre Kraemer

Cool, mein Blogeintrag zum Thema Viewstate hat es auf die offizielle Microsoft ASP.NET Seite geschaft. Nun ja, zumindest auf die deutsche Variante davon :-)



blog.codemurai.de © André Krämer |Impressum | Abonieren

Die xtopia[kompakt] Roadshow 2010!

23.03.2010 10:23:38 | Oliver Scheer

Xtopia-kompakt-Logo-schwarzDie xtopia[kompakt] Roadshow geht in die nächste Runde und Sie können dabei sein! Erleben Sie einen spannenden Abend mit interessanten Vorträgen zu Webdesign, RIA, Silverlight, User Experience und vieles, vieles mehr – und das Ganze kostenlos!

In insgesamt sechs Städten in Deutschland haben Sie die Möglichkeit an einer der Abendveranstaltungen teilzunehmen. Beginn ist jeweils 17 Uhr, Ende gegen 22.30 Uhr. Neben den Sessions wird es Gelegenheit geben, bei Getränken und Snacks sich untereinander auszutauschen und zu “networken”.

Die Sprecher

imageimageimage

image

 

 

 

Es erwartet Sie ein bunter Mix an Themen. In verschiedenen Sessions werden Microsoft-Sprecher über alle Innovationen aus dem Bereich Web, Design, Usability und RIA sprechen. Darüberhinaus werden Kreativagenturen, wie Ergosin, UID, Designaffairs, UCD Plus und Neon Red vom Praxis-Einsatz neuester Technologien berichten. Das Usability Team der Nero AG wird des weiteren über den Einsatz von Microsoft Expression Studio im Entwicklungsprozess der neuen Version ihrer Brennsuite sprechen. 

image imageimage

Themengebiete

Jan Schenk (Microsoft): Heiter trotz wolkig - Cloud Computing mit Windows Azure

Cloud Computing ist in aller Munde. Das Konzept und die Philosophie hinter Windows Azure sehen Sie hier im Schnelldurchlauf: Für welche Einsatzbereiche macht Cloud Computing wirklich Sinn? Wann rechnet sich Windows Azure? Gehen Sie in dieser Session auf Tuchfühlung mit der Wolke!

Frank Prengel (Microsoft): Windows Phone – neue Ansätze, neue Möglichkeiten

Kurzinhalt: Das Jahr 2010 wird viele signifikante Neuerungen für Windows Phones bringen – für Anwender, Entwickler und Designer. Diese Session vermittelt Ihnen in komprimierter Form, wie Microsoft seine mobile Plattform auffrischt und Maßstäbe im Smartphone-Bereich setzen wird.

Oliver Scheer (Microsoft): Silverlight 4 – Die Highlights

Rich Internet Applications mit Microsoft Silverlight: Einfach, Schnell und Beeindruckend. Silverlight 4 bringt eine Fülle von neuen Möglichkeiten mit und macht das Entwickeln und Designen von interaktiven Webanwendungen noch einfacher. Dieser Vortrag zeigt die Highlights der neuen Version von Silverlight.

Tom Wendel (Microsoft): SharePoint 2010 spricht Silverlight

Mit der Einführung von SharePoint 2010 wächst zusammen, was zusammen gehört. Mit Hilfe von Silverlight lassen sich Daten in SharePoint perfekt visualisieren. Eine nahtlose Integration der beiden Technologien verschafft völlig neue Möglichkeiten – sei es direkt als Webpart oder als eigenständige Silverlight-Anwendung.

Clemens Lutsch & verschiedene Kreativagenturen: Silverlight & WPF in der Design-Praxis

Führende Design-Agenturen berichten von Erfahrungen mit WPF & Silverlight in aktuellen, innovativen Projekten. So erfahren Sie aus erster Hand, wie moderne UX mit modernen Tools entsteht.

Georg Christoph, Nero AG: Microsoft Expression im Einsatz bei Nero

Wie Expression dabei hilft, Brücken zwischen Usability, Design und Entwicklung zu bauen.

Zur Anmeldung 

Jetzt heißt es schnell sein: Suchen Sie sich Ihre Lieblingsstadt aus und reservieren Sie sich sofort einen der begehrten Plätze.

Montag, 19.04.2010

München

Hilton München Park, Am Tucherpark 7, 80538 München

Zur Anmeldung

image

Dienstag, 20.04.2010

Karlsruhe

Best Western Karlsruhe, Ettlingerstr. 23, 76137 Karlsruhe

Zur Anmeldung

image

Mittwoch, 21.04.2010

Frankfurt / Bad Homburg

Maritim Bad Homburg, Ludwigstraße 3, 61348 Bad Homburg

Zur Anmeldung

image

Montag, 26.04.2010

Köln

Leonardo Hotel Köln, Waldecker Straße 11-15, 51065 Köln

Zur Anmeldung

image

Dienstag, 27.04.2010

Hamburg

Baseler Hof Hamburg, Esplanade 11, 20354 Hamburg

Zur Anmeldung

image

Mittwoch, 28.04.2010

Berlin

Mövenpick Berlin, Schöneberger Straße 3, 10963 Berlin

Zur Anmeldung

image

Weitere Informationen zu den einzelnen Sessions, detaillierte Agendas, News zu den Sprechern und vieles mehr finden Sie exklusiv hier im Silverlight & Expression Team Blog. Also am Besten direkt den Feed abonnieren und immer auf dem Laufenden bleiben.

Schöne Grüße

TheOliver

Umgang mit Multivalued Fields in Importen

23.03.2010 08:02:00 | Martin Hey

Ein Feature von Access 2007, das wohl besonders die Umschwenker von Excel freut, sind Multivalued Fields. Man kann damit innerhalb einer Tabellenspalte eine Mehrfachauswahl abbilden - etwas wofür man im Datenbankdesign wie wir es alle kennen mindestens 3 Tabellen verwenden würden. Und sie sind ja auch so einfach zu erstellen: Man muss einfach nur im Tabellendesigner bei Mehrere Werte zulassen den Haken setzen.
So bequem dieses Feature für Endanwender ist, so unbequem ist es für Entwickler, denn man muss schon sehr schmerzresistent sein, wenn man auf eine Tabelle mit einem Multivalued Field trifft. Man könnte schon fast sagen, man hat es hier mit einer kleinen Prinzessin zu tun, die auch wie eine solche behandelt werden möchte.
Aktuelles Beispiel für diese These ist der Import solcher Felder. Das Szenario ist leicht erklärt: Eine Anwendung auf der Basis von Access 2007 bekommt ein neues Feature und das Datenmodell ändert sich insofern als dass ein neues Feld in der Tabelle notwendig wird. Schön für den Endanwender ist es nun, wenn es eine Importroutine gibt, die die Daten aus der alten Datenstruktur in die neue Struktur übernehmen kann. An und für sich ist das mit Access kein Problem, denn Access kennt ja Remote Queries:
Private Sub Import(source As String)
CurrentDb.Execute "INSERT INTO SimpleTable SELECT * FROM SimpleTable IN """ & source & """"
End Sub
Das geht so lange gut, bis man auf eine Tabelle mit einem Multivalued Field trifft, denn plötzlich sind Remote Queries nicht mehr möglich.

Einen entsprechenden Versuch wird Access nicht dulden.

Dabei ist diese Meldung unabhängig davon, ob man das Multivalued Field wirklich mit abfragt oder nicht - man bekommt immer wieder diese Meldung.

Nun gibt es in meinen Augen 3 Lösungsansätze:
  1. Der Kunde gibt einfach alle Daten nochmal manuell ein. Ok, dazu wird er sicher nicht bereit sein, aber anscheinend ist es das was in dem Fall die naheliegendste Lösung ist, wenn sich Access so hartnäckig sträubt.
  2. Man könnte über Externe Daten eine Tabelle der alten Datenbank mit der neuen Datenbank verknüpfen und hätte damit dann ein INSERT-INTO-Statement, das sich nur auf die aktuelle Datenbank bezieht, da die verknüpfte Tabelle sich wie eine in der Datenbank befindliche Tabelle verhält. Schön automatisieren lässt sich das aber auch nicht. Das wäre also der halbautomatische Weg.
  3. Möchte man den vollautomatischen Weg gehen, kommt man wohl nicht drum herum, die Daten feldweise zu übernehmen und mit Recordsets zu hantieren.
Für Tor Nummer 3 hab ich mich letztendlich auch entschieden:
Private Sub Import(source As String)
Dim wrksp As DAO.Workspace
Set wrksp = DBEngine.Workspaces(0)

On Error GoTo Err_Import
' open transaction
wrksp.BeginTrans

' import a simple table
CurrentDb.Execute "INSERT INTO SimpleTable SELECT * FROM SimpleTable IN """ & source & """"

' import table with multivalued field
Dim otherDB As DAO.Database, otherRS As DAO.Recordset, currentRS As DAO.Recordset
Dim i As Long

' open recordsets to read data from old database and append it to current database
Set otherDB = DBEngine.OpenDatabase(source)
Set otherRS = otherDB.OpenRecordset("MVFTable")
Set currentRS = CurrentDb.OpenRecordset("MVFTable")

' loop records in old data and add a new record in current db for each record in old db
While Not otherRS.EOF
currentRS.AddNew
' iterate through the old fields and update the value in current record
For i = 0 To otherRS.Fields.Count - 1
If otherRS.Fields(i).Name <> "MFVField" Then
currentRS(otherRS.Fields(i).Name) = otherRS(otherRS.Fields(i).Name)
End If
Next
currentRS.Update
otherRS.MoveNext
Wend

' close the recordsets
currentRS.Close
otherRS.Close

' open a recordset for the values of the multi valued field
Set otherRS = otherDB.OpenRecordset("SELECT Id, MVFField.Value FROM MVFTable")
While Not otherRS.EOF
If Not IsNull(otherRS.Fields(1)) Then
' insert selected values of the multivalued field
CurrentDb.Execute "INSERT INTO MVFTable (MVFField.Value) VALUES (" & otherRS.Fields(1) & ") WHERE Id = " & otherRS.Fields(0)
End If
otherRS.MoveNext
Wend

' close the recordset
otherRS.Close

' commit transaction
wrksp.CommitTrans

MsgBox "Import erfolgreich beendet"
Exit Sub

Err_Import:
' rollback transaction
wrksp.Rollback
MsgBox "Import ist fehlgeschlagen"
End Sub
Wie man gut sehen kann, muss man bei dieser Lösung statt eines einzigen SQL Statements (im Beispiel der Import von SimpleTable) eine ganze Routine schreiben und die Tabelle mehrfach anfassen, weil das MultiValued Field quasi eine Tabelle in der Tabelle ist und mit einer speziellen Syntax befüllt werden möchte.

Ich hätte mir gewünscht, dass Features, auch wenn sie nicht Standard-SQL-konform sind, sich doch zumindest so verhalten, wie man es vom Rest der Applikation gewohnt ist - und dazu gehört in meinen Augen auch die Möglichkeit, bei Multivalued Fields Remote Queries zuzulassen.

Daily Demos: Silverlight Deep Zoom Navigate Home Behavior

23.03.2010 08:00:00 | Oliver Scheer

A common used feature in Deep Zoom Images is the “Home” Feature. If you zoom deep into an image you might get lost ;-). But don’t be afraid. The following behavior applied to you MultiScaleImage bring you back to the origin position (Home) of your image.

 

image

Livepreview

 

XAML-Code

<UserControl
    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"
    mc:Ignorable="d"
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    xmlns:TheOliver_Controls="clr-namespace:TheOliver.Controls"
    x:Class="DeepZoomMouseBehavior.MainPage"
    d:DesignHeight="300"
    d:DesignWidth="400">

    <Grid
        x:Name="LayoutRoot"
        Background="White">
        <TextBlock
            Text="Deep Zoom Sample" />
        <MultiScaleImage
            x:Name="_msi"
            Source="Images/dzc_output.xml"
            Margin="0,19,0,0">
            <i:Interaction.Behaviors>
                <TheOliver_Controls:DeepZoomBehavior />
            </i:Interaction.Behaviors>
        </MultiScaleImage>
        <Button
            HorizontalAlignment="Right"
            VerticalAlignment="Top"
            Width="53"
            Content="Home">
            <i:Interaction.Triggers>
                <i:EventTrigger
                    EventName="Click">
                    <TheOliver_Controls:DeepZoomNavigateHomeBehavior
                        TargetName="_msi" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>
    </Grid>
</UserControl>

 

Sourcecode for Behavior

// Copyright © Microsoft Corporation.  All Rights Reserved.
// This code released under the terms of the 
// Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)

using System.Windows.Interactivity;
using System.Windows;
using System.Windows.Controls;

namespace TheOliver.Controls
{
    public class DeepZoomNavigateHomeBehavior : TargetedTriggerAction<MultiScaleImage>
    {
        MultiScaleImage msi;

        protected override void Invoke(object parameter)
        {
            msi = this.Target as MultiScaleImage;
            
            msi.ViewportWidth = 1;
            msi.ViewportOrigin = new Point(0, 0);
        }
    }
}

 

 

Solutiondownload

Daily Demos: Deep Zoom Mouse Zoom Features

22.03.2010 08:15:00 | Oliver Scheer

Deep Zoom is brilliant, awesome, super exciting … I LOVE DEEP ZOOM. And I love to create my own applications based on Deep Zoom. In Silverlight you can use Deep Zoom with the MultiScaleImage-Control. The challenge is, it doesn’t bring support for navigation in a deep zoom image. So you have to do it by yourself … or better use a Behavior for this features.

image

Live Preview

 

XAML-Code

<UserControl
    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"
    mc:Ignorable="d"
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    xmlns:TheOliver_Controls="clr-namespace:TheOliver.Controls"
    x:Class="DeepZoomMouseBehavior.MainPage"
    d:DesignHeight="300"
    d:DesignWidth="400">

    <Grid
        x:Name="LayoutRoot"
        Background="White">
        <TextBlock
            Text="Deep Zoom Sample" />
        <MultiScaleImage
            x:Name="_msi"
            Source="Images/dzc_output.xml"
            Margin="0,12,0,0">
            <i:Interaction.Behaviors>
                <TheOliver_Controls:DeepZoomBehavior />
            </i:Interaction.Behaviors>
        </MultiScaleImage>
    </Grid>
</UserControl>

Sourcecode

// Copyright © Microsoft Corporation.  All Rights Reserved.
// This code released under the terms of the 
// Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;

namespace TheOliver.Controls
{
    public class DeepZoomBehavior : Behavior<MultiScaleImage>
    {
        MultiScaleImage _msi;
        Point _lastMousePos = new Point();
        double _zoom = 1;
        bool _mouseButtonPressed = false;
        bool _mouseIsDragging = false;
        Point _dragOffset;
        Point _currentPosition;

        private double ZoomFactor
        {
            get { return _zoom; }
            set { _zoom = value; }
        }

        protected override void OnAttached()
        {
            _msi = this.AssociatedObject;
           
            _msi.MouseMove += delegate(object sender, MouseEventArgs e)
            {
                if (_mouseButtonPressed)
                {
                    _mouseIsDragging = true;
                }
                _lastMousePos = e.GetPosition(_msi);
            };

            _msi.MouseLeftButtonDown += delegate(object sender, MouseButtonEventArgs e)
            {
                _mouseButtonPressed = true;
                _mouseIsDragging = false;
                _dragOffset = e.GetPosition(_msi);
                _currentPosition = _msi.ViewportOrigin;
            };

            _msi.MouseLeave += delegate(object sender, MouseEventArgs e)
            {
                _mouseIsDragging = false;
            };

            _msi.MouseLeftButtonUp += delegate(object sender, MouseButtonEventArgs e)
            {
                _mouseButtonPressed = false;
                if (_mouseIsDragging == false)
                {
                    bool shiftDown = (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift;

                    ZoomFactor = 2.0;
                    if (shiftDown) ZoomFactor = 0.5;
                    Zoom(ZoomFactor, _lastMousePos);
                }
                _mouseIsDragging = false;
            };

            _msi.MouseMove += delegate(object sender, MouseEventArgs e)
            {
                if (_mouseIsDragging)
                {
                    Point newOrigin = new Point();
                    newOrigin.X = _currentPosition.X - (((e.GetPosition(_msi).X - _dragOffset.X) / _msi.ActualWidth) * _msi.ViewportWidth);
                    newOrigin.Y = _currentPosition.Y - (((e.GetPosition(_msi).Y - _dragOffset.Y) / _msi.ActualHeight) * _msi.ViewportWidth);
                    _msi.ViewportOrigin = newOrigin;
                }
            };

            _msi.MouseWheel += (s,e) =>
                {
                e.Handled = true;
                if (e.Delta > 0)
                {
                    ZoomFactor = 1.2;
                }
                else
                {
                    ZoomFactor = .80;
                }

                Zoom(ZoomFactor, _lastMousePos);
            };
        }

        public void Zoom(double zoom, Point pointToZoom)
        {
            Point logicalPoint = _msi.ElementToLogicalPoint(pointToZoom);
            _msi.ZoomAboutLogicalPoint(zoom, logicalPoint.X, logicalPoint.Y);
        }

    }
}

 

Solutiondownload

Daily Demos: Week Summary

22.03.2010 08:00:00 | Oliver Scheer

Last week I started my daily demo challenge. The Result, five simple, and easy to use samples for Silverlight.

15.03.2010 – Silverlight 3: Text Tipping Control // [Preview]

16.03.2010 – Silverlight 3: Image Spindle // [Preview]

17.03.2010 – Silverlight 3: Image Stack // [Preview]

18.03.2010 – Silverlight 3: Behavior - 3D Hover Effect // [Preview]

19.03.2010 – Silverlight 3: Trigger Action – Fullscreen // [Preview]

If you have any suggestions and comments, please feel free to comment.

Best regards,
The-Oliver

Office 2010 Developer Atlas – Eine Übersicht für Entwickler

21.03.2010 03:50:00 | Lars Keller

Mit dem Office 2010 Developer Atlas hat Microsoft eine Übersicht für Entwickler geschaffen. Die Seite ist in verschiedene Bereiche der Office 2010 Entwicklung unterteilt. Hier drunter zählen die Ribbon, der Backstage-Bereich sowie das Backend.

Die Seite dient auch als gutes Nachschlagewerk, wenn man mal eben den richtigen XML Tag benötigt.,

Neue MSDN-TV Folge Online

19.03.2010 16:21:33 | Oliver Scheer

In der heutigen Ausgabe von msdn tv – Nachrichten für Entwickler ist Jan Schenk nach kurzem Aufenthalt unter Palmen zu Gast bei der DNUG München, der DotNET Usergroup München (http://www.munichdot.net/). Im Interview ist Hardy Erlinger, Gründer der Münchner Usergroup und Leiter der INETA Deutschland (http://ineta-germany.org), und Gregor Biswanger, Silverlight-Abhängiger und Referent auf dem Usergroup-Treffen. Ausserdem gibt es in den Fast Facts of the Week wieder viel Neues zu Dariusz Parys Tutorialserie über Visual Studio 2010, der Beta 2 der Windows Server AppFabric, einer Webcastreihe von Holger Sirtl zum Thema Windows Azure Platform und der Microsoft Roadshow "Zwanzig Zehn" zum Launch von Visual Studio 2010 am 12. April. Ausserdem ein Terminhinweis auf Tom Wendels TechTalk-Runde quer durch Deutschland zum neuen Sharepoint 2010.
Mit welcher Kopfbedeckung, welchen Versprechern und welchem Set msdn tv seine Zuschauer heute überrascht lässt sich nicht in Textform fassen. Um es mit wenigen Worten zu sagen: Die heutige Ausgabe ist die Überlänge wert. Die Gesamtspieldauer des Director’s Cut sind heute ganze 20 Minuten 38 Sekunden.

 

Daily Demo: Silverlight Fullscreen Trigger Action

19.03.2010 08:00:00 | Oliver Scheer

A common needed and used feature in Silverlight is the Fullscreen Mode. A feature to switch the current application from a hosted in browser to fullscreen mode. This features is interesting in scenarios like Point of Sales- or Games-Applications.

image

Normal Browser Mode

image

Full Screen Mode

Livepreview here

XAML-Code

<UserControl x:Class="FullScreenBehavior.MainPage"
    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"
    mc:Ignorable="d"
    xmlns:TheOliver_Controls="clr-namespace:TheOliver.Controls"
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">
        <Button
            Content="Button"
            Height="23"
            HorizontalAlignment="Left"
            Margin="10,10,0,0"
            Name="button1"
            VerticalAlignment="Top"
            Width="75">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <TheOliver_Controls:FullScreenAction/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
            
        </Button>
        <Rectangle Stroke="Black" Margin="155,113,141,110">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="MouseLeftButtonUp">
                    <TheOliver_Controls:FullScreenAction/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
            <Rectangle.Fill>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="Black" Offset="0"/>
                    <GradientStop Color="White" Offset="1"/>
                </LinearGradientBrush>
            </Rectangle.Fill>
        </Rectangle>
    </Grid>
</UserControl>

Sourcecode

// Copyright © Microsoft Corporation.  All Rights Reserved.
// This code released under the terms of the 
// Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)

using System.Windows;
using System.Windows.Interactivity;

namespace TheOliver.Controls
{
    public class FullScreenAction : TargetedTriggerAction<FrameworkElement>
    {
        protected override void Invoke(object o)
        {
            Application.Current.Host.Content.IsFullScreen =
                !Application.Current.Host.Content.IsFullScreen;
        }

    }
}

 

Solution download

WinDbg Videotutorial

19.03.2010 01:19:48 | Andre Kraemer

Vor einiger Zeit habe ich ein kurzes Tutorial zur Bedienung der Windows Debugging Tools hier in meinem Blog veröffentlicht.

Dieses Tutorial traf auf großen Anklang. Zumindest wenn ich meinen Statistiken trauen darf. Denn laut diesen kommen die meisten Besucher durch eine Google Suche nach WinDbg auf mein Blog.

Um dieser Tatsache gerecht zu werden, habe ich mich dazu entschlossen das ursprüngliche Tutorial nun auch als Video bereit zu stellen. Ich hoffe damit auch Gregor zufrieden zu stellen, der meinte dass die geschriebene Variante doch etwas schwierig zu befolgen wäre ;-)

-->

The Camtasia Studio video content presented here requires a more recent version of the Adobe Flash Player. If you are you using a browser with JavaScript disabled please enable it now. Otherwise, please update your version of the free Flash Player by downloading here.

-->

Über Kommentare und Rückfragen würde ich mich sowohl hier auf meinem Blog, als auch unter der im Video angegebenen E-Mail Adresse sehr freuen.

War dieser Eintrag hilfreich für dich? Dann kicke ihn doch bitte.



blog.codemurai.de © André Krämer |Impressum | Abonieren

Verwendung der Visual Studio 2010 Test und Lab Management Produkte in Microsoft

18.03.2010 16:21:17 | Christian Binder

Während der Entwicklung neuer Produkte werden diese schon in Pre-Release Stati intern eingesetzt, wir nennen diesen Prozess “Dogfooding” in Microsoft. Amit Chatterjee hat auf seinem Blog die Erfahrungen mit den neuen Visual Studio 2010 Test und Lab Management Produkte beschrieben :-)

image

Mehr gibt’s auf Amit’s Blog

Chris

Daily Demo: Silverlight Behavior for 3D Hover Effect

18.03.2010 08:00:00 | Oliver Scheer

Behaviors are great new feature in Silverlight 3 (or better in Blend 3) for adding “features” to a control without coding. My favorite sample is a hover effect, that applies when a mouse enters a control.

 

image

 

Live-Preview

 

XAML-Code:

 

<UserControl
    x:Class="Hover3DBehavior.MainPage"
    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"
    mc:Ignorable="d"
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    xmlns:TheOliver_Controls="clr-namespace:TheOliver.Controls"
    d:DesignHeight="300"
    d:DesignWidth="400"
    xmlns:dataInput="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.Input">

    <Grid
        x:Name="LayoutRoot"
        Background="White">
        <Button
            Content="Button"
            Height="23"
            HorizontalAlignment="Left"
            Margin="89,78,0,0"
            Name="button1"
            VerticalAlignment="Top"
            Width="75">
            <i:Interaction.Behaviors>
                <TheOliver_Controls:Hover3DBehavior />
            </i:Interaction.Behaviors>
        </Button>

        <dataInput:Label
            Height="50"
            HorizontalAlignment="Left"
            Margin="274,64,0,0"
            Name="label1"
            VerticalAlignment="Top"
            Width="100"
            Content="Hello World">
            <i:Interaction.Behaviors>
                <TheOliver_Controls:Hover3DBehavior />
            </i:Interaction.Behaviors>
        </dataInput:Label>

        <RadioButton
            Content="RadioButton"
            Height="16"
            HorizontalAlignment="Left"
            Margin="12,133,0,0"
            Name="radioButton1"
            VerticalAlignment="Top">
            <i:Interaction.Behaviors>
                <TheOliver_Controls:Hover3DBehavior />
            </i:Interaction.Behaviors>
        </RadioButton>

    </Grid>
</UserControl>

 

Source-Code:

 

// Copyright © Microsoft Corporation.  All Rights Reserved.
// This code released under the terms of the 
// Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)

using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interactivity;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace TheOliver.Controls
{
    public class Hover3DBehavior : Behavior<UIElement>
    {
        PlaneProjection _planeProjection;

        public Hover3DBehavior()
            : base()
        {
           
        }

        Storyboard _hoverMe;
        Storyboard _unhoverMe;

        public double ZHoverValue
        {
            get { return (double)GetValue(ZHoverValueProperty); }
            set { SetValue(ZHoverValueProperty, value); }
        }

        public static readonly DependencyProperty ZHoverValueProperty =
            DependencyProperty.Register("ZHoverValue", typeof(double), typeof(Hover3DBehavior),
            new PropertyMetadata(500.0, null));

        public int HoverDurationMilliseconds
        {
            get { return (int)GetValue(HoverDurationMillisecondsProperty); }
            set { SetValue(HoverDurationMillisecondsProperty, value); }
        }

        public static readonly DependencyProperty HoverDurationMillisecondsProperty =
            DependencyProperty.Register("HoverDurationMilliseconds"
            , typeof(int)
                , typeof(Hover3DBehavior),
                new PropertyMetadata(200, null));

        #region Overrides 

        protected override void OnAttached()
        {
            base.OnAttached();

            _planeProjection = new PlaneProjection();
            this.AssociatedObject.Projection = _planeProjection;

            if (!DesignerProperties.GetIsInDesignMode(this))
            {
                _hoverMe = new Storyboard();

                DoubleAnimation da1 = new DoubleAnimation();

                _hoverMe.Children.Add(da1);
                da1.Duration = new Duration(new System.TimeSpan(0, 0, 0, 0, HoverDurationMilliseconds));
                da1.To = this.ZHoverValue;
                Storyboard.SetTarget(da1, this.AssociatedObject);
                Storyboard.SetTargetProperty(da1, new PropertyPath("(UIElement.Projection).(PlaneProjection.LocalOffsetZ)"));

                DoubleAnimation da2 = new DoubleAnimation();
                BounceEase be2 = new BounceEase();
                be2.EasingMode = EasingMode.EaseOut;
                be2.Bounces = 3;
                da2.EasingFunction = be2;

                _unhoverMe = new Storyboard();
                _unhoverMe.Children.Add(da2);
                da2.Duration = new Duration(new System.TimeSpan(0, 0, 0, 0, 1000));
                da2.To = 0.0;
                Storyboard.SetTarget(da2, this.AssociatedObject);
                Storyboard.SetTargetProperty(da2, new PropertyPath("(UIElement.Projection).(PlaneProjection.LocalOffsetZ)"));

                if ((this.AssociatedObject as FrameworkElement).Resources.Contains("hoverme"))
                {
                    (this.AssociatedObject as FrameworkElement).Resources.Remove("hoverme");
                }
                (this.AssociatedObject as FrameworkElement).Resources.Add("hoverme", _hoverMe);
                
                if ((this.AssociatedObject as FrameworkElement).Resources.Contains("unhoverme"))
                {
                    (this.AssociatedObject as FrameworkElement).Resources.Remove("unhoverme");
                }
                (this.AssociatedObject as FrameworkElement).Resources.Add("unhoverme", _unhoverMe);
            }
            
            this.AssociatedObject.MouseEnter += AssociatedObject_MouseEnter;
            this.AssociatedObject.MouseLeave += AssociatedObject_MouseLeave;

        }
        
        protected override void OnDetaching()
        {
            base.OnDetaching();

            this.AssociatedObject.Projection = null;
            _planeProjection = null;

            this.AssociatedObject.MouseEnter -= AssociatedObject_MouseEnter;
            this.AssociatedObject.MouseLeave -= AssociatedObject_MouseLeave;
        }

        #endregion

        #region Events

        void AssociatedObject_MouseLeave(object sender, MouseEventArgs e)
        {
            _unhoverMe.Begin();
        }

        void AssociatedObject_MouseEnter(object sender, MouseEventArgs e)
        {
            //FrameworkElement e1 = this.AssociatedObject as FrameworkElement;
            //if (e1.Parent is Panel)
            //{
            //    Panel p = e1.Parent as Panel;
            //    if (p != null)
            //    {
            //        UIElement element = this.AssociatedObject;
            //        element.SetValue(UIElement.
            //        p.Children.Remove(element);
            //        p.Children.Add(element);
            //    }
            //}
            _hoverMe.Begin();
        }

        #endregion

    }
}

 

Download-SampleCode

Ein 26-Gigabyte großes Digitalbild von Paris

18.03.2010 02:14:33 | Oliver Scheer

Auf www.paris-26-gigapixels.com befindet sich das derzeit angeblich größte Digitalfoto. Aus 2346 Bilden wurde die Skyline von Paris zusammengesetzt.

image

Schon sehr beeindruckend. Allerdings frage ich mich warum man sich so einen riesigen Aufwand mit dem Zusammensetzen der Bilder macht, aber null Aufwand für einen gescheiten Player, der das Bild ordentlich darstellt.

Die Navigation ist sehr gewöhnungsbedürftig, übliche Verfahren wie Doppelklicks oder Mausrad funktionieren nicht. Entgegen allen üblichen Navigationen wandert man nach rechts in dem man die Maus nach links bewegt. Darüber hinaus explodiert quasi Speicherverbrauch der Webseite.

Wer so etwas auf einfache Art und Weise selber machen möchte, ohne wirklich selber viel Aufwand zu haben, kriegt dazu von Microsoft kostenlose Werkzeuge an die Hand gelegt.

Mit der Windows Live Fotogallerie gibt es eine sehr gute Bilderverarbeitung die für jeden Hobby- und semiprofessionellen Fotografen ausreicht. Die Fotogallerie hat eine tolle Funktion zum automatischen Zusammensetzen von vielen Bildern, die allerdings gewisse Überschneidungen haben müssen.

Hat man dann ein sehr großes Bild, dann kann man dieses mit dem Deep Zoom Composer so vorbereiten, das es sehr schnell von jedem Browser geladen werden kann. Diese Technik basiert auf Silverlight.

Die Tools sind kostenlos und gibt es hier:

Windows Live Fotogallerie

Deep Zoom Composer

Ein weiteres Tool das etwas technischer ist: Microsoft Research Image Composite Editor

Microsoft, Ajax und JQuery

17.03.2010 10:41:29 | Andre Kraemer

Wie Stephen Walter in seinem Blog angekündigt hat, stoppt Microsoft die Entwicklung des eigenen clientseitigen ASP.NET Ajax Library und steuert stattdessen Code zu jQuery bei. Bedeutet Microsoft hat jQuery nicht "übernommen", sondern steuert wie jeder andere einfach nur Quellcode bei bzw. schlägt Features vor, die anschließend durch das jQuery Team geprüft werden.

Da die Beta der ASP.NET Ajax Library nun bereits seit November verfügbar war, überraschte mich diese Ankündigung ein wenig. Andererseits fragte ich mich, je tiefer ich mich mit der Library beschäftigte, sowieso weshalb man den clientseitigen Teil neben jQuery überhaupt brauchen würde.

Jedem der sich nun genötigt fühlt, jQuery zu lernen, dem kann ich nur wärmstens Dave Wards Blog empfehlen. Außerdem ist seine Tekpub jQuery Serie die er gemeinsam mit James Avery aufzeichnet natürlich auch Pflichtprogramm.



blog.codemurai.de © André Krämer |Impressum | Abonieren

TT.DOM: Views, Teil 2

17.03.2010 08:30:00 | Jörg Neumann

Wie im ersten Teil bereits beschrieben, bietet TT.DOM ein View-Modell, das es ermöglicht beliebig viele Sichten auf eine Liste zu erzeugen. Während es zuletzt um die Möglichkeiten ging, Sortier- und Filterkriterien auf die View anzuwenden, möchte ich in diesem Post beschreiben, wie Sie die Darstellung einer View anpassen und um berechnete Spalten erweitern können.

Views anpassen

Wie hier bereit beschrieben, basiert die Anpassbarkeit der Views auf dem Interface ITypedList. Es definiert die GetItemProperties()-Methode, über die das gebundene Listensteuerelement Informationen über die Spalten der Datenquelle abfragt. Sie gibt eine Collection von PropertyDescriptor-Objekten zurück, welche die jeweiligen Eigenschaften beschreiben. Über einen PropertyDescriptor kann beispielsweise festgelegt werden, welchen Anzeigenamen eine Eigenschaft bei der Bindung annehmen soll, ob diese schreibgeschützt ist oder diese ausgeblendet werden soll. Diese Darstellungsmerkmale ermittelt die PropertyDescriptor-Klasse per Reflection aus der Datenklasse. In der Datenklasse können die Merkmale in Form von Attributen signalisiert werden:

[Browsable(false)]
public string Name { get; set; }

Hierbei können die folgenden Attribute aus dem Namespace System.ComponentModel verwendet werden:

  • Browsable bestimmt, ob die Eigenschaft angezeigt werden soll.
  • DisplayName gibt den Anzeigenamen an
  • ReadOnly steuert den Schreibschutz der Spalte
  • Description liefert eine Beschreibung der Spalte

Die folgende Abbildung zeigt die Kommunikation zwischen beteiligten Parteien:

ITypedList

Wie hier bereits erwähnt, haben Sie nicht immer Einfluss auf die Datenklasse, sodass Sie unter Umständen die genannten Attribute nicht setzen können. Hierfür bietet DataObjectView<T> die Eigenschaft ColumnAttributes. Sie enthält für jede Eigenschaft der Liste ein DisplayAttributeInfo-Objekt, über das die Darstellung gesteuert werden kann.

DataObjectView<Person> view = list.DefaultView;
view.ColumnAttributes["Id"].Browsable = false;
view.ColumnAttributes["FirstName"].DisplayName = "Vorname";
view.ColumnAttributes["LastName"].DisplayName = "Nachname";
view.ColumnAttributes["LastName"].ReadOnly = true;

Auf diese Weise können Sie die entsprechenden Anzeigeattribute programmatisch zuweisen, ohne die jeweilige Datenklasse anpassen zu müssen. Zudem kann es vorkommen, dass die Darstellung vom jeweiligen Kontext in der Anwendung abhängt.

Neben den genannten Anzeigeattributen bietet DisplayAttributeInfo über die Ordinal-Eigenschaft die Möglichkeit, die Position der Spalte für die Bindung festzulegen. Alternativ können Sie auch die SetOrdinal()-Methode der View verwenden.

list.DefaultView.SetOrdinal(
  "Id", "FirstName", "LastName");

Um diese Art der Anpassung auch dem Endanwender zu ermöglichen, bietet TT.DOM einen Standarddialog (CustomizeColumnsForm) mit dem die Darstellung zur Laufzeit angepasst werden kann.

CustomizeColumns

Berechnete Spalten

Über den ITypedList-Mechanismus stellt TT.DOM auch die Möglichkeit zu Verfügung, dynamisch berechnete Spalten zu definieren. Die Spalten werden hierbei über einen eigene PropertyDescriptor-Ableitung bereitgestellt, welche die Werte über einen Delegate ermitteln.

Die Anlage von berechneten Spalten erfolgt über die ComputedColumns-Eigenschaft von DataObjectView<T>. Hierbei geben Sie lediglich den Namen und den Typ der “virtuellen” Eigenschaft, sowie einen Delegate zur Berechnung an.

ComputedColumn col =
  new ComputedColumn("FullName", typeof(string),
    item =>
      ((Person)item).FirstName + " " +
      ((Person)item).LastName);
_persons.DefaultView.ComputedColumns.Add(col);

Daraufhin erscheint die Spalte automatisch im gebundenen Listensteuerelement. Das sich der Wert der Spalte automatisch aktualisiert, wenn sich die abhängigen Eigenschaften ändern, brauche ich wohl nicht zu erwähnen ;)

Auch bei dieser Technik besteht der Vorteil vor allem darin, berechnete Spalten bereitzustellen, ohne die zugrunde liegende Datenklasse anpassen zu müssen.

Daily Demo: Image Stack

17.03.2010 08:00:00 | Oliver Scheer

An interesting control is a Image Stack, where Images are stacked on top of each other. Normally you remove the image on top and put it to the back. So I did. If you double-click the stack an animation move the image to the back.

image

Live-Demo here

XAML-Code:

<UserControl x:Class="ImageStack.MainPage"
    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"
    mc:Ignorable="d"
    d:DesignHeight="321" d:DesignWidth="416" xmlns:my="clr-namespace:TheOliver.Controls">

    <Grid x:Name="LayoutRoot" Background="White">
        <my:ImageStack Margin="12" x:Name="imageStack1" Background="Gray" >
            <Image Source="/ImageStack;Component/Assets/1.jpg" />
            <Image Source="/ImageStack;Component/Assets/2.jpg" />
            <Image Source="/ImageStack;Component/Assets/3.jpg" />
            <Image Source="/ImageStack;Component/Assets/4.jpg" />
            <Image Source="/ImageStack;Component/Assets/5.jpg" />

        </my:ImageStack>
    </Grid>
</UserControl>

Source-Code:

// Copyright © Microsoft Corporation.  All Rights Reserved.
// This code released under the terms of the 
// Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)

using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Effects;
using System.Windows.Threading;

namespace TheOliver.Controls
{
    public class ImageStack : Panel
    {
        public ImageStack()
        {
            _doubleClickTimer = new DispatcherTimer();
            _doubleClickTimer.Interval = new TimeSpan(0, 0, 0, 0, DoubleClickSpeedInMS);
            _doubleClickTimer.Tick += (s, e) =>
                {
                    _clickCount = 0;
                    _doubleClickTimer.Stop();
                };

            this.MouseLeftButtonUp += (s, e) =>
                {
                    if (_clickCount == 1)
                    {
                        // Doubleclick detected
                        HideCurrentImage();
                    }
                    else
                    {
                        _clickCount++;
                        _doubleClickTimer.Start();
                    }
                };

            _hideStoryboard.Completed += (s, e) =>
                {
                    this.Children.Remove(_removedImage);
                    this.Children.Insert(0, _removedImage);
                    ShowNextImage();
                };

            _showStoryboard.Completed += (s, e) =>
                {
                    _storyboardIsActive = false;
                };
        }

        Random _random = new Random();
        int _clickCount;
        DispatcherTimer _doubleClickTimer;
        Storyboard _hideStoryboard = new Storyboard();
        Storyboard _showStoryboard = new Storyboard();
        Image _removedImage;
        bool _storyboardIsActive = false;
        double _newX;
        double _newY;
        Size _finalSize;

        private void ShowNextImage()
        {
            TimeSpan duration = new TimeSpan(0, 0, 0, 0, AnimationInMS);
                
            // Part 2
            DoubleAnimation xa2 = new DoubleAnimation();
            xa2.Duration = duration;
            xa2.To = -_newX;

            DoubleAnimation ya2 = new DoubleAnimation();
            ya2.Duration = duration;
            ya2.To = -_newY;

            _showStoryboard.Stop(); 
            _showStoryboard.Children.Clear();
            _showStoryboard.Duration = duration;
            _showStoryboard.Children.Add(xa2);
            _showStoryboard.Children.Add(ya2);

            TransformGroup tg = _removedImage.RenderTransform as TransformGroup;
            TranslateTransform tt2 = new TranslateTransform();
            tg.Children.Add(tt2);
            _removedImage.RenderTransform = tg;

            Storyboard.SetTarget(xa2, tt2);   //set Animation Target
            Storyboard.SetTargetProperty(xa2, new PropertyPath("X"));   // set Animation TargetProperty
            Storyboard.SetTarget(ya2, tt2);
            Storyboard.SetTargetProperty(ya2, new PropertyPath("Y"));

            if (this.Resources.Contains("showme"))
            {
                this.Resources.Remove("showme");
            }
            this.Resources.Add("showme", _showStoryboard);

            _showStoryboard.Begin();
        }

        bool _layouted = false;

        protected override Size ArrangeOverride(Size finalSize)
        {
            _finalSize = finalSize;

            if (!_layouted)
            {
                LayoutImages(_finalSize);
                _layouted = true;
            }
            return base.ArrangeOverride(finalSize);
        }

        
        private void HideCurrentImage()
        {
            if (_storyboardIsActive)
            {
                return;
            }
                
            _storyboardIsActive = true;
            _removedImage = this.Children[this.Children.Count - 1] as Image;
            if (_removedImage != null)
            {
                TimeSpan duration = new TimeSpan(0, 0, 0, 0, AnimationInMS);
            
                double angle = _random.Next(360);
                _newX = Math.Sin(angle) * this.RenderSize.Width;
                _newY = Math.Cos(angle) * this.RenderSize.Height;

                _hideStoryboard.Stop();
                _hideStoryboard.Children.Clear();

                
                // Part 1
                DoubleAnimation xa1 = new DoubleAnimation(); 
                xa1.Duration = duration;
                xa1.To = _newX;      

                DoubleAnimation ya1 = new DoubleAnimation();
                ya1.Duration = duration;
                ya1.To = _newY;

                _hideStoryboard.Duration = duration;
                _hideStoryboard.Children.Add(xa1);
                _hideStoryboard.Children.Add(ya1);

                TransformGroup tg = _removedImage.RenderTransform as TransformGroup;
                
                TranslateTransform tt = new TranslateTransform();
                tg.Children.Add(tt);
                _removedImage.RenderTransform = tg;
                
                Storyboard.SetTarget(xa1, tt);   
                Storyboard.SetTargetProperty(xa1, new PropertyPath("X"));   
                Storyboard.SetTarget(ya1, tt);
                Storyboard.SetTargetProperty(ya1, new PropertyPath("Y"));

                if (this.Resources.Contains("hideme"))
                {
                    this.Resources.Remove("hideme");
                }
                this.Resources.Add("hideme", _hideStoryboard);

                _hideStoryboard.Begin();
            }
        }

        private Size LayoutImages(Size finalSize)
        {
            var images = this.Children.OfType<Image>();
            Random rnd = new Random();

            foreach (var image in images)
            {
                // Drop Shadow Effect
                if (ShowDropShadowEffect)
                {
                    DropShadowEffect dse = new DropShadowEffect();
                    dse.ShadowDepth = 0.3;
                    image.Effect = dse;
                }

                // Center image
                image.VerticalAlignment = System.Windows.VerticalAlignment.Center;
                image.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;

                TransformGroup tg = new TransformGroup();

                // Scale to fit the finalsize * 90%
                image.Stretch = Stretch.Uniform;
                image.Width = finalSize.Width * ResizeFactor;
                image.Height = finalSize.Height * ResizeFactor;

                image.Margin = new Thickness(
                    (finalSize.Width - image.Width) / 2, (finalSize.Height - image.Height) / 2,
                    (finalSize.Width - image.Width) / 2, (finalSize.Height - image.Height) / 2);

                // Rotate image
                RotateTransform rt = new RotateTransform();
                rt.Angle = 90 - rnd.Next(180);
                rt.CenterX = image.Width / 2;
                rt.CenterY = image.Height / 2;
                tg.Children.Add(rt);

                image.RenderTransform = tg;
            }
            return finalSize;
        }

        #region Properties
        

        public double ResizeFactor
        {
            get { return (double)GetValue(ResizeFactorProperty); }
            set { SetValue(ResizeFactorProperty, value); }
        }

        public static readonly DependencyProperty ResizeFactorProperty =
            DependencyProperty.Register(
                "ResizeFactor", 
                typeof(double), 
                typeof(ImageStack), 
                new PropertyMetadata(0.5, OnValueChanged));

        private static void OnValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ImageStack stack = sender as ImageStack;
            stack.InvalidateArrange();
        }

        public bool ShowDropShadowEffect
        {
            get { return (bool)GetValue(ShowDropShadowEffectProperty); }
            set { SetValue(ShowDropShadowEffectProperty, value); }
        }

        public static readonly DependencyProperty ShowDropShadowEffectProperty =
            DependencyProperty.Register(
                "ShowDropShadowEffect", 
                typeof(bool), 
                typeof(ImageStack), 
                new PropertyMetadata(true, OnValueChanged));

        public int DoubleClickSpeedInMS
        {
            get { return (int)GetValue(DoubleClickSpeedInMSProperty); }
            set { SetValue(DoubleClickSpeedInMSProperty, value); }
        }

        public static readonly DependencyProperty DoubleClickSpeedInMSProperty =
            DependencyProperty.Register(
                "DoubleClickSpeedInMS", 
                typeof(int), 
                typeof(ImageStack), 
                new PropertyMetadata(500, OnDoubleClickSpeedChanged));

        private static void OnDoubleClickSpeedChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ImageStack stack = sender as ImageStack;
            stack._doubleClickTimer.Stop();
            stack._doubleClickTimer.Interval = new TimeSpan(0, 0, 0, 0, (int)e.NewValue);
        }

        public bool EnableDragging
        {
            get { return (bool)GetValue(EnableDraggingProperty); }
            set { SetValue(EnableDraggingProperty, value); }
        }

        public static readonly DependencyProperty EnableDraggingProperty =
            DependencyProperty.Register(
                "EnableDragging", 
                typeof(bool), 
                typeof(ImageStack), 
                new PropertyMetadata(false));
        
        public int AnimationInMS
        {
            get { return (int)GetValue(AnimationInMSProperty); }
            set { SetValue(AnimationInMSProperty, value); }
        }

        public static readonly DependencyProperty AnimationInMSProperty =
            DependencyProperty.Register(
                "AnimationInMS", 
                typeof(int), 
                typeof(ImageStack), 
                new PropertyMetadata(125));

        #endregion

    }
}

Download Sourcecode

Buchempfehlung: Why Software Sucks…

17.03.2010 04:13:01 | Jürgen Gutsch

Das Buch ist zwar schon etwas älter (von 2006) aber erst nachdem ich auf der BASTA! Spring David S. Platt in der Keynote gesehen habe bin ich darauf aufmerksam geworden.

Why Software Sucks…and what you can do about it” ist nicht nur ein Buch für Softwareentwickler und UI-Designer, sondern auch für jeden andern, der immer wieder Probleme mit Software hat und wissen möchte, warum Softwareentwickler keine User Interfaces gestalten können.

“A riotous book for all us downtrodden computer users, written in language that we understand” -  Stacy Baratelli, the author’s barber
(Zitat abgeschrieben vom Buchdeckel *fg*)

Das Buch beschreibt auf radikale und humorvolle Art und Weise anhand von reellen Beispielen was schlechte und was gute User Interfaces sind. Er erklärt in einfacher Sprache warum Softwareentwickler nicht in der Lage sind gute User Interfaces zu designen, bzw. was der Softwareentwickler beachten und tun muss um eben bessere User Interfaces zu gestalten.

Wer also von David S. Platt mit der Nase in die eigene Sch***e gedrückt werden möchte oder einfach nur schmunzeln möchte und Interesse an guten (und schlechten) User Interfaces hat, sollte sich das Buch auf jeden Fall zulegen. Das Buch ist zudem eine perfekte Ergänzung zu Clean Code, da Softwareentwicklung von einer anderen Seite betrachtet wird, die ebenfalls clean und simple gehalten werden sollte und bei allen Clean Codes und CCD dennoch übersehen wird.

Für 15,20 € bei Amazon: Why Software Sucks...and What You Can Do about It
(Verlag: Addison Wesley; Sprache: Englisch; ISBN: 0-321-466756)

DotNetKicks-DE Image

codezone.de und Content-Partnerschaft

17.03.2010 01:53:00 | Jürgen Gutsch

Nachdem es per E-Mail nicht funktioniert, versuche ich es mal auf diesem Weg.

Seit mehreren Monaten versuche ich, für den .NET-Stammtisch Konstanz-Kreuzlingen, eine Content-Partnerschaft mit codezone.de einzugehen, um UG-Termine automatisch auf codezone.de zu veröffentlichen. Dafür gibt es auf der codezone.de ein spezielles Formular, das ausgefüllt und abgeschickt werden kann.

So habe ich das nun innerhalb der letzten 12 Monate drei mal gemacht und jedes Mal per E-Mail die Hinweise erhalten, dass die E-Mailadressen der Formular-Empfänger nicht (mehr) verfügbar sind. Der eine Empfänger ist Kay Giza der zweite ein Mitarbeiter bei Axinom, auf deren Servern codezone.de gehostet wird.

Nach dem ersten und zweiten Versuch hatte ich Kay kontaktiert. Allerdings nur beim ersten Kontakt eine Antwort, aber keine Lösung erhalten. Der Kontakt nach dem zweiten Versuch blieb leider unbeantwortet.

Folgende Fragen stellen sich mir nun nach den drei erfolglosen Versuchen das Formular abzuschicken:

  1. 1. Warum wundert sich keiner, dass keine Content-Partner-Anfragen mehr hereinkommen?
  2. 2. Warum werden E-Mailkontakte im System nicht aktualisiert, wenn sich die Zuständigkeiten ändern?
  3. 3. Warum vergisst das “4-köpfiges Gremium, dass aktiv für den Betrieb und die weitere Ausgestaltung des Web-Service verantwortlich ist” ein zwar kleines, aber nicht unbedeutendes Feature zu aktualisieren? ;-)

Man wird verstehen, dass ich hierüber etwas enttäuscht bin.

DotNetKicks-DE Image

CeBIT 2010: Nachlese fuer Entwickler und IT Professionals

17.03.2010 00:25:25 | Kay Giza

CeBIT 2010 - NachleseVom Microsoft-Messestand direkt ins Netz: auf der diesjährigen CeBIT haben die Experten von MSDN und TechNet wieder ein vollgepacktes Programm mit Vorträgen zu aktuellen Technologiethemen präsentiert – fünf Tage lang, von morgens bis zum Messeschluss, immer im Halbstunden-Takt.
Insgesamt 15 dieser Vorträge für Entwickler und IT-Pros sind seit letzter Woche (wir hatten es auf MSDN Online und MSDN Flash Newsletter bereits angekündigt) im „CeBIT Special“ von MSDN Online in Video-Aufzeichnungen kostenfrei und ohne Registrierung abrufbar; dazu gibt’s die jeweiligen Präsentationsfolien zum herunterladen.

Zusätzlich sollte man einen Blick ins MSDN TV werfen, wo zahlreiche TV-Beiträge von der CeBIT zu finden sind, u.a. auch Kai Pflaume, der beste Grüße in die Entwicklergemeinde sendet!



This post is powered by www.Giza-Blog.de | Giza-Blog.de: RSS Feed
Visit:  MSDN Online | Follow MSDN Online on Twitter | Follow Kay Giza on Twitter
Daily News on MSDN:  MSDN Aktuell
© Copyright 2006-2010 Kay Giza. All rights reserved. Legal
Subscribe

MSDN Guide Update im Maerz 2010 - ueber 50 neue Info-Quellen

17.03.2010 00:10:53 | Kay Giza

Kennen Sie unseren MSDN Guide?
MSDN Guide

Er bietet seit geraumer Zeit eine bewährte und kompakte Übersicht zu den wichtigsten technischen Informationsquellen von MSDN Online Deutschland. Dort finden Sie auf einen Blick die wichtigsten Links zu den Technologien und Produkten von Microsoft.

Aktuell haben wir von der MSDN Online-Redaktion über 50 neue Wissensquellen hinzugefügt und hunderte von Links aktualisiert.
Wir nennen das: „Orientierung leicht gemacht!“ – und dies auch noch einfach und schnell mit drei Mausklicks realisiert.

Testen Sie es aus! Fehlt etwas oder haben Sie einen Hinweis? Wir freuen uns über jeden Hinweis!



This post is powered by www.Giza-Blog.de | Giza-Blog.de: RSS Feed
Visit:  MSDN Online | Follow MSDN Online on Twitter | Follow Kay Giza on Twitter
Daily News on MSDN:  MSDN Aktuell
© Copyright 2006-2010 Kay Giza. All rights reserved. Legal
Subscribe

Eclipse Plug-in : Microsoft Visual Studio Team Explorer 2010 codename "Eaglestone"

16.03.2010 18:22:59 | Christian Binder

Team Foundation Server 2010 stellt als ALM Plattform unter anderem integrierte Repositorien für Version Control, Team Builds, Test, Entwicklungs Prozesse (Agile oder Formal) und entsprechendes Reporting bereit. Der Team Explorer 2010 codename “Eaglestone”  ist ein Plug-In für die Eclipse IDE, womit der Zugriff auf den TFS 2010 möglich ist. Auf diese Weise können Entwickler die mit Visual Studio arbeiten und Entwickler die mit der Eclipse IDE arbeiten, die gleiche ALM Plattform nutzen.

Supported Operating Systems: Apple Mac OS X; HP-UX; IBM AIX; Linux; Solaris; Unix; Windows 7; Windows Vista; Windows XP Service Pack 2

Download

Chris

Internet Explorer 9 Platform Preview

16.03.2010 17:44:44 | Oliver Scheer

Microsoft hat heute auf der MIX10 in Las Vegas das Internet Explorer 9 Platform Preview Programm vorgestellt. Im Rahmen dieser Vorschau zeigt Microsoft seinen Entwicklungen rund um die nächste Version des Internet Explorer.

Einige Highlights:

  • Hardwarebeschleunigung
  • Eine neue JavaScript-Engine
  • Standards: HTML5, CSS3, DOM, SVG

Microsoft liefert auf der Webseite diverse Testszenarien für diese Standards mit. DIese sollte man definitiv mit den “anderen” Browsern auch mal testen.

Download und Testplattform: http://ietestdrive.com

msdn tv - Nachrichten für Entwickler (Ausgabe 04/2010)

16.03.2010 16:00:39 | Jan Schenk



tweetmeme_url = 'http://blogs.msdn.com/jansche/archive/2010/03/16/msdn-tv-nachrichten-f-r-entwickler-ausgabe-04-2010.aspx'; tweetmeme_source = 'jansche';

Get Microsoft Silverlight


In der heutigen Ausgabe von msdn tv - Nachrichten für Entwickler ist Jan Schenk nach kurzem Aufenthalt unter Palmen zu Gast bei der DNUG München, der DotNET Usergroup München (http://www.munichdot.net/). Im Interview ist Hardy Erlinger, Leiter der Münchner Usergroup und Gründer der INETA Deutschland (http://ineta-germany.org), und Gregor Biswanger, Silverlight-Abhängiger und Referent auf dem Usergroup-Treffen. Ausserdem gibt es in den Fast Facts of the Week wieder viel Neues zu Dariusz Parys Tutorialserie über Visual Studio 2010, der Beta 2 der Windows Server AppFabric, einer Webcastreihe von Holger Sirtl zum Thema Windows Azure Platform und der Microsoft Roadshow "Zwanzig Zehn" zum Launch von Visual Studio 2010 am 12. April. Ausserdem ein Terminhinweis auf Tom Wendels TechTalk-Runde quer durch Deutschland zum neuen Sharepoint 2010.
Mit welcher Kopfbedeckung, welchen Versprechern und welchem Set msdn tv seine Zuschauer heute überrascht lässt sich nicht in Textform fassen. Um es mit wenigen Worten zu sagen: Die heutige Ausgabe ist die Überlänge wert. Die Gesamtspieldauer des Director's Cut sind heute ganze 20 Minuten 38 Sekunden.

 

msdn tv ist ein neues Video-Nachrichtenformat, und hat seinen Ursprung auf MSDN Online (http://www.msdn-online.de/msdntv/). Alle zwei Wochen präsentiert Ihnen Jan Schenk, Developer Evangelist mit Hut, die wichtigsten Neuigkeiten für Entwickler, Hintergrundberichte und Interviews zu aktuellen Technologien sowie Highlights von Messen und Konferenzen. Das ganze kompakt, in ca. 15 Minuten erfrischend jung verpackt , und sowohl als Download für Ihren Rechner oder im Online-Player per Streaming verfügbar.

msdn tv is a German-speaking new and innovative video news series, and has originally been featured exclusively on the German MSDN Online Platform (http://www.msdn-online.de/msdntv/). Hatted Developer Evangelist Jan Schenk biweekly presents latest news for developers, background-stories and interviews concerning current and upcoming technologies, as well as video-highlights from fairs and conferences. Packed into 15 minutes, these news videos feature a fresh informative style, and are downloadable as well as available as online streaming video.

Blend 4 Add-in Preview for Windows Phone

16.03.2010 15:57:34 | Oliver Scheer

Für Expression Blend 4 wird es bald eine spezielle kostenfrei Version für Windows Phone geben. Diese Version hat es nicht mehr in den Developer Toolkit CTP für Windows Phone geschafft, wird aber in der finalen Version bald verfügbar sein.

Um dennoch mit Blend Windows Phone Anwendungen entwickeln zu können, wird dieses Add-in benötigt.

image

Download

TT.DOM: Views, Teil 1

16.03.2010 09:40:00 | Jörg Neumann

Neben der normalen Datenbindungsfunktionalität bietet TT.DOM ein View-Modell, das es ermöglicht mehrere unterschiedliche Sichten auf die selben Daten zu erstellen. So können Sie beispielsweise verschiedene Filter- und Sortierkriterien, oder Anzeigefelder je Sicht definieren.

Hierbei kommen eine Reihe von Standardinterfaces zum Einsatz, die vom jeweiligen Tabellensteuerelement zur Interaktion mit der Datenquelle verwendet werden.

View-Konzept

Eine View wird durch die Klasse DataObjectView<T> repräsentiert. Sie implementiert die folgenden Interfaces:

  • IBindingListView stellt Member für das Filtern und Sortieren bereit. Anders als bei LINQ, werden diese jedoch in Form von Zeichenketten bereitgestellt, was die dynamische Erstellung zur Laufzeit ermöglicht.
  • ITypedList wird von der Datenbindungsinfrastruktur verwendet, um die anzuzeigenden Eigenschaften der Datenquelle abzufragen. Hierzu stellt die Datenquelle PropertyDescriptor-Objekte zu Verfügung, die um Anzeigeattribute, wie DisplayName, ReadOnly oder Browsable angereichert werden können. Zudem können Sie über diesen Mechanismus berechnete Spalten bereit stellen, die dynamisch erzeugt werden und nicht in Form von Eigenschaften von der Datenklasse bereitgestellt werden müssen.
  • IListSource wird von der Listenklasse implementiert und verweist auf die Default View. Auf diese Weise wird beim Binden der Liste auf die Default View verwiesen. Dadurch wirken sich Änderungen der Default View direkt auf die Anzeige aus, auch wenn nicht explizit an diese gebunden wurde.

Views erstellen

Für den Zugriff auf eine View stellt DataObjectList<T> zwei Möglichkeiten zu Verfügung:

  1. DefaultView liefert die Standardsicht der Liste. Wie oben bereits erwähnt wird diese durch das IListSource-Interface standardmäßig bei der Binding verwendet.
  2. CreateView() erzeugt eine neue View. Auf diese Weise können Sie beliebig viele Views für die Datenquelle erstellen, wobei Änderungen der Daten – sowohl in der View, auch in der Originalliste – automatisch synchronisiert werden.

ListViewRelation

Liste sortieren

Für das Sortieren von Daten stellen alle Tabellensteuerelemente entsprechende Funktionen bereit. Es macht jedoch durchaus Sinn diese Funktionalität auch über das Objektmodell anzubieten. So müssen Sie nicht direkt mit dem Tabellensteuerelement kommunizieren, was die Kapselung der Logik und die Austauschbarkeit der Controls erhöht. Zudem stellt .NET mit dem Interface IBindingListView einen Mechanismus bereit, der eine Synchronisation zwischen der Liste und dem Anzeigesteuerelement ermöglicht. Auf diese Weise passt sich die Anzeige automatisch der programmatisch zugewiesenen Sortierung an und umgekehrt.

Die Zuweisung des Sortierkriteriums vollzieht sich bei TT.DOM nach dem gleichen Prinzip wie bei der guten, alten DataView-Klasse: Es wird eine Zeichenfolge mit den Sortierfeldern und optional “ASC” oder “DESC” für aufsteigende bzw. absteigende Reihenfolge festgelegt.

list.DefaultView.Sort = "FirstName ASC, LastName DESC";

Wie bereits erwähnt, bietet die String-basierte Zuweisung den Vorteil, diese zur Laufzeit zuweisen und ändern zu können. Auf diese Weise kann auch der Anwender von der Funktionalität profitieren. Hierfür stellt TT.DOM den Dialog SortForm bereit.

SortDialog 

Filter definieren

Das Filtern der Liste erfolgt über die Filter-Eigenschaft der DataObjectView<T>-Klasse.

view.Filter = "LastName LIKE N*";

Hierbei wird der Ausdruck dynamisch via CodeDom nach C# konvertiert, kompiliert und auf die Liste angewendet. Die folgende Abbildung zeigt diesen Prozess:

Filtern

Bei der Syntax orientiert sich die Funktionalität an den Filterausdrücken, die DataView bietet. Die folgenden Ausdrücke sind hierbei möglich:

Funktion

Beschreibung

Lower()

Wandelt den Text in Kleinbuchstaben.

Upper()

Wandelt den Text in Großbuchstaben.

Str()

Wandelt einen Ausdruck in eine Zeichenfolge.

Trim()

Entfernt Leerzeichen an Anfang und Ende einer Zeichenfolge.

IsNull()

Gibt true zurück, wenn ein Ausdruck den Wert null enthält.

Round()

Rundet eine Zahl auf eine bestimmte Anzahl an Nachkommastellen.

Date()

Wandelt eine Zeichenfolge in ein Datum.

Substring()

Extrahiert eine Teilzeichenfolge an der angegebenen Stelle.

Len()

Gibt die Länge einer Zeichenkette zurück.

Year()

Gibt das Jahr eines Datums zurück.

Month()

Gibt den Monat eines Datums zurück.

Day()

Gibt den Tag eines Datums zurück.

Hour()

Gibt die Stunde eines Datums zurück.

Minute()

Gibt die Minuten eines Datums zurück.

Second()

Gibt die Sekunden eines Datums zurück.

Millisecond()

Gibt die Millisekunden eines Datums zurück.

Damit auch der Benutzer von der Funktionalität profitieren kann, stellt TT.DOM zwei Standarddialoge zu Verfügung – einen für die einfache, Spalten-basierte Filterung und einen Expression Editor für Power User.

FilterColumnsDialog

FilterDialog

Ich könnte mir vorstellen den Filterprozess zukünftig durch Scripting (via dynamic in .NET 4.0) zu ersetzen. Dies würde den komplexen Konvertierungsvorgang überflüssig machen und würde zudem einen reichhaltigeren Sprachumfang bieten.

Wenn sich jemand dazu berufen fühlt, einfach bei mir melden! :)

Daily Demo: Image Spindle

16.03.2010 08:00:00 | Oliver Scheer

There are a lot of carousel controls out there, but I didn’t find any control which can be customized easy without re-coding or “hacking” hard-coded links to images. What I want is a control that can be customized from the design-interface or in XAML, but not in code.

So I created based on a sample on the web a really reusable carousel with mouse control to move it to the left or right.

And … very important you can insert as much pictures as you want, and change different other parameters like radius

image

 

A spindle with five images ….

image

A spindle with ten images … and no code change.

Live-Preview here

Xaml-Code:

<UserControl x:Class="ImageSpindle.MainPage"
    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"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400" 
xmlns:my="clr-namespace:TheOliver.Controls"> <Grid x:Name="LayoutRoot" Background="White"> <my:ImageSpindle Margin="12" x:Name="imageSpindle1"> <Image Source="Assets/1.jpg" /> <Image Source="Assets/2.jpg" /> <Image Source="Assets/3.jpg" /> <Image Source="Assets/4.jpg" /> <Image Source="Assets/5.jpg" /> </my:ImageSpindle> </Grid> </UserControl>

 

Control-Sourcecode:

using System;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace TheOliver.Controls
{
    public class ImageSpindle : Panel
    {
        Point _mousePoint;
        double _height;
        double _width;
        bool _isMouseOver;

        public ImageSpindle()
        {
            this.Loaded += (s, e) =>
                {
                    if (DesignerProperties.GetIsInDesignMode(this))
                    {
                        return;
                    }

                    this.MouseMove += (s1, e1) =>
                        {
                            _mousePoint = e1.GetPosition(this);
                        }; 

                    CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
                };

            this.MouseEnter += (s, e) =>
                {
                    _isMouseOver = true;
                };

            this.MouseLeave += (s, e) =>
                {
                    _isMouseOver = false;
                };
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            _height = availableSize.Height;
            _width = availableSize.Width;

            var images = this.Children.OfType<Image>();
            int imageCount = images.Count();
            if (imageCount > 0)
            {
                double step = 360.0 / imageCount;
                double currentStep = 0;
                foreach (var image in images)
                {
                    UpdateImage(image, currentStep);
                    currentStep += step;
                }
            }
            return base.MeasureOverride(availableSize);
        }

        private Image UpdateImage(Image image, double step)
        {
            image.Height = ImageHeight;
            image.Width = ImageWidth;
            image.Margin = new Thickness(
                (_width - ImageWidth) / 2, (_height - ImageHeight) / 2, 
                (_width - ImageWidth) / 2, (_height - ImageHeight) / 2); 
            image.RenderTransformOrigin = new Point(0.5, 0.5);
            image.Stretch = ImageStretch;

            PlaneProjection pp = new PlaneProjection();
            pp.CenterOfRotationZ = SpindleCenterOfRotation;
            pp.RotationY = step;
            image.Projection = pp;

            return image;
        }

        void CompositionTarget_Rendering(object sender, EventArgs e)
        {
            if (StopWhenMouseLeft)
            {
                if (!_isMouseOver)
                {
                    return;
                }
            }

            if (double.IsNaN(_width) || _width == 0)
            {
                return;
            }

            foreach (var image in this.Children.OfType<Image>())
            {
                PlaneProjection pp = image.Projection as PlaneProjection;
                if (pp != null)
                {
                    pp.RotationY += ((_mousePoint.X - (_width / 2)) / _width) * 10;
                }
                image.Opacity = (_mousePoint.Y / _height) * 0.5 + 0.5;
            }
        }

        #region Properties

        public Stretch ImageStretch
        {
            get { return (Stretch)GetValue(ImageStretchProperty); }
            set { SetValue(ImageStretchProperty, value); }
        }

        public static readonly DependencyProperty ImageStretchProperty =
            DependencyProperty.Register(
                "ImageStretch", 
                typeof(Stretch), 
                typeof(ImageSpindle), 
                new PropertyMetadata(Stretch.Uniform, OnValueChanged));

        public double ImageWidth
        {
            get { return (double)GetValue(ImageWidthProperty); }
            set { SetValue(ImageWidthProperty, value); }
        }

        public static readonly DependencyProperty ImageWidthProperty =
            DependencyProperty.Register(
                "ImageWidth", 
                typeof(double), 
                typeof(ImageSpindle), 
                new PropertyMetadata(160.0, OnValueChanged));

        public double ImageHeight
        {
            get { return (double)GetValue(ImageHeightProperty); }
            set { SetValue(ImageHeightProperty, value); }
        }

        public static readonly DependencyProperty ImageHeightProperty =
            DependencyProperty.Register(
                "ImageHeight", 
                typeof(double), 
                typeof(ImageSpindle), 
                new PropertyMetadata(120.0, OnValueChanged));

        public double SpindleCenterOfRotation
        {
            get { return (double)GetValue(SpindleCenterOfRotationProperty); }
            set { SetValue(SpindleCenterOfRotationProperty, value); }
        }

        public static readonly DependencyProperty SpindleCenterOfRotationProperty =
            DependencyProperty.Register(
                "SpindleCenterOfRotation", 
                typeof(double), 
                typeof(ImageSpindle), 
                new PropertyMetadata(-160.0, OnValueChanged));

        private static void OnValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ImageSpindle spindle = sender as ImageSpindle;
            spindle.InvalidateMeasure();
        }

        public bool StopWhenMouseLeft
        {
            get { return (bool)GetValue(StopWhenMouseLeftProperty); }
            set { SetValue(StopWhenMouseLeftProperty, value); }
        }

        public static readonly DependencyProperty StopWhenMouseLeftProperty =
            DependencyProperty.Register(
                "StopWhenMouseLeft", 
                typeof(bool), 
                typeof(ImageSpindle), 
                new PropertyMetadata(true));

        #endregion

    }
}

 

Download-Source

Meine erste Visual Studio 2010 Express for Windows Phone Installation

15.03.2010 23:04:58 | Oliver Scheer

Das erste Mal vergisst man nie. Besonders heute. Live auf der MIX10 habe ich mir zum ersten Mal Visual Studio 2010 Express for Windows Phone installiert. Auf meinen 1,5 Jahre alten Samsung NC 10 im Batteriesparmodus. Inklusive Download aus einem völlig überlasteten freien WLAN, inklusive Installation … eine Stunde … Ta Da

image

Mix: Keynote

15.03.2010 19:06:26 | Oliver Scheer

Sitze gerade in der Keynote der MIX10 in Las Vegas.

09:07 Video von Bing Maps Future Video mit Streetside, Argumented Reality. www.discoverbingmaps.com

09:10 Es geht los. Scott Guthrie betritt die Stage.

09:11 Silverlight. Silverlight hat heute 60 % Verbreitung weltweit. Und ist damit das sich am schnellsten verbreitende Browserplugin.

12 Millionen Stunden Live Übertragung bei den Olympischen Spielen in Vancouver 2010. IIS Smooth Streaming + Silverlight.

Der Player ist jetzt Open Source unter http://smf.codeplex.com

Silverlight erlaubt es jetzt in Umgebungen mit mehreren Monitoren auf einem Monitor Fullscreen HD darzustellen, während auf anderen Monitoren andere Anwendungen aktiv sind.

09:18 Live Labs Pivot wird präsentiert. Deep Zoom zum Pivotieren von extrem großen Bilddaten (www.kiva.org, AP, Football-League). www.getpivot.com

image

9:21 Expression Blend 4 wird angekündigt. Jeder Besitzer von Expression Blend 3 bekommt ein kostenloses Update.

Ebay und Cynergy präsentieren ihre Silverlight Lösung zum Einstellen neuer Artikel zum Verkaufen. Integration von Out-Of-Browser-Experience, Webcamsupport zum Scannen von Barcodes auf Produkten. Coole UI. Auf Open Ebay kann jetzt jeder Entwickler spezialisierte Ebay-Anwendungen in Silverlight 4 entwickeln.

Demonstration wie diese Lösung mit SketchFlow zusammen mit Ebay und Cynergy designt und entwickelt wurde.


9:33 Scott Guthrie: Silverlight 4 RC ist ab sofort verfügbar

9:34 Windows Phone

Joe Belfiore, Corporate Vice President Wndows Phone. Die erste Thirdparty Lösung wird präsentiert: Associated Press.

Cool. Windows Phone kann die Darstellung auf dem Bildschirm auch nach außern liefern, so das man prima Demos auf den Beamer bringen kann.

Start, Search, Back – Die einzigen Buttons auf einem Windows Phone.

Sehr coole Demos, die zeigen, die sehr genial miteinander kombinierbar sind. Facebook, Windows Live, Photos. Sehr cool. Alles in Silverlight gebaut.

Jetzt kommt ein 3D Game in XNA entwickelt: Harvest. Genial. Ein echtes XBOX-Live Game. Echtes 3D.

10:01 Scott Guthrie ist wieder auf der Bühne.

Silverlight auf Windows Phone. Same Programming Model. Same Silverlight. Same Tools.

Scott macht selber eine Live Demo. Ist halt immer noch ein Entwickler Wink Visual Studio ist die Entwicklungsumgebung für Windows Phone. Alle Features die man kennt, funktionieren auch für Windows Phone Entwicklung. Design Preview, Intellisense, Debugging, Emulator (Virtual PC). “It just works”. Orientation Testing.

Scott baut live der ersten Windows Phone Twitter Client. Mit WebClient-Klasse einfach auf den Feed zugreifen … Fertig.

10:12 Jon Harris zeigt Photo Apps auf dem Windows Phone und wie diese mit Expression Blend for Windows Phone erstellt werden können.

10:22 Scott is back.

Die Tools für die Entwicklung von Windows Phone:

  • Expression Blend for Windows Phone
  • Visual Studio 2010 Express for Windows Phone

KOSTENLOS

Download: http://developer.windowsphone.com

Noch Fragen???

Jetzt ein paar Beispiele von Partnern:

  • Netflix – Playready DRM
    Videos ausleihen aufs Handy. Genial.
  • Graphic.Ly – Mike Swanson
    Comic Viewer, inklusive Hardware Accelerated Deep Zoom.
  • FourSquare – Laura Foy

10:36 Scott introducing Shazam – Jeff Sandquist

Lieder erkennen mit dem Windows Phone. Shazam erkennt Lieder. Integration mit dem Zune Marketplace.

Major League Soccer – Charlie Kindel stellt vor, wie man mit dem Windows Phone Daten über Fussball (nicht American Football) visualieren kann.

Marionette – Einen Avatar Tool. Scott läßt Steve Ballmer “Phone Developers” singen …

10:45 Seesmic - Loic Le Meur´

Eine coole Silverlight Anwendung für den Desktop (Windows und Mac). Und jetzt auch auf Windows Phone. Sehr cool. http://platform.seesmic.com

10:51 Coding4Fun mit dem Windows Phone – Cannon.

Eine Remote Kanonensteuerung jetzt wird auf das Publikum geschossen. Schnell weg hier Smile Rote Polo Shirts werden ins Publikum geschossen.

10:57 XNA Gaming auf dem Windows Phone und in der Cloud – Battle Punks und Harvest

Die 3-Screen-Experience = Ein Spiel auf drei Plattformen = Windows Phone 7 + XBOX 360 + PC. Live Demo … sehr cool. Alles mit dem XNA Studio 4.0. Genial.

11:02 Marketplace – Wie können Entwickler Geld verdienen? Ganz einfach über den Marketplace für Windows Phone.

Sehr cool, das Try & Buy Feature. Anwendungen erst mal testen bevor man die Katze im Sack kauft. Für den Consumer super, für den Entwickler eine Zeile Code.

Okay … das wars.

Windows Phone 7 = Silveright + XNA + Kostenloses Blend for Windows Phone + Kostenloses Visual Studio for Windows Phone

Silverlight 4: Out-Of-Browser Enhancements

15.03.2010 11:00:00 | Oliver Scheer

Silverlight 4 comes with a lot of new features. A common request was the support of different types of window styles for the out-of-browser-functionality.

And … Microsoft listen … The support is there. This feature enables a developer to create their on style of window styles for their browser. This is requires, the agreement of the user, to change this.

When you customize your application for deployment, you have now several options in the configuration.

image

The button “Out-of-Browser-Settings” enables the developer to customize the behavior of the Application, when it runs out of browser. If you request elevated trust from the user, you can choose different styles of a window.

image

 

When the user tries to install the application he got the following standard installation Prompt.

image

After that, he can enjoy one of the following window styles:

  • Default Style
  • No Border
  • Single Border
  • Borderless round corners
    Have fun,
    The-Oliver

TT.DOM: Transaktionen

15.03.2010 08:48:00 | Jörg Neumann

Wie hier bereit beschrieben, stellt TT.DOM Unterstützung für Undo/Redo-Transaktionen bereit. Darüber hinaus können DataObject-Ableitungen auch an lokalen oder verteilten Transaktionen teilnehmen – ohne dass Sie dafür etwas tun müssen!

Hierfür setzt TT.DOM auf der Funktionalität von System.Transactions auf. So implementiert z.B. die Basisklasse DataObject das Interface IEnlistmentNotification (Prepare, Commit, Rollback, …). Zudem wird sowohl das implizite, als auch das explizite Programmiermodell von System.Transactions unterstützt.
Beispiel für das explizite Enlistment:

Person p = new Person
  { FirstName = "Jörg", LastName = "Neumann" };
CommittableTransaction tran =
  new CommittableTransaction();
tran.EnlistVolatile(p);
p.FirstName = "Joerg";
tran.Commit();

Beispiel für das implizite Enlistment:

Person p = new Person
  { FirstName = "Jörg", LastName = "Neumann" };
using (TransactionScope tx = new TransactionScope())
{
  p.FirstName = "Joerg";
  tx.Complete();
}

Das Ganze kann natürlich auch für auf Listenebene vollzogen und mit anderen transaktionsfähigen Objekten kombiniert werden.

Daily Demo: Tipping Text

15.03.2010 08:00:00 | Oliver Scheer

Basierend auf einer wahren Begebenheit habe ich das folgende Steuerelement gebastelt. Es macht nichts anderes als Text zu tippen … klingt einfach … ist es auch.

image

Liveversion: hier.

Code für das Steuerelement

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;

namespace TheOliver.Controls
{
    public class TippingText : UserControl
    {
        TextBox _textblock;
        DispatcherTimer _timer;

        public TippingText()
        {
            _textblock = new TextBox();

            this.Content = _textblock;

            _timer = new DispatcherTimer();
            
            _timer.Interval = new TimeSpan(0, 0, 0, 0, TippingSpeedInMilliseconds);
            _timer.Tick += (s, e) =>
                {
                    ShowNextCharacter();
                    _currentCharacter++;
                    if (_currentCharacter >= Text.Length)
                    {
                        _timer.Stop();
                        if (Repeat)
                        {
                            _currentCharacter = 0;
                            _timer.Start();
                        }
                    }
                };

            this.Loaded += (s, e) =>
                {
                    if (Text.Length > 0)
                    {
                        _timer.Start();
                    }
                };
        }

        private void ShowNextCharacter()
        {
            if (Text.Length > _currentCharacter + 1)
            {
                _textblock.Text = Text.Substring(0, _currentCharacter + 1);
            }
        }

        private int _currentCharacter;

        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register(
                "Text", 
                typeof(string), 
                typeof(TippingText), 
                new PropertyMetadata("No Text", OnValueChanged));

        private static void OnValueChanged(object sender, DependencyPropertyChangedEventArgs args)
        {
            TippingText tt = sender as TippingText;
            tt._timer.Stop();
            tt._timer.Interval = new TimeSpan(0, 0, 0, 0, tt.TippingSpeedInMilliseconds);
            tt._currentCharacter = 0;
            tt._textblock.TextWrapping = tt.TextWrapping;
            tt._textblock.TextAlignment = tt.TextAlignment;
            tt._textblock.Text = tt.Text;
            if (tt.Text.Length > 0)
            {
                tt._timer.Start();
            }
        }

        public int TippingSpeedInMilliseconds
        {
            get { return (int)GetValue(TippingSpeedInMillisecondsProperty); }
            set { SetValue(TippingSpeedInMillisecondsProperty, value); }
        }

        public static readonly DependencyProperty TippingSpeedInMillisecondsProperty =
            DependencyProperty.Register(
                "TippingSpeedInMilliseconds", 
                typeof(int), 
                typeof(TippingText),
                new PropertyMetadata(200, OnValueChanged));

        public bool Repeat
        {
            get { return (bool)GetValue(RepeatProperty); }
            set { SetValue(RepeatProperty, value); }
        }

        public static readonly DependencyProperty RepeatProperty =
            DependencyProperty.Register(
                "Repeat", 
                typeof(bool), 
                typeof(TippingText), 
                new PropertyMetadata(true, OnValueChanged));

        public TextWrapping TextWrapping
        {
            get { return (TextWrapping)GetValue(TextWrappingProperty); }
            set { SetValue(TextWrappingProperty, value); }
        }

        public static readonly DependencyProperty TextWrappingProperty =
            DependencyProperty.Register(
                "TextWrapping",
                typeof(TextWrapping), 
                typeof(TippingText),
                new PropertyMetadata(TextWrapping.Wrap, OnValueChanged));

        public TextAlignment TextAlignment
        {
            get { return (TextAlignment)GetValue(TextAlignmentProperty); }
            set { SetValue(TextAlignmentProperty, value); }
        }

        public static readonly DependencyProperty TextAlignmentProperty =
            DependencyProperty.Register(
                "TextAlignment", 
                typeof(TextAlignment), 
                typeof(TippingText), 
                new PropertyMetadata(TextAlignment.Center, OnValueChanged));

        
    }
}

Download Sourcecode

Wie böse ist RAD?

15.03.2010 06:42:00 | Jürgen Gutsch

Jeder der mich kennt, weiß, dass ich keine Freund von RAD-Controls (Rapid Application Developement) – besonders von Controls und Tools diverser Drittanbietern – bin.

Aber halte ich RAD deshalb generell böse?

Ralf Westphal schreib im aktuellen Beitrag seiner Kolumne “Sandbox” (in der dotnetpro 4/2010) sinngemäß und zusammengefasst: RAD-Tools für sich gesehen sind nicht böse, sondern die naive Herangehensweise, also zu glauben, dass RAD alle Probleme erledigt, ist böse, bzw. schlecht und die daraus resultierenden Probleme werfen ein schlechtes Licht auf RAD.

Ist das wirklich so?

Generell kann ich die Frage leider nicht komplett beantworten. Sondern nur aus meiner Sicht als Webentwickler, auf RAD-Tools und RAD-Controls für ASP.NET. Ich kann mich also nur auf ASP.NET beziehen und weis nicht wie es sich bei WinForms, WPF und SilverLight verhält.

So wie Ralf es beschreibt, würde ich generell erst mal “Ja” sagen, aber aus meiner Sicht kommen einige Fragen hinzu. Warum gibt es denn überhaupt die Möglichkeit, dass man sich bei naiver Herangehensweise seine komplette Anwendung mit RAD-Tools und RAD-Controls versauen kann? Warum schaffen es die Anbieter nicht, einfache, kleine und flexible Tools zu schaffen mit denen man nicht viel falsch machen kann? Warum müssen alle möglichen, erdenkbaren Funktionen von Anfang an in einem RAD-Tool, bzw. RAD-Control enthalten sein?

Schöne und positive Beispiele kommen von Microsoft selber: LINQ to SQL; die ASP.NET Controls GridView und Calendar sind absolut flexibel beliebig erweiterbar. Es ist also generell machbar.

Zu großer Umfang

Müssen RAD-Tools und drittanbieter-Controls so viele Funktionen anbieten, das der naive Nutzer alle Möglichkeiten ausnutzen will? Anbieter von RAD-Tools wollen die breite Masse zufrieden stellen und stellen deshalb die eierlegende Wollmilchsau zur Verfügung. Das muss aber nicht sein, ganz im Gegenteil. Ich persönlich nutze lieber die kleine Schlanke Komponente die ich selber erweitern kann und nicht das Universal-Tool von dem ich 80% nicht benötige, aber mit schleifen muss.

Unförmiger HTML Code

Wer meinen UG-Vortrag im Herbst (beim .NET-Stammtisch Konstanz-Kreuzlingen) gesehen hat, konnte miterleben wie sich die verschiedenen Hersteller bei der Menge an HTML-Code, JavaScripts und HTML-Verschachtelungen überboten haben. (Ich bin gerne bereit diesen Vortrag auch in einer anderen UGs zu halten. Machen Sie sich dabei auf was gefasst *fg*)

Ein namhafter Hersteller von RAD-Controls zwingt die Browser in die Knie, wenn man mehr als 10 abhängige Comboboxen nutzt, die unter anderem Grids beinhalten. Eine Combobox dieses Anbieters benötigt für 10 Listeneinträge übrigens mehrere ineinander verschachtelte HTML-Tabellen und mehr als 30 Zeilen HTML-Code. Nutzt man zusätzlich noch die Möglichkeit, beim Aufklappen der Combobox ein Grid anzuzeigen, erhöht sich die Menge des benötigten HTML-Codes um die benötigte Menge des Grids, welches auch nicht gerade sparsam mit verschachtelten HTML-Tabellen umgeht. Hinzu kommen Unmengen von JavaScripts, die direkt auf der Seite ausgegeben werden. Die kleine Combobox entpuppt sich bei genauerer Betrachtung als ein riesiges, unperformates und überladenes Control.

Ein weiterer Hersteller hatte es übrigens nicht geschafft, trotz enormer Mengen an unsauberen Code und JavaScripts, die Combobox in allen Browsern zu funktionieren: Im Opera war lediglich eine leere Standard-Combobox zu sehen.

Zu unflexibel und schlecht erweiterbar

Warum schaffen es die meisten Hersteller von RAD-Tools und drittanbieter-Controls nicht, flexible und erweiterbare Tools und Controls zu erstellen?

In einer Kalender-Komponente eines weiteren namhaften Herstellers, benötigte ich zwei Wochen, um ein Doppelklick-Event auf einen Kalendertag abzufangen und einen eigenen Termindialog anzubinden.

  • Warum ich nicht den vorhandenen Dialog genutzt habe?
    Dieser Passte nicht zu der Art von Terminen war nur schwer erweiterbar und passte nicht in das Layout.
  • Warum ich nicht die Komponente eines anderen Herstellers genommen habe?
    Alle anderen waren aufgrund von unsauberen HTML-Code einfach zu unperformant beim Aufbau der Seite, zudem schaffte es das herstellereigene JavaScript nicht mal mehr die per Callback geholten Termine in diesen unmöglichen Code zu setzen.

Grund hier war eine nicht dokumentierte, clientseitige JavaScript API und das tagelange JavaScript-Debugging in unschönem Code.

Fazit

Es ist nicht nur alleine die Naivität der, Nutzer sondern auch die Art wie die Hersteller die Controls produzieren und vermarkten. Auf den Demoseiten der Hersteller sieht alles toll und bunt aus, alles funktioniert einwandfrei, aber dort habe ich auch nie mehr als zehn abhängige Grid-Comboboxen gesehen ;-)

Man RAD-Controls ist man unheimlich schnell bei der Entwicklung von schönen, bunten und benutzerfreundlichen Oberflächen.

Mit RAD-Controls stößt man aber auch unheimlich schnell auf Probleme, wenn man spezielle Anforderungen hat und wenn man Anpassungen und Erweiterungen an den Controls vornehmen möchte. RAD-Controls werden als schnell einsetzbare Tools präsenteiert, aber unter den schönen bunten Oberfläche erweisen sich die meisten als unflexibel, schlecht dokumentiert und unperformant.

Klingt jetzt wahnsinnig abwertend, gell?

Aber ich möchte RAD-Controls nicht generell schlecht machen. Wenn man keine sehr speziellen Anforderungen an z. B: Grid und Kalender-Controls hat, kann und sollte man diese auch nutzen. Der Entwicklungsaufwand um selber eine entsprechendes Control zu schreiben ist einfach zu hoch.

Nur warum sollte man eine TextBox, eine ComboBox, eine CheckBox, etc. von einem Drittanbieter verwenden? Wegen dem schönen Design? Wohl kaum, denn dafür gibt es CSS.

Wegen einer speziellen Funktion mehr? Eine Funktion ist schnell selber geschrieben. Oder man benutzt vorhandene JavaScript-Frameworks, wie z. B. jQuery, um Controls zu erweitern ohne den HTML-Code aufzublähen und die Browser in die Knie zu zwingen.

Im Gegenteil halte ich RAD für absolut Sinnvoll und sollte auf alle Fälle in Betracht gezogen werden, wenn es darum geht den Aufwand klein zu halten. Allerdings hat Ralf absolut recht, wenn man die meisten, heute auf dem Markt befindlichen RAD-Tools anschaut, sollte, bzw. darf man nicht naiv daherkommen und einfach so alle möglichen Tools einsetzen und nutzen, sondern sollte sich penibel mit den Tools auseinandersetzen, abwägen und schauen wie erweiterbar und flexibel die Controls und Tools wirklich sind.

Zu guter Letzt:

Ich kann es einfach nicht lassen und muss hier mal ein anonymisiertes Beispiel posten.

Es soll ein schöner, bunter, formatierter Button angezeigt werden:

<table cellpadding="0" cellspacing="0" style="height: 57px;">
  <tr>
    <td>
      <table cellspacing="0" cellpadding="0" id="ctl00_phContent_BackgroundImageTextGroupBox_Button1" border="0" style="height:30px;width:90px;border-collapse:collapse;border-collapse:separate;">
        <tr>
          <td id="ctl00_phContent_BackgroundImageTextGroupBox_Button1_B" align="center" style="color:White;background-image:url(Images/Wine/normal.jpg);cursor:pointer;padding-bottom:2px;">
            <div id="ctl00_phContent_BackgroundImageTextGroupBox_Button1_CD" class="dxb">
              <span>Submit</span>
            </div>
          </td>
          <td style="width:0%;">
            <input value="" onfocus="ButtonGotFocus('ctl00_phContent_BackgroundImageTextGroupBox_Button1')" name="ctl00$phContent$BackgroundImageTextGroupBox$Button1" type="submit" style="background-color:Transparent;border-width:0px;height:0px;width:0px;padding:0px;" />
          </td>
        </tr>
      </table>
<script id="dxss_202605327" type="text/javascript">
<!--
addHoverItems('ctl00_phContent_BackgroundImageTextGroupBox_Button1',[[[''],['padding-bottom:2px;color:#FAD9E0;background-image:url(Images/Wine/hover.jpg);'],['B'],['','TC'],[['']],['Img']]]);
addPressedItems('ctl00_phContent_BackgroundImageTextGroupBox_Button1',[[[''],['padding-bottom:2px;color:#DCB7C8;background-image:url(Images/Wine/pressed.jpg);'],['B'],['','TC'],[['']],['Img']]]);
var o = new ClientButton('ctl00_phContent_BackgroundImageTextGroupBox_Button1');
window['ctl00_phContent_BackgroundImageTextGroupBox_Button1'] = o;
o.uniqueID = 'ctl00$phContent$BackgroundImageTextGroupBox$Button1';
addSelectedItems('ctl00_phContent_BackgroundImageTextGroupBox_Button1',[[['bf'],[''],['CD']]]);
o.InlineInitialize();
//-->
</script>
    </td>
  </tr>
</table>

Die “alternative” mit normalem HTML würde so aussehen:

<input type="submit" value="Submit" class="beautifulButton" id="submitButton" runat="server" />

Formatiert mit CSS und ggf. erweitert per jQuery und man hat ein besseres Ergebnis, da der HTML-Code schlanker ist und die Browser weniger zeit für die Verarbeitung benötigen.

DotNetKicks-DE Image

Design.Toolbox – Portal für Online Design Trainings

15.03.2010 00:00:00 | Oliver Scheer

Microsoft hat gerade eine neue Plattform für kostenfreie Online-Trainings zu Silverlight und Expression Studio gelauchnt. Zielgruppe sind alle Designer und Design-affine Entwickler.

image

Link: http://www.microsoft.com/design/toolbox/

Hyperlinks in das Word-Nirvana

14.03.2010 00:16:00 | Jan Christian Selke

Das Kopieren von Dokumentinhalten von einem Dokument in das Andere ist ein weites und interessantes Thema im Kontext Word2007/2010 und OpenXml SDK. Hierbei können verschiedenste Abhängigkeiten eine große Rolle spielen. Werden beispielsweise Hyperlink beinhaltende Dokumentteilte kopiert, ist die Überraschung groß. Der Link verweist unter Umständen nicht nur ins Nirvana, er ist selbst vollständig dorthin gewandert. Warum das so ist und was man dagegen machen kann, möchte ich am Beispiel des Kopierens von Inhalten aus einem MainDocument zeigen.

Hyperlinks werden als eigenständiges Element w:hyperlink zwischen Paragraphen w:p und Runs w:r abgelegt. Alternativ zum w:p kann als parent Element auch häufig ein w:sdtContent, ein ContentControl, vorliegen.

Hyplerlink

Das wichtigste Attribut eines Hyperlinks ist das Attribut r:id. Dieses verweist auf eine externe Beziehung, die in dem Dokument document.xml.rels in dem Unterordner _rels innerhalb der Package Struktur hinterlegt wird.

ordner

Bei dem Attribut w:history handelt es sich um einen OnOffValue, im Prinzip einen Boolschen-Wert, durch den angezeigt wird, ob diesem Link bereits gefolgt wurde.

Öffne ich nun dasDokument document.xml.rels finde ich unter der ID 4 den folgenden Eintrag.

<Relationship
    Id="rId4"
   
Type=”
http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink
    Target=”
http://jcselke.blogspot.com
    TargetMode="External" />

Damit ist auch schon geklärt, weshalb Hyperlinks verschwinden. Sie werden also als Externe Beziehung abgelegt, in der die Ziel URL des Hyperlinks hinterlegt ist. Diese werden natürlich nicht durch einfaches Kopieren von Inhalten aus dem Dokument übernommen und gehen daher verloren.

Gut, das bloße Kopieren der Inhalte reicht also nicht aus. Was kann aber getan werden? Eine Lösung kann es sein, durch alle HyperlinkRelationships des Mainparts zu iterieren und diese Stück für Stück in das Zieldokument zu übertragen. Dazu werden Ausgangs- und Zieldokument geöffnet und die Inhalte, in diesem Fall durch Zuweisen des InnerXml, kopiert.

public void ImportContent()
{
using (var package = WordprocessingDocument.Open("c:\\test\\hyperlink.docx", true))
{
var mainDocumentPartSource = package.MainDocumentPart;
var documentSource = mainDocumentPartSource.Document;
using (var packageTarget = WordprocessingDocument.Open("c:\\test\\hyperlink_target.docx", true))
{
var mainDocumentPartTarget = packageTarget.MainDocumentPart;
mainDocumentPartTarget.Document.InnerXml = documentSource.InnerXml;
this.TransferHyperlinks(mainDocumentPartSource, mainDocumentPartTarget);
mainDocumentPartTarget.Document.Save();
}
}
}


Im Anschluss wird in der Methode TransferHyperlinks() eine neue HyperlinkRelationship erzeugt und die alten Werte des zu kopierenden Hyperlinks werden übernommen. Dann wird im Zieldokument das Hyperlink anhand der bisherigen Id identifiziert und die alte Id durch die der neuen HyperlinkRelationship ersetzt.



private void TransferHyperlinks(OpenXmlPartContainer openXmlPartContainer, MainDocumentPart mainDocumentPartTarget)
{
foreach (var hyperlinkRel in openXmlPartContainer.HyperlinkRelationships)
{
var newHyperLinkRel = mainDocumentPartTarget.AddHyperlinkRelationship(hyperlinkRel.Uri, hyperlinkRel.IsExternal);
var relationship = hyperlinkRel;
var importedHyperlink = mainDocumentPartTarget
.Document.Descendants<Hyperlink>()
.Where(x => x.Id == relationship.Id).First();
importedHyperlink.Id = newHyperLinkRel.Id;
}
}


So lässt sich natürlich auch mit allen anderen Parts verfahren, die Hyperlinks enthalten können. Da wären vor allem aber nicht ausschließlich Header- und FooterParts zu nennen.

Git, Mercurial und die PowerShell

13.03.2010 17:41:19 | Albert Weinert

 

Ich versuche seit ein paar Tagen die cmd.exe durch die PowerShell abzulösen. Ist so einiges anders, aber dies ist hier nicht das Thema.

Dabei bin ich auf zwei Skripte für die PowerShell gestoßen mit denen man sich a) den Status eine Git-Repositories als Command-Prompt anzeigen lassen kann, sowie b) git ein wenig Tab-Completion beibringt (Befehle und Repositories).

Ich habe es ein wenig refakttorisiert, zusammengefasst, für mich verbessert und auch noch Mercurial Support eingebaut. Es sind meine erste Schritte in der PowerShell, also hab nachsicht ;).

So schaut es aus.

image

Sofern es in Hg oder Git Repository ist so wird dies in der Titel-Leiste angezeigt, dort ist auch der vollständige Pfad zu sehen, während im Prompt nur der aktuelle Verzeichnisname steht.

Zwischen den Klammern sind dann die Repository Informationen, der Name des aktuellen Branches (in Rot wenn es nicht erfasste Dateien gibt), danach folgen Zahlen die mit +, ~ und - als Vorzeichen. + bedeuten hingefügte Dateien, ~ die geänderten und – gibt die gelöschten Dateien an.

An ein paar Stellen wo bei git und hg die Befehle stehen oder wo Namen von Branches und Remotes gebraucht werden können die mit Tab-Completion durchgetabt werden.

Das ganze ist sicher noch nicht vollständig oder optimal, aber es ist ein Anfang.

Hiermit stelle ich es der Allgemeinheit zu Verfügung und hoffe dass es sich ein wenig weiterentwickelt.

http://github.com/DerAlbertCom/GitHgPowerShell

Um diese zu verwenden einfach die beiden Skripte nach

%USERPROFILE%\My Documents\WindowsPowerShell

kopieren (getestet unter Windows 7). Wenn schon eine profile.ps1 vorhanden ist muss natürlich aufgepasst werden und das ganze Integriert werden.

Viel Spaß damit und forkt fleißig um das ganze zu verbessern ;)

Technorati Tags: ,,,

Wie verwende ich den Meta-Tag robots in meinem Blog?

13.03.2010 16:44:38 | Klaus Bock

Suchmaschinenrobot

Bewusst, dynamisch und abhängig von der gerade aufgerufenen Seite. Aber dazu später mehr.
Der Meta-Tag robots ist eines der wertvollsten Werkzeuge im Umgang mit Suchmaschinen, wird aber oft, gerade in der deutschen .NET Blogosphäre, sträflich vernachlässigt. Die meisten Blogs verwenden den robots-Tag mit den Werten index, follow in jeder Seite ihres Blog. Viele Blogs verwenden den Tag gar nicht, was den vorherigen Werten gleich kommt. Manches Blog, ich will hier keine Namen nennen, verwendet den Tag gleich mehrfach in einer Seite, erst mit noindex, nofollow und drei Zeilen weiter mit index, follow.
Wie man an diesen Beispielen bereits sehen kann, machen sich die wenigsten Blogbetreiber Gedanken darüber, wie eine Suchmaschine mit dem Inhalt des Blog umgehen soll. Frei nach dem Motto: Google, Yahoo, Bing und wie sie nicht alle heißen, werden es schon richten.
Das tun sie auch, aber bestimmt anders als der Blogbetreiber vielleicht will.

Was macht so ein Spider, oder auch Crawler genannt, mit unseren Blogs?
Er ist hungrig nach Futter und seine Lieblingsspeise ist nun mal Text. Der erste Kontakt mit einem Blog ist meist die Startseite. Hier sind in typischer Manier die letzten Artikel, entweder als Teaser oder manchmal als kompletter Artikel, aufgeführt. Für den Crawler ist das schon eine ganze Menge. Ein hat mehrere Überschriften mit H1 oder H2 Tags und einiges an zugehörigem Text. Wenn sich jetzt im Teaser unter der jeweiligen Überschrift einige Wörter aus eben dieser Überschrift wiederfinden, ist der Crawler schon glücklich. Wird in der Startseite auch noch der robots-Tag mir index, follow verwendet, hat er was er will. Die Startseite landet im Index.
Bei Webseiten, die oftmals sehr viel Wert auf die Startseite legen, mag dieses Verhalten ja gewünscht sein. Ich spreche hier aber von einem Blog. Ich will nicht meine Startseite im Index einer Suchmaschine sehen, sondern meine Artikel.
Nehmen wir an, der Crawler folgt von der Startseite aus dem Link zum Artikel. Er analysiert diesen Artikel und stellt fest, dass Teile des Inhalts bereits im Index vorhanden sind. Was soll ihn nun dazu bewegen diese Artikelseite ebenfalls in den Index mit aufzunehmen? Er hat doch bereits auf der Startseite gefunden was er wollte.

Nun gut, dieses Szenario ist wahrscheinlich stark überzeichnet. In Wirklichkeit sind noch ganz andere Faktoren von Bedeutung. Welche genau weiß ich nicht, denn ich bin kein SEO-Fachmann. Nichtsdestotrotz sagt mir der gesunde Menschenverstand, dass der oben geschilderte Fall sich ziemlich sicher so verhält. Was also tun?

Kurz und knapp, ein radikaler Schnitt. Alle Übersichtsseiten, dazu gehört auch die Startseite, werden mit den Werten noindex, follow im Meta-Tag robots versehen. Klingt schmerzhaft? Ist es für den Moment auch.
Ich habe mich vor ca. drei Monaten getraut diesen Schritt zu tun. Anfangs fiel die Anzahl der indizierten Seiten meines Blog ins Bodenlose. Aber nach und nach zeigte sich der gewünschte Effekt. Mittlerweile sind die verschiedenen Artikel im Index und ranken auf den vorderen Plätzen in den SERPs.
Bei einer Suche zu den Begriffen shared memory .net in Google wird mein Blog auf der ersten Seite gelistet. Wenn diese Suche auf Seiten aus Deutschland begrenzt wird, werden sogar zwei Artikel meines Blog auf der ersten Seite gelistet. Die gleiche Suche bei Bing, listet mich auf die beiden ersten Plätze. Auch mit dem Begriff Web Slice wird mein Blog sowohl bei Google als auch bei Bing auf der ersten Seite gelistet; und das bei 13 Millionen Ergebnissen bei Bing und über 15 Millionen bei Google. Ich bin mit diesem Ergebnis mehr als zufrieden.

Programmtechnisch ist die dynamische Verwendung des robots-Tag nicht schwer umzusetzen.
Da BlogEngine.NET nur einen ContentPlaceHolder in der MasterPage des jeweiligen Theme verwendet, ist der Weg über den Head-Bereich im Markup verbaut. Eine rein codebasierende Variante ist allerdings auch nicht schwerer zu verwirklichen.
Da auf die einzelnen Meta-Tags im Header über einen ControlCollection zugegriffen werden kann, ist der robots-Tag einfach zu finden. Wenn der Meta-Tag gefunden wurde, wird der entsprechende Wert gesetzt. Sollte er nicht gefunden werden, wird der Tag mit dem entsprechenden Wert der ControlCollection hinzugefügt.
In eine Methode verpackt, muss dieser Methode nur noch der gewünschte Wert mitgegeben werden. Um Code-Redundanz zu vermeiden, wird die Methode als statische Methode in einer Hilfsklasse verwendet, der als zweiter Parameter die aktuelle Page-Instanz mitgegeben wird.

public static void AddMetaRobots(string metaContent, Page page)
{
    HtmlMeta tag = null;

    foreach (Control ctrl in page.Header.Controls)
    {
        if (ctrl is HtmlMeta
            && ((HtmlMeta)ctrl).Name.ToLowerInvariant() == "robots")
        {
            tag = (HtmlMeta)ctrl;
            tag.Content = metaContent;
            break;
        }
    }

    if (tag == null)
    {
        var meta = new HtmlMeta();
        meta.Name = "robots";
        meta.Content = metaContent;

        page.Header.Controls.Add(meta);
    }
}

So kann nun einfach in jeder Seite des Blog der richtige Wert für den robots-Tag gesetzt werden. In der Startseite, dem Archiv, im Web Slice Container und der Übersichtsseite für Artikelserien wird der Wert noindex, follow gesetzt. Im Page_Load Ereignis der jeweiligen Seite braucht nur ein Aufruf der obigen Methode zu erfolgen:

BlogUtils.AddMetaRobots("noindex, follow", this.Page);

In den Artikel- und statischen Seiten wird dementsprechend index, follow gesetzt.

BlogUtils.AddMetaRobots("index, follow", base.Page);

Fazit:

Wenn mir als Blogbetreiber von den einschlägigen Suchmaschinen ein Werkzeug zur Steuerung der Suchmaschinenbots zur Verfügung gestellt wird, warum sollte ich es dann nicht nutzen?
In der heutigen Zeit, mit über 180 Millionen Seiten im Internet, ist die Auswahl an Informationen nahezu unüberschaubar. Die Anzahl der SERPs jeder Suchanfrage steigen ständig. Wie soll unter diesen Voraussetzungen ein Artikel meines Blog überhaupt gefunden werden? Wenn ich nichts dafür tue, mit Sicherheit gar nicht.

Technorati-Tags: | | |

TT.DOM in der aktuellen dotnetpro

12.03.2010 13:39:00 | Jörg Neumann

In der aktuellen Ausgabe der dotnetpro (4/2010) ist der erste Teil meiner vierteiligen Artikelserie über TT.DOM erschienen. Hierin geht es zunächst um die Grundlagen von Datenbindung und Eingabevalidierung in Windows Forms, WPF und Silverlight.

Aus dem Abstract:

In verteilten Anwendungen spielen Datenklassen eine zentrale Rolle. Doch um diese zu erstellen, an die Oberfläche zu binden und zwischen den Schichten zu transferieren, müssen einige Hürden genommen werden. Hierbei spielen Datenbindung, Änderungsverfolgung und Transaktionsverwaltung eine zentrale Rolle. Haben Ihnen in der Vergangenheit DataSet und Co. den größten Teil der Arbeit abgenommen, müssen Sie sich bei der Entwicklung eigener Datenklassen um Vieles selbst kümmern. dotnetpro beleuchtet in dieser Artikelserie die wichtigsten Grundlagen und stellt ein Objektmodell vor, das ihnen einen Großteil der Arbeit abnimmt.

dnp_042010

Ich werde nicht schreiben…

12.03.2010 00:40:00 | Jürgen Gutsch

… dass das die RTM des ASP.NET MVC 2.0 für .NET 3.5 und Visual Studio 2008 draußen ist. Das haben andere bereits zur Genüge getan.
(Und wahrscheinlich werden es im Laufe des Tage noch einige mehr tun.)

Hier eine kleine Auswahl:

Alexander Zeitler:
ASP.NET MVC 2 RTM – für .NET Framework 3.5 SP 1 / Visual Studio 2008

Robert Mühsig:
ASP.NET MVC 2 ist RTM (für VS2008)

Scott Guthrie:
ASP.NET MVC 2 Released

Scott Hanselmann:
ASP.NET MVC 2 Released

Phil Haak:
ASP.NET MVC 2 Released!

Shiju Varghese:
ASP.NET MVC 2 RTM Released !

ASP.NET:
http://www.asp.net/mvc/

Außerdem gibt es Unterstützung für die Installation von ASP.NET MVC (per Web Plattform Installer), Anleitungen zur Migration von Version 1 nach Version 2. Die aktuellen Sourcen sind ebenfalls verfügbar unter codeplex.com (siehe obige Links)

DotNetKicks-DE Image

ASP.NET Webforms Anwendungen und Ajax (Teil 6) kleine Tipps die das Leben leichter machen.

11.03.2010 21:44:25 | Andre Kraemer

In den letzten 5 Einträgen meines Blogs habe ich über verschiedene Möglichkeiten geschrieben Ajax in einer ASP.NET Webforms zu implementieren.

Angefangen mit dem manuellen Weg über das XmlHttpRequest Objekt ging es weiter zu Client Callbacks, dem Updatepanel, dem ASP.NET Ajax Framework sowie jQuery.

Der Fokus meiner Beiträge lag darauf nicht nur einfach zu zeigen welche Möglichkeiten es gibt, sondern zusätzlich auch zu zeigen, welche Datenmengen über die Leitung gehen und ob bzw. welche Teile des ASP.NET Page Life Cycles durchlaufen werden.

Ich hoffe dass ich bei dem ein oder anderen Leser für manchen Aha Effekt sorgen konnte. Zumindest ging es mir persönlich bei der ersten detaillierten Auseinandersetzung mit dem Thema so. Schließlich ist man als ASP.NET Webforms Entwickler traditionell doch eher auf dem Server zu Hause und realisiert vorerst garnicht welchen Overhead Client Callbacks oder das Updatepanel mit sich bringen.

Mein persönliches Fazit ist, dass Updatepanel und Client Callbacks korrekt eingesetzt in einigen Fällen vielleicht berechtigte Alternativen sind, in den meisten Fällen jedoch zum Ajax Framework oder jQuery gegriffen werden sollte.

Meine zurzeit favorisierte Lösung ist - ähnlich wie bei vielen anderen sicherlich auch - der Einsatz von jQuery.

Da mein letztes Beispiel noch ein wenig aufgebläht war, möchte ich an dieser Stelle zwei kurze Tipps geben, die die Arbeit mit jQuery und Ajax ein wenig erleichtern.

Der erste Punkt beschäftigt sich mit der großen Redundanz zwischen den verschiedenen Ajax Aufrufen:

$("#StaticFileLink").click(function(e) {
    e.preventDefault();
    $.ajax({
        type: "POST",
        url: "Teil5.aspx/ReadStaticFile",
        data: "{}",
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: function(msg) {
            $("#content").html(msg.d);
        }
    });
});

$("#HelloWorldLink").click(function(e) {
    e.preventDefault();
    $.ajax({
        type: "POST",
        url: "AjaxDemoService.asmx/HelloWorld",
        data: "{}",
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: function(msg) {
            $("#content").html(msg.d);
        }
    });
});

$("#EchoLink").click(function(e) {
    e.preventDefault();
    var number = $("#EchoTextBox").val();
    var jsonData = "{ 'number' : '" + number + "'}";
    $.ajax({
        type: "POST",
        url: "AjaxDemoService.asmx/Echo",
        data: jsonData,
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: function(msg) {
            $("#content").html(msg.d);
        }
    });
});

Bereits beim ersten Blick auf den Quellcode fällt auf, dass die Werte einiger Parameter statisch zu sein scheinen. So haben folgende Parameter stets einen fixen Wert:

  • type
  • contentType
  • dataType

Außerdem ist zumindest in den ersten beiden Aufrufen auch der Eintrag für data gleich.

Ein Weg um diese Redundanz herum zu kommen wäre eine eigene Funktion, die nur die Variablen Parameter entgegen nimmt.

Standardwerte setzen

Eine andere Alternative besteht darin, Standardwerte für jQuery Ajax Aufrufe zu setzen. Dies sähe dann so aus:

<script type="text/javascript">
    $(document).ready(function() {
        $.ajaxSetup({
            type: "POST",
            data: "{}",
            contentType: "application/json; charset=utf-8",
            dataType: "json"
        });
        $("#StaticFileLink").click(function(e) {
            e.preventDefault();
            $.ajax({
                url: "Teil6.aspx/ReadStaticFile",
                success: function(msg) {
                    $("#content").html(msg.d);
                }
            });
        });

        $("#HelloWorldLink").click(function(e) {
            e.preventDefault();
            $.ajax({
                url: "AjaxDemoService.asmx/HelloWorld",
                success: function(msg) {
                    $("#content").html(msg.d);
                }
            });
        });

        $("#EchoLink").click(function(e) {
            e.preventDefault();
            var number = $("#EchoTextBox").val();
            var jsonData = "{ 'number' : '" + number + "'}";
            $.ajax({
                url: "AjaxDemoService.asmx/Echo",
                data: jsonData,
                success: function(msg) {
                    $("#content").html(msg.d);
                }
            });
        });
    });
</script>

Neu hinzugekommen sind die Zeilen 2 - 8. Diese setzen Standardwerte für alle folgenden Ajax Aufrufe. Diese Variante kann einiges an Code sparen, ist allerdings mit Vorsicht zu genießen. Sollte nämlich zum Beispiel ein jQuery Plug-In auf der Seite genutzt werden, dass auch die $.ajax Funktion nutzt, könnte es zu Seiteneffekten kommen. Konkret wäre dies der Fall, wenn einer der per .ajaxSetup gesetzten Parameter nicht überschrieben, aber mit einem anderen Wert erwartet wäre. Typischerweise würde dies für den contentType oder oder dataType geschehen.

Serialisieren - einfach gemacht

Eine weitere Unschönheit des gezeigten Quellcodes besteht darin, dass die String Variante des in JSON notierten Objekts data von Hand zusammen gebaut wurde. Dies ist natürlich nicht sonderlich schick. Abhilfe schafft die Funktion stringify des Objekts JSON. Einige Browser wie Firefox ab Version 3.5 oder IE ab der Version 8 haben bereits ein eingebautes Objekt JSON. Für alle anderen gibt es unter http://www.json.org/js.html eine JavaScript Library zum Download, die entsprechenden Support nachrüstet, falls noch nicht vorhanden.

Konkret sähe dies dann wie folgt aus:

<script src="scripts/json2.js" type="text/javascript"></script>

[ ... ]


$("#EchoLink").click(function(e) {
    e.preventDefault();
    var number = $("#EchoTextBox").val();
    var jsonData = { 'number': number };
    var jsonString = JSON.stringify(jsonData);
    $.ajax({
        url: "AjaxDemoService.asmx/Echo",
        data: jsonString,
        success: function(msg) {
            $("#content").html(msg.d);
        }
    });

Wie man sieht, wird nun in Zeile 9 zuerst ein JavaScript Objekt jsonData in JSON Notation erzeugt. Dies wird anschließend über JSON.stringify in Zeile 10 in einen String konvertiert. Bei diesem konkreten Beispiel mag der Vorteil noch nicht auf der Hand liegen, spätestens bei komplexen Objekten lernt man die Funktion stringify jedoch schnell zu schätzen.

Bei der Recherche zu den Beiträgen dieser Serie bin ich übrigens auf einen sehr gut geschriebenen Eintrag von Roberto Bez gestolpert. Roberto stellt in seinem Blog Post die verschiedenen Varianten kompakt gegenüber. Die Lektüre des Artikels kann ich jedem Ajax interessierten Webforms Entwickler wärmstens empfehlen.

Weiter hat René Drescher-Hackel in einem Kommentar zu meinem letzen Beitrag, dass mit Ajax.NET Professional (AJAX.PRO) eine weitere effiziente Alternative zur Verfügung steht. Ich muss gestehen, dass mir die Existenz dieses Frameworks bis jetzt vollkommen entgangen ist. Gelobe allerdings Besserung und werde es mir gerne ansehen und mein Beispiel damit umsetzen.



blog.codemurai.de © André Krämer |Impressum | Abonieren

Vorsicht mit Visible = false

11.03.2010 19:41:16 | Andre Kraemer

Eigentlich altbekannt, trotzdem bin ich gerade mal wieder darauf hereingefallen und schreibe des deshalb hier auf:

Ich wollte in einer ASP.NET Webforms Anwendung ein Servercontrol serverseitig über

meinControl.Visible = false;

ausblenden, um es nach einer Nutzeraktion auf dem Client wieder einzublenden:

$(Id$="MeinControl").show();

Leider funktioniert das allerdings nicht, da ein serverseitiges Visible = false dafür sorgte, dass das Control erst garnicht gerendert wurde und somit auf dem Client nicht verfügbar war.

Die simple Lösung im Codebehind:

meinControl.Style.Add(HtmlTextWriterStyle.Display, "none");

Dann klappts auch mit dem Einblenden ;-)

War dieser Beitrag hilfreich? Dann kick ihn doch bitte.



blog.codemurai.de © André Krämer |Impressum | Abonieren

TT.DOM: Runtime Proxies

11.03.2010 10:48:00 | Jörg Neumann

Bei TT.DOM steckt der Hauptteil der Logik in der Basisklasse DataObject. Von dieser leitet die jeweilige Datenklasse ab und hat dadurch Zugriff auf die Funktionalität. Doch was ist, wenn die Datenklasse bereits von einer anderen Basisklasse ableitet? Dies kann beispielsweise der Fall sein, wenn die Datenklassen in Form eines Entity Framework Modells vorliegen. Vielleicht wollen Sie auf Severseite auch nicht von einer Basisklasse ableiten, um Interoperabilität zu gewährleisten. Ein anderer Fall ist, wenn Sie sich WCF Proxy-Klassen von Visual Studio generieren lassen. In diesem Fall haben Sie keinen Einfluss auf die Basisklasse der Data Contracts.

Für solche Fälle bietet TT.DOM die Möglichkeit, dynamische Runtime Proxies für die Objekte zu erzeugen. Hierbei handelt es sich um Typen, die per Reflection.Emit zur Laufzeit erzeugt werden und einen Wrapper um die Datenklasse bilden.

Ein Runtime Proxy-Typ leitet von DataObject ab und enthält die selben Eigenschaften wie die jeweilige Datenklasse. In den Gettern und Settern der Eigenschaft werden die Anfragen an das Datenobjekt delegiert, welches zuvor im Konstruktor übergeben wurde. Das Ganze sieht dann in etwa wie folgt aus:

DataObjectProxy

Das folgende Beispiel zeigt den Code einer Proxyklasse für die fiktive Klasse Person.

public class Person_Proxy : DataObject
{
  private Person _originalObject;

  public Person_Proxy(Person person1)
  {
    this._originalObject = person1;
  }

  public string FirstName
  {
    get { return this._originalObject.FirstName; }
    set
    {
      base.OnPropertyChanging("FirstName");
      this._originalObject.FirstName = value;
      base.OnPropertyChanged("FirstName");
    }
  }
  ...
}

Proxyliste erzeugen

Die einfachste Art Runtime Proxies zu erzeugen, ist über die Extension Method .ToDataObjectListProxy(), welche auf alle Listen vom Typ IEnumerable angewendet werden kann. Hierbei wird ein Runtime Proxy für den jeweiligen Objekttyp erstellt und die Objekte in eine Liste vom Typ DataObjectList<T> gefüllt. Da T an dieser stelle den jeweiligen Proxy-Typ repräsentiert, können Sie die Liste nicht direkt verwenden (da ja der Proxy-Typ zur Entwurfszeit noch nicht existiert). Stattdessen gibt .ToDataObjectListProxy() eine Instanz von IDataObjectProxyList zurück, über die Sie die Member von DataObjectList<T> ansprechen können.

List<Person> results = personService.GetPersons();
IDataObjectProxyList list = results.ToDataObjectListProxy("Id");
list.BeginEdit();
...

Proxies manuell erzeugen

Zudem besteht auch die Möglichkeit Runtime Proxies manuell zu erzeugen. Hierfür stellt TT.DOM die Klasse ProxyFactory zu Verfügung. Diese stellt Methoden zur Erzeugung von Proxytypen, Objekten und Listen bereit.

// Proxytyp erstellen
ProxyFactory factory = new ProxyFactory();
Type proxyType =
  factory.CreateProxyType(typeof(Person), attributes);

// Proxyobjekt erstellen
DataObject obj = (DataObject)
  factory.CreateProxy(proxyType, person1);

// Proxyliste erstellen
IDataObjectProxyList proxyList =
  factory.CreateProxyCollection(proxyType, sourceList);

// Objekt der Liste hinzufügen
Person p = new Person() { FirstName = "Jörg" };
factory.Add(proxyList, p, typeof(Person));

Bei der Erstellung eines Proxytyps können Sie zusätzliche Anzeigeattribute, wie Browsable, ReadOnly, oder DisplayName angeben, mit denen die Eigenschaften des Proxytyps entsprechend dekoriert werden. Hierdurch können Sie Einfluss auf die Datenbindung nehmen (wie hier beschrieben). Zudem können Sie programmatisch Validierungsregeln einbringen, die von der Proxyklasse über das Interface IDataErrorInfo abgebildet werden, doch dazu mehr in einem separaten Post.

Verwendung der Proxyobjekte

Die Verwendung der Runtime Proxies bietet sich vor allem in Szenarien an, in denen die Objekte vor allem an die Oberfläche gebunden werden. Beim programmatischen Zugriff ergeben sich einige Besonderheiten. Da der Proxytyp nicht von der Datenklasse ableitet, können Sie nicht auf diese casten, was zur Folge hat, dass Sie nicht typisiert auf dessen Eigenschaften zugreifen können. Stattdessen bieten DataObject und IDataObjectProxyList entsprechende Zugriffsmethoden an.

DataObject.GetValue(string propertyName);
DataObject.SetValue(string propertyName, object value);

Alternativ können Sie sich aber auch das zugehörige Datenobjekt ermitteln.

Person p = proxyList.GetDataObject(0);
string firstName = p.FirstName;

Dies bietet sich besonders beim lesenden Zugriff an. Der schreibende Zugriff sollte jedoch immer über die SetValue()-Methode durchgeführt werden, da nur in diesem Fall die Änderung vom Change Tracking bzw. von der Undo-/Redo-Funktionalität berücksichtigt wird.

Das ist der Preis, den Sie für die Flexibilität zahlen müssen ;)

Ableitung vs. Delegation

Das TT.DOM-Proxyverfahren unterscheidet sich von den üblichen Proxy-Generierungskonzepten. So leiten z.B. die Proxies von EF4 direkt von der jeweiligen Datenklasse ab und delegieren die Änderungen an einen zentralen State Manager weiter. Dies hat den Vorteil, dass Sie die Proxies auf den Typ Ihrer Datenklasse casten und somit typisiert auf dessen Eigenschaften zugreifen können.

Damit dieses Verfahren jedoch funktioniert, muss die Datenklasse sämtliche Eigenschaften als virtual definieren. Da dies jedoch nicht immer vorausgesetzt werden kann und auch nicht vom WCF Proxy Generator unterstützt wird, habe ich mich bei meiner Implementierung dagegen entschieden. Zudem ist es auch beim EF4-Ansatz zwingend erforderlich neue Objektinstanzen über eine Factory zu erzeugen, um Change Tracking zu gewährleisten.

NEW Version 3.4 TeamSpeak Sidebar Gadget für Windows Vista und Windows 7

10.03.2010 20:18:00 | Andreas Mehl

Server Migration! New Server (IP: 212.227.134.98) .Change it in your teamspeak server query_ip_whitelist.txt.

I have released a new version from my teamspeak sidebar gadget.

What i added was:

  • Added Extra Language: Spanish

Screenshots can be found here: Screenshots

Documentation can be found here: Documentation

Have fun Laughing

Download Sidebar Gadget Teamspeak 3.4

Eindrücke vom dotnetpro powerday zum Thema CCD

10.03.2010 19:48:00 | Martin Hey

Ein professioneller Softwareentwickler - was kennzeichnet ihn eigentlich? Mit dieser Frage starten Ralf Westphal und Stefan Lieser, wenn sie erklären, worum es bei der Clean-Code-Developer-Initiative eigentlich geht. Und genau so beginnt auch die Keynote des dotnetpro powerdays zum Thema CCD, der am 09.03.2010 in München stattfand. Die Antworten aus dem Publikum sind sehr vielseitig: "Man hat Erfahrung.", "Man schreibt wiederverwendbaren Code", "Jemand ist bereit, einem Geld für die Leistung zu geben", "Man schreibt Code, den andere verstehen" hört man Wortmeldungen aus allen Richtungen. Aber sind das wirklich die Kriterien? "Wiederverwendbarkeit? - Ich möchte keinen Klempner, der Dinge wieder verwendet, weil das professionell ist", meint Ralf und macht damit klar: Nicht das sind die Kriterien für Professionalität, sondern eine Mischung aus Bewusstheit und Prinzipien. Mit viel Witz und mehren verschenkten Mausmatten als Belohnung für interessante Antworten führen die beiden durch die Keynote und bringen so jedem das Thema näher.

Klar ist, die beiden wissen was sie rüberbringen wollen und vertreten da auch ihre Meinung recht konsequent. Selbst langjährige und erfahrene Entwickler betrachten Probleme mal aus einem anderen Blickwinkel, wenn Aussagen wie "Wozu brauche ich einen Debugger – meine Tests zeigen mir doch, wo der Fehler ist", "Zum Erstellen einer Softwarearchitektur braucht man keine Tools – nur ein Flipchart" im Raum stehen - und wenn uns jemand nach einer Software-Architektur für ein Warenwirtschaftssystem gefragt hat, haben wir dann nicht alle mit einem einzigen "großen Kreis mit Bubbel in der Mitte" auf dem Flipchartpapier geantwortet?
"Wie vermeide ich Abhängigkeiten?", war die Frage, die einen Abstecher in Richtung Event Based Programming mit den Hauptakteuren "Paula Portal", "Anton Adapter", "Frieda Filter" und "Zacharias Zähler" bescherte, die gemeinsam die Codezeilen einer Datei zählten, während "König Kunde" sich einen neuen Kaffee holte.

Der Nachmittag bestand dan darin, eine "Brownfield-Anwendung" mit Gummistiefeln zu betreten und im Sinne von CCD sauber zu machen. Leider musste ich nach der Ermittlung der guten und schlechten Eigenschaften der Anwendung die Veranstaltung verlassen, weil sonst mein Flieger ohne mich gestartet wäre, aber ich denke das anschließende Refactoring der Anwendung war auch noch sehr interessant.

Ja, ich mag die Art von Stefan und Ralf, wie sie solche Veranstaltungen durchführen - mal ganz unabhängig davon, ob es eine kostenpflichtige Veranstaltung wie der CCD-Powerday oder eine kostenfreie wie Usergroup-Treffen oder OpenSpaces sind. Durch diese Art wird man abseits vom täglichen Geschäft mal dazu animiert, neue Wege einzuschlagen oder anders an ein Thema heranzugehen. Und unabhängig davon, ob man CCD unterstützt oder nicht - die Notwendigkeit professionell zu arbeiten gibt es durchaus und die sollte auch immer im Hinterkopf sein. Und die Initative hin zur Professionalität unterstütze ich aus vollster Überzeugung.

TT.DOM: Change Tracking

10.03.2010 16:55:00 | Jörg Neumann

Wie im letzten Post bereits beschrieben, stellt TT.DOM mit der Basisklasse DataObject eine Reihe von Datenbindungsfunktionen bereit.

Darüber hinaus ist DataObject aber auch in der Lage, automatisch die Originalwerte der geänderten Eigenschaften eines Objekts zu speichern. Dies ist vor allem für eine spätere Datenbankaktualisierung hilfreich. Die Änderungsverfolgung muss jedoch explizit aktiviert werden, um zu vermeiden, dass Änderungen bereits beim Befüllen der Objekte protokolliert werden. Hierfür bietet DataObject und DataObjectList<T> die Methode BeginEdit().

List<Person> persons = service.GetPersons();
var list = persons.ToDataObjectList("Id");
list.BeginEdit();

Zudem kann die Änderungsverfolgung auch durch Setzen der Mode-Eigenschaft auf Objektebene festgelegt werden.

Um festzustellen, welche Datenobjekte geändert wurden, können Sie die State-Eigenschaft abfragen. Diese enthält je nach Änderung den Wert Unchanged, Insert, Update oder Delete.

Über die Methode GetChanges() können die geänderten Objekte abgefragt werden.

List<Person> changes = list.GetChanges();

Alternativ können auch Änderungen eines bestimmten Typs abgefragt werden.

List<Person> updates = 
  list.GetChanges(DataObjectStateType.Update);

Wollen Sie die Änderungen an einen WCF-Service übertragen, können Sie die Methode SaveChanges() nutzen. Diese nimmt drei Function Delegates für die Methoden Update Insert und Delete entgegen.

list.SaveChanges<Customer>(
    c => service.UpdateCustomer(c),
    c => service.InsertCustomer(c),
    c => service.DeleteCustomer(c));

Hierbei wird davon ausgegangen, dass ein WCF-Service Proxy mit folgender Signatur existiert:

public Person UpdatePerson(Person p);
public Person InsertPerson(Person p);
public void DeletePerson(Person p);

Alternativ können Sie auch alle Änderungen an den Service übertragen und serverseitig auf den jeweiligen Änderungstyp filtern.

List<Person> changes = list.GetChanges();
service.UpdatePersons(changes);

Auf Serverseite können Sie daraufhin den Status der Objekte, sowie deren Originalwerte ermitteln.

public List<Person> UpdatePersons(List<Person> changes)
{
  foreach (Person p in changes)
  {
    switch (p.State)
    {
      case DataObjectStateType.Update:
        var orgValue = p.GetOriginalValue("Name");
        // Datensatz in DB aktualisieren
      …
    }
  }
}

Hierbei sollte die Service-Methode nicht nur eine Liste der Objekte entgegen nehmen, sondern auch zurückgeben. Dies ist erforderlich, da auf Datenbankseite z.B. Identity-Werte oder Timestamps vergeben werden, die an den Client zurück synchronisiert werden müssen.

Hierfür können Sie auf Clientseite die Methode MergeItems() aufrufen und die lokale Liste mit der serverseitigen synchronisieren.

List<Person> changes = list.GetChanges();
List<Person> refrehedList =
  service.UpdatePersons(changes);
list.MergeItems(refreshedList);

Wenn Sie jedoch oben genannte SaveChanges()-Methode aufrufen, können Sie sich diesen separaten Schritt sparen, da dieser automatisch durchgeführt wird.

Undo/Redo

Neben dem Speichern der Originalwerte, kann DataObject und DataObjectList<T> auch beliebige Änderungen rückgängig machen bzw. wiederholen. Beide Klassen bieten hierfür die Methoden Undo() und Redo(). Darüber hinaus können Sie auch einen benannten Undo-Punkt definieren, zu dem zurückgesprungen werden soll. Hierfür legen Sie zunächst über die Methode SetUndoPoint() einen Punkt an und geben diesem einen beliebigen Namen. Einer Überladung der Undo()-Methode können Sie daraufhin den Namen übergeben und alle bis dahin durchgeführten Änderungen werden entsprechen zurückgerollt.

list.SetUndoPoint("MyUndoPoint");
list[0].Name += "*";
list.Add(new Person() { Name = "Bob" };
list.Remove(1);
list.Undo("MyUndoPoint");

Wenn Sie mitbekommen wollen, ob sich die Undo- oder Redo-Liste geändert hat, können Sie sich auf das UndoListChanged bzw. RedoListChanged-Event anmelden.

Einladung zum Treffen der .NET Usergroup Dresden

09.03.2010 20:57:00 | Martin Hey

Am 24. März um 18:00 Uhr findet das nächste Treffen der .NET Usergroup Dresden in den Räumen der T-Systems MMS statt. Die große Überschrift für den Abend lautet Silverlight 4 und wir haben wieder zwei sehr interessante Vorträge dabei.

Beginnen wird der Abend mit Zurück in die Zukunft mit Silverlight 4 von Gregor Biswanger. Gregor selbst ist sicher dem ein oder anderen schon durch seine Tätigkeit als Sprecher auf diversen Konferenzen und Autor in Entwicklermagazinen bekannt. Sein Vortrag bei uns demonstriert die Highlights von Silverlight 4 und geht zudem auf Erwartungen bezüglich Silverlight 5 ein. Zusammengefasst: Wir können schon heute sehen, was uns morgen mit Silverlight 4 erwarten wird.

Im zweiten Teil geht es um das Silverlight Augmented Reality Toolkit (SLARToolkit), das René Schulte entwickelt hat und das er uns vorstellen wird. Mehr Informationen von und über René findet ihr auf seinem Blog und wer sich bereits im Vorab über das Toolkit informieren möchte, kann sich bei Codeplex informieren.

Der Abend verspricht wieder sehr interessant zu werden.

Tiefergehende Informationen zum Termin finden sich auf der Seite der .NET Usergroup Dresden. Dort gibt es auch einen Link zur Anmeldung für den Abend.

Image Carousel in Silverlight

09.03.2010 16:11:01 | Oliver Scheer

Ein großes Hobby von mir sind Steuerelemente für Silverlight. Es gibt extrem viele tolle Beispiele an Tricks und Effekten in Silverlight. Doch leider sind diese sehr oft nur schwer übertragbar, da es sich dabei um Spaghetti-Code handelt oder hart-verdrahtete Konstanten verwendet werden.

Im heutige Beispiel erstelle ich ein Bilderkaroussel das man dynamisch anpassen kann, so wie man es von “echten” Steuerelementen gewohnt ist.

image

In Blend hat kann man nun beliebige Bilder einfügen, anpassen und sortieren.

image

Der Objektbaum wird dabei im Objects&Timeline-Bereich ordentlich dargestellt.

Der gesamte Sourcecode:

using System;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace TheOliver.Controls
{
    public class ImageSpindle : Panel
    {
        Point _mousePoint;
        double _height;
        double _width;
        bool _isMouseOver;

        public ImageSpindle()
        {
            this.Loaded += (s, e) =>
                {
                    if (DesignerProperties.GetIsInDesignMode(this))
                    {
                        return;
                    }

                    this.MouseMove += (s1, e1) =>
                        {
                            _mousePoint = e1.GetPosition(this);
                        }; 

                    CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
                };

            this.MouseEnter += (s, e) =>
                {
                    _isMouseOver = true;
                };

            this.MouseLeave += (s, e) =>
                {
                    _isMouseOver = false;
                };
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            _height = availableSize.Height;
            _width = availableSize.Width;

            var images = this.Children.OfType<Image>();
            int imageCount = images.Count();
            if (imageCount > 0)
            {
                double step = 360.0 / imageCount;
                double currentStep = 0;
                foreach (var image in images)
                {
                    UpdateImage(image, currentStep);
                    currentStep += step;
                }
            }
            return base.MeasureOverride(availableSize);
        }

        private Image UpdateImage(Image image, double step)
        {
            image.Height = ImageHeight;
            image.Width = ImageWidth;
            image.Margin = new Thickness(
                (_width - ImageWidth) / 2, (_height - ImageHeight) / 2, 
                (_width - ImageWidth) / 2, (_height - ImageHeight) / 2); 
            image.RenderTransformOrigin = new Point(0.5, 0.5);
            image.Stretch = ImageStretch;

            PlaneProjection pp = new PlaneProjection();
            pp.CenterOfRotationZ = SpindleCenterOfRotation;
            pp.RotationY = step;
            image.Projection = pp;

            return image;
        }

        void CompositionTarget_Rendering(object sender, EventArgs e)
        {
            if (StopWhenMouseLeft)
            {
                if (!_isMouseOver)
                {
                    return;
                }
            }

            if (double.IsNaN(_width) || _width == 0)
            {
                return;
            }

            foreach (var image in this.Children.OfType<Image>())
            {
                PlaneProjection pp = image.Projection as PlaneProjection;
                if (pp != null)
                {
                    pp.RotationY += ((_mousePoint.X - (_width / 2)) / _width) * 10;
                }
                image.Opacity = (_mousePoint.Y / _height) * 0.5 + 0.5;
            }
        }

        #region Properties

        public Stretch ImageStretch
        {
            get { return (Stretch)GetValue(ImageStretchProperty); }
            set { SetValue(ImageStretchProperty, value); }
        }

        public static readonly DependencyProperty ImageStretchProperty =
            DependencyProperty.Register(
                "ImageStretch", 
                typeof(Stretch), 
                typeof(ImageSpindle), 
                new PropertyMetadata(Stretch.Uniform, OnValueChanged));

        public double ImageWidth
        {
            get { return (double)GetValue(ImageWidthProperty); }
            set { SetValue(ImageWidthProperty, value); }
        }

        public static readonly DependencyProperty ImageWidthProperty =
            DependencyProperty.Register(
                "ImageWidth", 
                typeof(double), 
                typeof(ImageSpindle), 
                new PropertyMetadata(160.0, OnValueChanged));

        public double ImageHeight
        {
            get { return (double)GetValue(ImageHeightProperty); }
            set { SetValue(ImageHeightProperty, value); }
        }

        public static readonly DependencyProperty ImageHeightProperty =
            DependencyProperty.Register(
                "ImageHeight", 
                typeof(double), 
                typeof(ImageSpindle), 
                new PropertyMetadata(120.0, OnValueChanged));

        public double SpindleCenterOfRotation
        {
            get { return (double)GetValue(SpindleCenterOfRotationProperty); }
            set { SetValue(SpindleCenterOfRotationProperty, value); }
        }

        public static readonly DependencyProperty SpindleCenterOfRotationProperty =
            DependencyProperty.Register(
                "SpindleCenterOfRotation", 
                typeof(double), 
                typeof(ImageSpindle), 
                new PropertyMetadata(-160.0, OnValueChanged));

        private static void OnValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ImageSpindle spindle = sender as ImageSpindle;
            spindle.InvalidateMeasure();
        }

        public bool StopWhenMouseLeft
        {
            get { return (bool)GetValue(StopWhenMouseLeftProperty); }
            set { SetValue(StopWhenMouseLeftProperty, value); }
        }

        public static readonly DependencyProperty StopWhenMouseLeftProperty =
            DependencyProperty.Register(
                "StopWhenMouseLeft", 
                typeof(bool), 
                typeof(ImageSpindle), 
                new PropertyMetadata(true));

        #endregion

    }
}

Dieses und weitere Controls befinden sich in meiner Control-Bibliothek unter http://theolivercontrols.codeplex.com/ Viel Spaß

Assemblies mit Team Build 2010 automatisch Versionieren

09.03.2010 14:49:19 | Christian Binder

Eine der häufigsten Anforderungen von Teams ist die automatische Versionierung von Assemblies durch Team Build. Also in der Eigenschaften des Assemblies eine entsprechende File Version zu haben, durch die jeder Zeit der entsprechende SourceCode und Build identifiziert werden kann.

image

Zum Thema hatte ich schon für VS 2008 einen entsprechenden Blogeintrag geschrieben. Da mit TFS 2010 Team Build WF 4.0 für den Workflow verwendet, ergeben sich hier einige neue Möglichkeiten. Mit TFS 2010 RTM ist leider keine fertige WF Activity für diesen Zweck an Board. Halb so schlimm, da Jim Lamb auf seinem Blog bereits eine entsprechende WF Activity mit genauer Beschreibung bereit gestellt hat. Warum schreibe ich dann drüber? Weil Jim sich auf das Activity Development fokusiert und zeige ich in folgendem Video Step by Step, wie man die Activity in Team Build verwenden kann:

Assemblies mit Team Build Versionieren

Alternativ gibt es noch von der AIT die kostenfreie Buildsuite2010, die ebenso eine Activity zur Versionierung von Assemblies enthält.

Da Team Build Templates als XAML in Version Control abgelegt werden, möchte man diese vielleicht direkt im WF Designer, also ohne den Kontext eines Projektes zu haben, anpassen und Custom Activities nutzen. Was aber tun, wenn der Designer für die Custom Activity dann ein Fehler anzeigt (dies wird auch hier der Fall sein):

image

In folgendem Video zeige ich Ursache und Lösung:

Custom Build Activities in Team Build nutzen

Viel Spass
Chris

TT.DOM: Datenbindung

09.03.2010 07:34:00 | Jörg Neumann

Wie hier bereits erwähnt, unterstützt Thinktecture.DataObjectModel (TT.DOM) die Entwicklung flexibler Datenklassen. In den folgenden Posts werde ich die wichtigsten Features des Frameworks vorstellen. Den Anfang mache ich mit dem Thema Datenbindung.

Damit ein Objekt optimal an die Oberfläche gebunden werden kann, sollte die entsprechende Klasse eine Reihe von Interfaces implementieren. Über diese kommuniziert die Datenbindungsinfrastruktur mit den gebundenen Objekten um z.B. Synchronisation, Transaktionssteuerung oder Eingabevalidierung zu realisieren. Die folgende Abbildung zeigt diese Kommunikation:

Neumann_Datenklassen2

  • INotifyPropertyChanged dient zur Synchronisation zwischen Datenquelle und Ziel. Auf diese Weise werden Änderungen, die programmatisch an den Objekten durchgeführt werden, an das gebundene Steuerelement gemeldet, sodass dieses die Anzeige entsprechend aktualisieren kann.
  • INotifyPropertyChanging dient zur Signalisierung von Änderungen, bevor diese durchgeführt werden. Dies Interface hat keine direkten Auswirkungen für die Bindung, ist jedoch für Change Tracking und Transaktionssteuerung wichtig.
  • IEditableObject stellt ein transaktionales Verhalten für die Datenbindung bereit. So können Sie beispielsweise mehrere Zellen in einem Grid geändert und per ESC wieder zurück gerollt werden.
  • IDataErrorInfo ist für die clientseitige Validierung zuständig. So kann der Benutzer bereits während der Eingabe auf fehlerhafte Werte aufmerksam gemacht werden.

Wie Sie sehen, gibt es eine Menge zu tun um eine Datenklassen für die Datenbindung zu optimieren.

Hier kommt TT.DOM ins Spiel. Es definiert die abstrakte Basisklasse DataObject, welche die oben genannten Interfaces implementiert. Sie können nun Ihre Datenklassen von DataObject ableiten und haben fast automatisch die entsprechenden Funktionalitäten. Das Einzige was Sie tun müssen, ist Änderungen an Ihren Properties an die Basisklasse zu melden.

public class Person : DataObject
{
  private string _name;
  public string Name
  {
    get { return _name; }
    set

      {
      base.OnPropertyChanging("Name");
      _name = value;
      base.OnPropertyChanged(“Name”); }
  }
}

Wollen Sie zusätzlich Validierungsregeln im Stile von IDataErrorInfo in der Datenklasse hinterlegen, überschreiben Sie zusätzlich den Indexer der Basisklasse und hinterlegen die Validierungsregeln nach folgendem Muster.

public class Person : DataObject
{
  ...
  public override string this[string columnName]
  {
    get
    {
      if ((columnName == "" || columnName == "Name") &&
          string.IsNullOrEmpty(this.FirstName))
      {
        return "\"Name\" ist ein Pflichtfeld!";
      }
      return string.Empty;
    }
  }
}

Auf diese Weise haben Sie Ihre Klasse ohne viel Aufwand mit Synchronisation, Transaktionssteuerung und Eingabevalidierung ausgestattet.

Wie Sie später noch sehen werden, bietet TT.DOM auch die Möglichkeit die Validierungsregeln programmatisch zur Laufzeit zu hinterlegen.

Listenbindung

Auch auf Listenebene müssen Sie für eine Synchronisation zwischen Datenquelle und Ziel sorgen. In Windows Forms und WPF können Sie hierfür das Interface IBindingList bzw. dessen Standardimplementierung BindingList<T> verwenden. Darüber hinaus stellt TT.DOM die Klasse DataObjectList<T> bereit. Diese leitet von BindingList<T> ab und stellt neben der Datenbindungsfunktionalität Einiges mehr zu Verfügung.

Um das Erstellen und Befüllen von DataObjectList<T> zu vereinfachen, stellt TT.DOM die Extension Method .ToDataObjectList() zu Verfügung. Sie kann auf alle Listen vom Typ IEnumerable angewendet werden.

List<Person> persons = service.GetPersons();
var list = persons.ToDataObjectList("Id");

Als Parameter wird der oder die Eigenschaften angegeben, die ein Objekt eindeutig identifizieren. Dies ist für eine spätere Synchronisation mit einem Middle Tier-Service notwendig, doch dazu  mehr in einem separaten Post ;)

Was habe ich vor über 10 Jahren programmiert?

08.03.2010 07:59:00 | Martin Hey

Schwelgen in Nostalgie - anders kann man das wohl gar nicht erklären. Vergangene Woche schrieb Mathias in einem Tweet, dass er in seinen alten Festplatten kramt und prompt hab auch ich überlegt, was ich vor etwa 10 Jahren so getrieben hab. Passend dazu kommt auch der Aufruf "Was hast du vor über zehn Jahren programmiert?" von Dariusz.

Festplatten oder Disketten von damals hab ich nicht mehr und ich hätte auch gar kein Laufwerk mehr für Disketten (wie die Zeit vergeht). Deshalb habe ich stattdessen mal etwas in meinem Gehirn gekramt. Fest steht, dass ich mich damals noch nicht mit C# beschäftigt habe. Und fest steht außerdem, dass ich in dieser Zeit gerade mitten im dualen Studium war.

In der Arbeit war VBA und Access 97 angesagt. Die Quellcodeverwaltung bestand darin, sich das Projekt vom Netzlaufwerk wegzukopieren und nach getaner Arbeit wieder hinzulegen. Ganz schön gruselig. Glücklicherweise hat sich das kurz darauf geändert und VSS wurde installiert. Ich wusste, dass es auch Visual Basic 6 gab (quasi die erwachsene Variante von VBA) und dass man damit Formular- und Kommandozeilenprogramme schreiben konnte. DLLs waren für mich damals noch irgendwas geheimnisvolles, wofür man unbedingt C++ braucht und womit ich mich partout nicht anfreunden konnte.

Und nebenbei hab ich mich mit Nicht-Microsoft-Feld rumgetrieben. Mein "Raumi" im Studentenwohnheim hat sich mit Java beschäftigt und sowohl der Ansatz, die Programme im Texteditor erstellen zu können als auch die Plattformunabhängigkeit haben mich fasziniert. Irgendwann war ich das Programmieren im Texteditor auch leid und hab mir eine Java-Entwicklungsumgebung gegönnt (damals JBuilder) und damit ging es schon etwas besser. Aber auch das Interesse verebbte ganz schnell, da ich keine Idee für ein wirkliches Projekt hatte.

Das besagte Projekt war dann die Homepage der Seminargruppe. Die Vision: Eine Präsentation der Seminargruppe nach außen, einen Mitgliederbereich wo man Unterlagen runterladen kann (für die die mal länger schlafen wollten), eine Erinnerungsfunktion für Geburtstage und eine Kontaktliste mit Emailadresse, ICQ-Nummer und Raumnummer im Wohnheim - die Inhalte dort sollten vom Nutzer selbst aktuell gehalten werden. Nun ja, der Weg von Java zu JSP war nicht weit und so habe ich mit 2 Kommilitonen die Seite mit statischen und dynamischen Elementen in HTML und JSP aufgebaut. Zusammengeschubse von Elementen in WYSIWYG-Editoren fand ich damals schon furchtbar und so haben wir HTML in Reinform geschrieben bzw. generiert.

Die Seite ist mittlerweile gestorben, aber die Erinnerung lebt ;)

Warum nicht CSS-Dateien in Abhängigkeit laden?

07.03.2010 17:03:00 | Klaus Bock

In Abhängigkeit wovon, werden sich jetzt die meisten fragen. Na in Abhängigkeit zur gerade geladenen Seite einer Web-Anwendung.

Diesen Gedanken verfolge ich schon länger, habe ihn aber immer wieder verworfen. Vor ein paar Tagen bin ich auf dem Internet Explorer Weblog über ein interessantes kleines Tool Namens CSS Crunch gestolpert. Es handelt sich dabei um eine IE Erweiterung für Entwickler. Eigentlich ist es nur ein Javascript, welches zur Laufzeit in die aktuelle Seite injiziert wird und das Vorkommen einer jeden CSS-Klasse zählt. Einfach, aber es erledigt seine Aufgabe.

Nach den ersten Analysen, war ich erst einmal erstaunt, wie viele ungenutzte CSS-Klassen, außer den momentan nicht genutzten, meine CSS-Datei enthielt. Alles Leichen, die im Laufe der Zeit übrig geblieben waren.
Dabei griff ich auch die alte Idee des abhängigen Ladens der CSS-Dateien wieder auf und begann ihn umzusetzen.

Bei der Aufteilung der zentralen CSS-Datei, galt es ein paar Grundregeln zu beherzigen.
In den Google Webmaster Tools wird immer empfohlen, CSS-Dateien in einer Datei zusammen zu fassen. Wie also verfahren?
Ich entschied mich, die CSS-Klassen der weniger verwendeten Seiten wie etwa das Archiv, die Suche und die Artikelserien in eigene Dateien auszulagern und bei Bedarf zu laden.
Normalerweise würde ich das im ContentPlaceHolder head der jeweiligen Seite erledigen. In BlogEngine.NET ist dies so jedoch nicht vorgesehen, da die MasterPage des jeweiligen Theme nur jeweils einen ContentPlaceHolder für den Inhalt bereit stellt. Also wird das setzen der benötigten Verknüpfung von einer Hilfsmethode erledigt. Dieser Methode muss lediglich der Name der zu verwendenden CSS-Datei und ein Verweis zur aktuellen Page Instanz übergeben werden.

public static void AddCssLink(string cssName, AspPage page)
{
    if (cssName.EndsWith(".css", StringComparison.OrdinalIgnoreCase))
    {
        cssName = cssName.Substring(0, cssName.IndexOf(".css", StringComparison.OrdinalIgnoreCase));
    }

    var name = cssName + BlogSettings.Instance.Version() + ".css";

    foreach (Control control in page.Header.Controls)
    {
        if (control is HtmlLink
			&& ((HtmlLink)control).Href.EndsWith(name, StringComparison.OrdinalIgnoreCase))
        {
            return;
        }
    }

        var cssLink = new HtmlLink();
        cssLink.Attributes.Add("rel", "stylesheet");
        cssLink.Href = page.Master.TemplateSourceDirectory + "/css.axd?name=" + name;

        page.Header.Controls.Add(cssLink);
}

Die Methode prüft, ob die angegebenen CSS-Datei bereits im Header referenziert ist. Wird keine Referenz gefunden, wird die Verknüpfung dem Header hinzugefügt und somit die CSS-Datei geladen.
In der Seite search.aspx.cs würde das Page_Load Ereignis also so aussehen:

protected void Page_Load(object sender, EventArgs e)
{
    rep.ItemDataBound += new RepeaterItemEventHandler(rep_ItemDataBound);
    BlogUtils.AddCssLink("search.css", this.Page);

    if (!string.IsNullOrEmpty(Request.QueryString["q"]))
    {
		// hier mehr Code
    }
    else
    {
        Page.Title = Resources.labels.search;
        h1Headline.InnerHtml = Resources.labels.search;
    }
}

In Zeile 30 wird die CSS-Datei search.css eingebunden.

Mit dieser Hilfsmethode muss die Struktur der Masterpages in BlogEngine.NET nicht geändert werden, was bei folgenden Updates immer zu sehr viel Arbeit führt. Sollten Änderungen in den betroffenen Seiten, wie etwa der Suche, erfolgen, ist die Anpassung mit einer Zeile Code wieder hergestellt.

Fazit:

Da allem Anschein nach in naher Zukunft die Ladezeit von Webseiten sowie die benötigte Zeit zum Rendern im Browser immer mehr an Relevanz gewinnt, sollte man sich schon frühzeitig mit diesen Kriterien auseinander setzen. Vor allem wenn diese Kenngrößen einer Webseite als Bewertungskriterium für das Suchmaschinenranking herangezogen werden.

Technorati-Tags: | | |

Just Released: Thinktecture.DataObjectModel

07.03.2010 11:06:00 | Jörg Neumann

Bei der Entwicklung verteilter Anwendungen steht man als Entwickler häufig zwischen den Stühlen. Denn je nach Schicht ist man mit teilweise gegenläufige Anforderungen konfrontiert. Dies betrifft vor allem das Domänenmodell:

  • Aus Sicht der Middle Tier sollten Datenklassen dem POCO- bzw. DTO-Ansatz folgen, um eine möglichst hohe Interoperabilität zu gewährleisten.
  • Die Datenbankseite interessiert sich hingegen in erster Linie für die Originalwerte der geänderten Objekte, um die Datenkonsistenz bei parallelen Zugriffen gewährleisten zu können. Zudem ist auch Transaktionsunterstützung von Vorteil.
  • Auf Clientseite sollen die Objekte möglichst einfach gebunden werden können. Darüber hinaus müssen Änderungen verfolgt werden können, um eine spätere Aktualisierung zu gewährleisten. Der Anwender freut sich hingegen über Inline-Validierung und Undo/Redo-Support. Auch das dynamische Erstellten von Sortier- und Filterregeln zur Laufzeit ist sehr beliebt.

Das Problem ist nur, dass die vorhandenen Frameworks (WCF/WPF/EF) keine durchgängige Story für Datenklassen bieten, die allen Seiten gerecht wird.

Daher habe ich in den letzten Monaten an einem Framework gearbeitet, das diesen Missstand beheben soll: Das Thinktecture.DataObjectModel steht nun in einer ersten Betaversion auf CodePlex zu Verfügung.

Die wichtigsten Features:

  • Support für Data Binding
    (inkl. Validierung, Change Tracking und Undo/Redo-Support)
  • Dynamische Attributierung von Properties
    (DisplayName, ReadOnly, Browsable, Ordinal, …)
  • Implementierung von Views
    (inkl. Sortieren, Filtern, Computed Columns, etc.)
  • Automatische Speicherung von Originalwerten für die Behandlung von Konkurrenzsituationen auf Datenbankseite.
  • Übertragen von Objekten, inkl. Änderungen an WCF-Services
  • Unterstützung von System.Transactions. So können alle Objekte automatisch an lokalen oder verteilten Transaktionen teilnehmen.

Für die Verwendung kann die entsprechende Datenklasse entweder von einer Basisklasse ableiten, oder sie wird zur Laufzeit über einen Runtime Proxy mit der beschriebenen Funktionalität ausgestattet. Auf diese Weise können zum Beispiel auch Modelle vom Entity Framework oder anderen O/R-Mappern flexibel erweitert werden.

Weitere Informationen finden Sie auf http://dataobjectmodel.codeplex.com. Hier gibt’s nicht nur die Sourcen, sondern auch einige Beispiele für Windows Forms und WPF.

Darüber hinaus erscheint in den nächsten Monaten eine vierteilige Artikelserie in der dotnetpro, in der ich das Framework detailliert beschreiben werde.

Falls Sie Fragen oder Anregungen haben, geben Sie Feedback über das Forum der Codeplex-Seite oder per Mail (joerg neumann at thinktecture de)!

Eine bessere 404 Fehlerbehandlung in Blogengine.NET

06.03.2010 16:52:27 | Klaus Bock

Im Artikel Blogengine.NET und 404 Fehler habe ich bereits auf das seltsame Verhalten von BlogEngine.NET im Umgang mit 404 Fehlern hingewiesen. Ich dachte ich hätte eine Lösung gefunden, bis mich ein aufmerksamer Leser auf ein neues Problem in meiner Lösung hingewiesen hat. Der Kommentar kann im oben genannten Artikel nachgelesen werden.

Ich konnte zunächst nicht glauben, dass sich ein Robot, wie etwa der Google-Bot, tatsächlich so verhält und den Statuscode der error404.aspx ignoriert. Also habe ich im Google Webmaster Forum nachgefragt. Tatsächlich wurde mir dort dieses Verhalten, zumindest annähernd, bestätigt.

Nur so viel vorne weg: Wie man in folgendem Screenshot sehen kann, ist eine direkte Ausgabe der 404-Fehlerseite mit Statuscode 404 ohne 302 Weiterleitung durchaus möglich. So wird der Statuscode korrekt an den jeweiligen User Agent übertragen und ein Benutzer vor einem Browser bekommt eine benutzerdefinierte Fehlerseite präsentiert.

direkte Ausgabe der 404-Fehlerseite

Als erstes habe ich mich von der ASP.NET Fehlerbehandlung in der web.config verabschiedet, in dem ich customErrors Mode=”Off” gesetzt habe.
BlogEngine.NET bringt offiziell seit der Version 1.6.0.0 eine eigene Fehlerbehandlung in der Global.asax mit. Also musste ich mich nur in diese Fehlerbehandlung einklinken.
Standardmäßig wird in BlogEngine.NET in der Methode Application_Error  ein 404 Fehler ignoriert und die Fehlerbehandlung an dieser Stelle beendet.
Die Fehlerbehandlung muss somit um die Fähigkeit zum behandeln eines 404 Fehlers erweitert werden.

Da die error404.aspx.cs den URL-Parameter aspxerrorpath sowie den UrlReferrer der aktuellen Anforderung verwendet, müssen hier Vorbereitungen getroffen werden, dass diese Informationen auch zur Verfügung stehen. Da keine clientseite Weiterleitung stattfindet, ist eine Übergabe der Informationen via URL nicht möglich. Auch ist der UrlReferrer der verweisenden Seite nicht vorhanden, da ja eine serverseitige Umleitung vorgenommen wird.
Als einfachste Lösung habe ich die Eigenschaft HttpContext.Items des aktuellen HttpContext in Betracht gezogen. Es wird sowohl der Pfad der nicht gefundenen Ressource sowie der verweisende UrlReferrer in das Dictionary des aktuellen HttpContext geschrieben.
Anschließend wird der anstehende Fehler gelöscht und serverseitig auf die error404.aspx umgeleitet. In folgendem Listing ein Auszug der relevanten Passage aus der Methode Application_Error der Global.asax.

var currentPage = context.CurrentHandler as System.Web.UI.Page;

if ((ex as HttpException).GetHttpCode() == 404)
{
    context.Response.StatusCode = 404;
    context.Items["aspxerrorpath"] = context.Request.RawUrl;
    context.Items["urlReferrer"] = context.Request.UrlReferrer;
    this.Server.ClearError();

    if (currentPage != null && currentPage.IsCallback)
    {
        return;
    }

    context.Server.Transfer("~/error404.aspx");

    return;
}

Jetzt muss noch die error404.aspx.cs angepasst werden, damit sie die benötigten Informationen aus dem Dictionary Items des aktuellen HttpContext verwendet.
Als erstes habe ich zwei klassenweite Felder, errorPath und urlReferrer, erzeugt die beim Laden der Seite mit Werten belegt werden.
Das Feld errorPath wird anstatt des Url-Parameter aspxerrorpath verwendet und urlReferrer ersetzt den Zugriff auf den bisher verwendetet UrlReferrer.
Damit die vorgenommenen Änderungen leichter ersichtlich sind, habe ich in folgendem Listing den bisherigen Code lediglich auskommentiert.

private string errorPath = null;
private Uri urlReferrer = null;

protected void Page_Load(object sender, EventArgs e)
{
    if (this.Request.QueryString["aspxerrorpath"] == null)
    {
        this.errorPath = (string)HttpContext.Current.Items["aspxerrorpath"];
        this.urlReferrer = (Uri)HttpContext.Current.Items["urlReferrer"];
    }
    else
    {
        this.errorPath = (string)this.Request.QueryString["aspxerrorpath"];
        this.urlReferrer = this.Request.UrlReferrer;
    }

    //if (Request.QueryString["aspxerrorpath"] != null && Request.QueryString["aspxerrorpath"].Contains("/post/"))
    if (!string.IsNullOrEmpty(errorPath) && errorPath.Contains("/post/"))
    {
        DirectHitSearch();
        divDirectHit.Visible = true;
    }
    //else if (Request.UrlReferrer == null)
    else if (this.urlReferrer != null)
    {
        divDirectHit.Visible = true;
    }
    //else if (Request.UrlReferrer.Host == Request.Url.Host)
    else if (this.urlReferrer != null && this.urlReferrer.Host == this.Request.Url.Host)
    {
        divInternalReferrer.Visible = true;
    }
    else if (GetSearchKey() != string.Empty)
    {
        SearchTerm = GetSearchTerm(GetSearchKey());
        BindSearchResult();
        divSearchEngine.Visible = true;
    }
    // else if (Request.UrlReferrer != null)
    else if (this.urlReferrer != null)
    {
        divExternalReferrer.Visible = true;
    }

    Page.Title += Server.HtmlEncode(" - " + "Page not found");
}

Neben der Methode Page_Load muss auch die private Methode GetSearchKey angepasst werden, da sie ursprünglich den UrlReferrer verwendet.

private string GetSearchKey()
{
    if (this.urlReferrer == null)
    {
        return string.Empty;
    }

    //string referrer = Request.UrlReferrer.Host.ToLowerInvariant();
    var referrer = this.urlReferrer.Host.ToLowerInvariant();

    if (referrer.Contains("google.") && referrer.Contains("q="))
        return "q=";

    if (referrer.Contains("yahoo.") && referrer.Contains("p="))
        return "p=";

    if (referrer.Contains("q="))
        return "q=";

    return string.Empty;
}

Somit sind die Anpassungen in BlogEngine.NET abgeschlossen und einer besserer Behandlung von 404-Fehlern, vor allem ohne 302-Weiterleitung, steht nichts mehr im Weg.

Fazit:

Auf den ersten Blick, vor allem für den Benutzer, mag die 404 Fehlersteuerung in der web.config ja ganz angenehm sein. Will man aber eine, in allen Lagen und ohne 302, funktionierende Fehlerbehandlung, muss man selbst Hand anlegen.

Technorati-Tags: | |

Apps & Games für Windows Phone 7 Series: .NET, Silverlight, XNA

05.03.2010 14:37:51 | Oliver Scheer

Aus dem offiziellen Deutschen Windows Phone 7 Series Blog -->

Es sind nur noch wenige Tage bis zur MIX10, der Konferenz, auf der wir über die offizielle Entwicklerstory zu WP7S sprechen werden. Doch die Spekulationen kochen inzwischen immer höher, und ich erlebe das hier z.Zt. täglich auf der CeBIT – ca. 50% der Fragen drehen sich darum, wie & womit für die neuen Phones entwickelt werden kann (und das Interesse, das zu tun, ist riesig, was mich sehr freut).

Das Produktteam hat deshalb, um die Sache etwas zu beruhigen und die Erwartungen für Las Vegas richtig zu setzen, eine Art offizielle Aussage über Charlie Kindels Blog veröffentlicht. Hier ist die Essenz daraus: Softwareentwicklung für Windows Phone 7 Series beruht auf

  • SL.NET
  • Silverlight (!)
  • XNA (!)
  • maßgeschneiderten Tools dafür von Microsoft
  • Web-2.0-Mechanismen

Die Katze ist damit aus dem Sack: Silverlight als neue Oberflächentechnologie wird es auf einfache Art und Weise möglich machen, Apps zu bauen, die in Sachen User Experience dem restlichen WP7S-UI in nichts nachstehen. XNA wird für fantastische, auf einem Windows Phone bisher nicht dagewesene Games sorgen. Ich denke, das ist eine großartige Botschaft für alle, die von uns einen mutigen Neuanfang erwartet haben – wir haben ihn gemacht, in Entwicklerdingen genauso wie bei der Konzeption der Phones generell.

phones[1]

Mehr Details auf der MIX – und ab dann online und auf diversen Veranstaltungen auch hierzulande.

P.S.: Und übrigens – heute existierende Anwendungen werden auf WP7S nicht lauffähig sein, das lassen die fundamentalen Neuerungen einfach nicht zu. Es heißt also Ärmel hochkrempeln und portieren oder ganz neu starten – die neuen Möglichkeiten legen es nahe, und die Tools werden es einfach machen!

WPF: ICO vs. PNG

05.03.2010 13:20:00 | Jörg Neumann

Viele Entwickler verwenden in ihren WPF-Anwendungen noch immer die guten, alten Windows Icons. Diese werden von WPF jedoch nicht optimal gerendert, wie das folgende Beispiel zeigt:

IcoVsPng

Neben der allgemeinen Unschärfe beim Rendern von Icons, sorgt ein weiterer Umstand für unschöne Ergebnisse: Wenn die Icon-Datei mehrere Icons unterschiedlicher Größe enthält, wählt WPF standardmäßig das Erste aus (meist 16x16 Pixel) und vergrößert es entsprechend.

Stattdessen sollten Sie besser PNG-Bitmaps verwenden. Diese werden nicht nur “sauberer” dargestellt, sondern bieten auch die von Icons bekannte Transparenz.

Für die Konvertierung von ICO nach PNG benötigen Sie jedoch einen leistungsfähigen (und daher meist kostenpflichtigen) Icon-Editor. Haben Sie den nicht, können Sie alternativ auch Power Point verwenden. Und das geht wie folgt:

  • Konvertieren Sie zunächst die ICO-Datei mit Paint nach PNG.
  • Dann öffnen Sie diese in Power Point
  • Klicken Sie im Ribbon “Format” den Punkt “Neu einfärben” und dann “Transparente Farbe bestimmen” an.

PPTTransparent

  • Daraufhin selektieren Sie den Hintergrund des Icons und speichern das ganze wieder als PNG-Datei ab.

Problematisch kann es jedoch werden, wenn die Hintergrundfarbe ebenfalls im Symbol selbst verwendet wird, da die entsprechenden Bereich dann ebenfalls transparent dargestellt werden. Daher sollten Sie den Hintergrund ggf. vorher mit einer anderen Farbe füllen.

So richtig schön ist das ganze Verfahren zwar nicht, dafür aber kostenlos ;)

Fließend Infrastruktur-Komponenten konfigurieren

05.03.2010 12:48:00 | Jan Christian Selke

Ein aktuell sehr interessantes Thema ist die Anwendung von Interner DSL zur Konfiguration einzelner Komponenten innerhalb einer Anwendung. Den Namen Fluent API prägten Eric Evans und Martin Fowler. Der Name entstand aufgrund der starken Versprachlichung des Quellcodes. Bekannte OSS Projekte haben es bereits vorgemacht, zu nennen sind hier Fluent NHibernate, Rhino Mocks oder auch StructureMap. Dass es sich bei diesem Thema immer noch um ein hot topic handelt, zeigt auch das von Ralph Westphal in der dotnetpro 02/2010 gezeigte Interesse. Für ein kleines Testprojekt verfolge ich einen ähnlichen Ansatz - nur um ausprobieren, wie es funktioniert. Um mich noch etwas intensiver damit auseinander zu setzen, schreibe ich dieses mal über die Grundzüge meines Konfigurationsmechanismus. Vielleicht gibt es noch nebenbei konstruktiven Feedback...

Der Zugang zur Konfiguration

Aus gegebenem Anlass habe ich mir als Spielwiese die Konfiguration von log4net ausgesucht.

Als Zugang zu einer, in der Regel statischen Infrastruktur Komponente, kann ein Pattern ähnlich zu dem statischen Gateway genutzt werden. Eine ausführliche Beschreibung findet sich beispielsweise bei J.P. Boodhoo, der dieses Muster auch entsprechend Static Gateway Pattern nannte.

Ein solches Gateway nutze ich auch als zentrale, statische Klasse. Über diese wird konfiguriert aber auch die Funktionalität kann hierüber aufgerufen werden. Mein statisches Gateway folgt im groben dem folgenden Muster.

public static class Log
{
public static IConfiguration Configure(Action<ConfigurationExpression> configure);
public static ILogger Log();
}

Der Konfigurationsmechanismus


Die vollständige Konfigurationsmethode sieht wie folgt aus. Die Rückgabe eines IConfiguration Objekts ist notwendig zur Verifizierung der Konfiguration innerhalb der Unit-Tests.


public static IConfiguration Configure(Action<ConfigurationExpression> configure)
{
var configurationExpression = new ConfigurationExpression();
configure(configurationExpression);
return configurationExpression;
}

Als erstes fällt der Action<> delegate als Eingangsparameter der Configure() Methode auf. Zum Ausführen der Konfiguration nutze ich eine nested closure. Hiermit habe ich die Möglichkeit, Konfigurationsaufrufe zu kapseln und selbst die Kontrolle über Ort und Zeitpunkt der Ausführung zu haben und das innerhalb eines klar abgegrenzten Kontexts. Der geschachtelte anonyme Block wird als Parameter an die Methode übergeben und dann an benötigter Stelle im Objekt ausgeführt. Nested closures können innerhalb von C#  am einfachsten in Form von Action<> oder Func<> Delegates umgesetzt werden. Aus diesem Grund erhält die Methode Configure() als Eingangsparameter ein Action<> Delegate. Dass Delegate wiederum erwartet ein Objekt vom Typ ConfigurationExpression. Hierbei handelt es sich um einen ExpressionBuilder, der method chaining im fluent API Stil innerhalb des Aufrufs ermöglicht.


Log.Configure(x => 
{
x.UseTheDefaultRepository();
x.LogToConsole().WithDefaultLayoutPattern();
});

Mein ExpressionBuilder zur Konfiguration, die Klasse ConfigurationExpression, erbt direkt von der Konfigurationsklasse Configuration. Dadurch erhält er alle Methoden, die für die Konfiguration bereitgestellt werden. Durch die Rückgabe von sich selbst oder eines ConsoleConfigurationExpression Objekts, einer weiteren geschachtelten Expression, lassen sich die Methodenaufrufe verketten.


public class ConfigurationExpression : Configuration
{
}
public class Configuration : IConfiguration
{
private ILoggerRepository _loggerRepository;
private Assembly _assembly;

public ILoggerRepository LoggerRepository { get; set; }

public IConfiguration UseTheDefaultRepository()
{
_assembly = Assembly.GetExecutingAssembly();
_loggerRepository = LogManager.GetRepository(_assembly)
?? LogManager.CreateRepository(_assembly, typeof(Hierarchy));
return this;
}

public ConsoleConfigurationExpression LogToConsole()
{
var consoleExpression = new ConsoleConfigurationExpression(_loggerRepository);
return consoleExpression;
}

public IConfiguration LogToConsole(Action<ConsoleConfiguration> action)
{
var consoleExpression = new ConsoleConfiguration(_loggerRepository);
action(consoleExpression);
return this;
}

public IConfiguration ResetConfiguration()
{
_loggerRepository.ResetConfiguration();
return this;
}

public IConfiguration ShutdownLogging()
{
_loggerRepository.Shutdown();
return this;
}
}

Ausblick


Ich stelle mir zur Zeit vor, als nächstes einen CoC Ansatz für eine minimale externe Konfiguration zu verfolgen. Wider aller Dynamik und Konfiguration im Quellcode, besteht gerade im Falle des Protokollierens der Bedarf im laufenden System die Log Level herauf- oder herab zu setzen oder auch nur den Protokollpfad zu ändern. Hierfür sollte die Anwendung natürlich nicht neu kompiliert werden müssen…


Aber gerade diese Konfigurationsparameter werden ohnehin (fast) immer gleich benannt, oder folgen zumindest in der Nomenklatur einem wiederkehrenden Muster. Durch Implementierung eines default CoC Scanners und/oder einer ableitbaren Konventionen-Klasse ließe sich dies mit Sicherheit abbilden.

Neue Silverlight-Kolumne beim dot.net magazin: “Silverlight-Expertise – Die Cremé de la Cremé des Monats”

04.03.2010 20:32:32 | Gregor Biswanger

dotnet-magazin

In der neuen Ausgabe vom dot.net magazin startet meine neue Silverlight-Kolumne “Silverlight-Expertise”:

Silverlight-Expertise - Die Crème de la Crème des Monats

In der neuen Kolumne zum Thema Silverlight „Silverlight-Expertise“ des dot.NET Magazins präsentiert Gregor Biswanger ab sofort monatlich zwei leckere top How-tos. Einsteiger und fortgeschrittene Silverlight-Experten sollen hier durch geballtes Wissen gesättigt werden. Heute stehen zwei Punkte auf der Menükarte: „Silverlight Install Experience ans eigene Design anpassen“ und „WebBrowser-Steuerelement ab Silverlight 2 selbst schreiben“. Viel Spaß und einen guten Appetit.

Cover_DM_44b8e61f1072c8

Zu lesen sind die How-To´s beim dot.net magazin, Ausgabe 04/2010.

Neuer Artikel beim dot.net magazin - “Zurück in die Zukunft mit Silverlight 4”

04.03.2010 20:20:05 | Gregor Biswanger

dotnet-magazin

In der neuen Ausgabe vom dot.net magazin gibt es einen neuen Artikel meinerseits:

Zurück in die Zukunft mit Silverlight 4 - Bereits heute die Features der Zukunft erblicken.

Am 18. November 2009 veröffentlichte Microsoft auf der PDC 2009 (Professional Developer Converence) in Los Angeles die erste Betaversion von Silverlight 4 und somit auch alle Informationen zu geplanten und bereits verfügbaren Features.

Cover_DM_44b8e61f1072c8

Zu lesen ist der Artikel beim dot.net magazin, Ausgabe 04/2010.

 

Passend zum Artikel läuft derzeit die Roadshow: „Zurück in die Zukunft mit Silverlight 4“.

Am 18. November 2009 veröffentlichte Microsoft auf der PDC2009 (Professional Developer Converence) in Los Angeles die erste Beta Version von Silverlight 4, und somit auch alle Informationen dazu, welche Features dafür geplant und bereits verfügbar sind.

Mit Silverlight 4 geht Microsoft den in Version 3 eingeschlagenen Weg weiter und erweitert es mit Verbesserungen die direkt von den Entwicklern gewünscht wurden. Mit Silverlight 3 zeigte sich der RIA-Sprössling mehr als erwachsen und mit Silverlight 4 kommt noch einiges an Reife dazu.

Der Vortrag demonstriert die Highlights von Silverlight 4 und geht zudem bereits auf Erwartungen bezüglich Silverlight 5 ein. Kurz zusammengefasst: Wir können heute schon sehen, was uns mit Silverlight 4 erwarten wird.


Veranstaltungen auf folgenden User-Groups

Die kommenden Termine finden bei folgenden User Groups statt:

11.03.2010

.NET User Group Karlsruhe (http://www.dotnet-ka.de)

24.03.2010

.NET User Group Dresden (http://www.dd-dotnet.de)

Rückblicke

Die folgenden Termine haben bereits stattgefunden:

15.02.2010

Munichdotnet – Münchner .NET User Group (http://www.munichdot.net/Events/585.aspx)

18.01.2010

INdotNET – Ingolstädter .NET Developers Group (http://indot.net/events.html)

Geplante User Groups

Für folgende User Groups werden noch weitere Termine folgen:

.NET User Group Ulm

Weitere User Groups die an diesem Vortrag Interesse haben, schreiben mir bitte eine E-Mail an: gregor.biswanger@web-enliven.de

Visual Studio Lab Management 2010 RC VHD verfügbar

04.03.2010 12:06:00 | Christian Binder

Visual Studio Lab Management 2010 ist nicht mal kurz in 5min aufgesetzt, damit man aber dennoch schnell mal Testen kann, gibt es eine fertig konfigurierte VHD:

Visual Studio Lab Management 2010 RC

Auf dem Visual Studio Lab Management Team Blog findet man dann auch einige Getting Startet infos.

Viel Spass
Chris

dotnet Cologne 2010 am 28. Mai 2010 in Köln

03.03.2010 20:15:00 | Martin Hey

Mal wieder wirft ein Community-Event seine Schatten voraus: Am 28. Mai findet in Köln die Entwicklerkonferenz dotnet Cologne statt. Organisiert wird der Event von Albert Weinert, Roland Weigelt und Stefan Lange von den .NET Usergroups in Köln und Bonn. Schwerpunkt der insgesamt 18 Sessions in 3 parallelen Tracks sind Themen rund um Visual Studio 2010 und .NET 4.0, aber es wird sich bestimmt auch das ein oder andere Thema abseits dieses Themenkomplexes finden.

Seit heute kann man sich für die Konferenz anmelden und wie man den Tweets von dotnetCologne entnehmen kann, haben sich wohl schon fast die ersten 150 Teilnehmer gefunden.

Wie Jan schreibt, wird es am Abend noch eine Grillfete des dotnet-forum geben, zu der alle Teilnehmer der Konferenz eingeladen sind. Ich hoffe es wird schönes Wetter und das Grillen findet am See statt.

Laufend neue Informationen gibt es im Twitter unter dem Hashtag #dc2010 oder wenn man dotnetCologne folgt.

Anmeldung zur dotnet Cologne 2010 hat begonnen.

03.03.2010 12:43:45 | Albert Weinert

Heute morgen um 10:20 Uhr habe ich die Anmeldung zur dotnet Cologne 2010 freigeschaltet.

Die ersten die sich angemeldet haben müssen wohl schon vor dem Rechner gesessen haben und immer wieder auf den Teilnehmen Knopf gedrückt haben. Kaum Freigeschaltet waren schon 8 angemeldet und in der ersten Minute waren es 37. Ok, dann ebbte es ein wenig ab und es wurde was langsamer.

Teilnehmer

Aktuell (Stand 12:42 Uhr) sind es schon 109 Anmeldungen und somit sind nur noch ein paar Plätze zum Super Early Bird verfügbar. Wer diesen noch erwischen will muss sich somit sputen http://www.dotnet-cologne.de.

Es ist ein schönes Gefühl dabei zuzusehen wie die Anmeldungen eintrudeln.

Als Teilnehmer könnt Ihr euch sicher sein dass Ihr nicht alleine vor Ort sein werdet. Und wir als Veranstalter sind froh dass wir auf so reges Interesse stoßen. Wir wollen für Euch wirklich eine tolle Community Konferenz auf die Beine zu stellen.

Agenda

Das Programm steht zwar noch nicht komplett fest, jedoch möchten wir ein breites Specktrum von Vorträgen anbieten bei dem die Sprecher auch wirklich wissen wovon sie sprechen. Im zwei Wochen Rhythmus werden wir wohl Sprecher und Vorträge veröffentlichen. Natürlich suchen wir bis dass Programm fest geklopfft ist weitere interessante Vorträge also meldet Euch!

Sponsoren

Wir sind noch auf der Suche nach weiteren Sponsoren, wir haben als Ziel 250 Teilnehmer vor Ort und Luft nach Oben. Unsere letzten beiden Konferenzen haben gezeigt dass die Teilnehmer hochmotiviert und aus eigenen Antrieb zu uns kommen. Wenn Sie die größte .NET Community Entwickler Konferenz in Deutschland unterstützen möchten, so nehmen bitte Sie mit uns Kontakt auf. Unsere Sponsoring Pakete sind wirklich günstig.

Technorati Tags: ,,

Nicht nur Methoden lassen sich erweitern

02.03.2010 23:28:00 | Jan Christian Selke

Während einer Erkundungsreise in die Welt von Ruby, bin ich auf ein kleines und feines Feature gestoßen, dass mich nicht mehr losgelassen hat. Ich wollte so etwas unbedingt auch in C# haben…

Wer Ruby kennt, kennt auch die times Methode. Eine sehr elegante Alternative zur for-Schleife.

5.times { |i| puts i }

0
1
2
3
4

Diese Notation gefiel mir so sehr, dass ich beschloss etwas gleiches in C# umzusetzen. Dazu bot sich eine Extension-Method förmlich an.

Neben dem erweiterten Typ int übergebe ich einen Action delegate, der einen int Wert erwartet und innerhalb einer gekapselten for-Schleife ausgeführt wird. Übergeben wird der Wert der jeweiligen Iteration.

public static class NumericExtensions
{
public static void Times(this int count, Action<int> action)
{
for (int i = 0; i < count; i++)
{
action(i);
}
}
}

Der Aufruf hat jetzt eine gewisse Ähnlichkeit mit dem Ruby Original…


5.Times(x => Console.Out.WriteLine(string.Format("Runde {0}\r\n", x)));

Das Ergebnis lässt sich sehen, es funktioniert.



output

Sicherlich bin ich nicht der Erste mit einem solchen Ansatz und über den Nutzen lässt sich sicherlich streiten, aber hey… ich finde es einfach großartig! Das gleiche werde ich wohl auch für die Methoden upto und downto machen.


Was denkt Ihr darüber? Ich würde mich über Kommentare freuen.

Mythos entzaubert: Microsoft Update, Windows Update, Office Update

02.03.2010 17:18:36 | Kay Giza

Ich glaube dies wird ein sehr emotionaler Blogpost, aber dafür ist ein Weblog ja auch da, meine persönliche Meinung widerzuspiegeln. Ich hoffe, ich werde nach der Einleitung etwas nüchterner in der Berichterstattung. In letzter Zeit habe ich sowohl im fernen Bekanntenkreis wie auch vermehrt auf vielen Webseiten gelesen, man möge bitte das Microsoft Update oder Windows Update nicht nutzen oder den automatischen Download lieber deaktivieren usw... Teilweise existieren dort Behauptungen und Annahmen (natürlich immer ohne Beweise), die jeglicher Grundlage entbehren. Weiterhin gefährden diese Webseiten wie auch die häufig durch Mundpropaganda übertragenen (falschen) Behauptungen die Sicherheit der Anwender, die diese Behauptungen glauben. Ich persönlich möchte diesen ganzen unsinnigen Behauptungen und Empfehlungen entgegentreten und hier für ein wenig für Klarheit sorgen! Alle Leserinnen und Leser dieses Blogartikels sind gerne aufgerufen, mir dazu Feedback per Kommentar zu geben. Kontrollieren Sie bitte ihre Einstellungen, oft werden diese durch so genannte Tuning- oder Schutzprogramme auf gefährliche Art und Weise umgestellt. Ich würde mich sehr freuen, wenn alle Webseiten-Betreiber und Blogger, die sich ermutigt fühlen diesen Weg hier mit einzuschlagen, auf meinen Blogartikel über einen eigenen Bericht verlinken würden und dort dann vielleicht auch Ihre Meinung dazu kundtun (egal ob positiv oder negativ). Ich verspreche(!), ich kontrolliere meine Trackbacks und Referrer sorgfältig und nehme die Links dazu hier auch als Weiterführende Verweise auf. Dies würde auch das Meinungsbild festigen oder für einen fairen Ausgleich zu meiner persönlichen Meinung sorgen. In diesem Blogartikel finden Sie Antworten auf die häufigsten Mythen rund um Windows Update, Microsoft Update und Office Update... [... mehr in diesem ausführlichen Blogeintrag auf Giza-Blog.de]

This post is powered by www.Giza-Blog.de | Giza-Blog.de: RSS Feed
Visit:  MSDN Online | Follow MSDN Online on Twitter | Follow Kay Giza on Twitter
Daily News on MSDN:  MSDN Aktuell
© Copyright 2006-2010 Kay Giza. All rights reserved. Legal
Subscribe

WPF Threading ohne Intellisense

02.03.2010 12:05:00 | Jörg Neumann

In meinen WPF-Schulungen kommt es immer wieder zu Verwirrungen bzgl. einiger Methoden, die im Zusammenhang mit Threading zum Einsatz kommen. Daher habe die Problematik hier noch einmal zusammengefasst.

Die Klasse DispatcherObject bietet mit CheckAccess() und VerifyAccess() zwei Methoden, mit denen abgefragt werden kann, ob der Zugriff auf ein Objekt aus dem aktuellen Thread aus möglich ist.

Das Problem ist nur, dass beide Methoden nicht über Intellisense zugreifbar sind! Dies führt dazu, dass viele Entwickler sie nicht kennen. Warum die Methoden nicht angezeigt werden, offenbart ein Blick in den Source Code:

[EditorBrowsable(EditorBrowsableState.Never)]
public bool CheckAccess()
{
  …
}

Hier sorgt das EditorBrowsable-Attribut dafür, dass die entsprechende Methode weder in Intellisense, noch im Object Browser angezeigt werden.

Das gleiche gilt übrigens auch für die gleichnamigen Methoden der Dispatcher-Klasse. Darüber hinaus werden alle Überladungen der Methoden Dispatcher.Invoke() und Dispatcher.BeginInvoke() nicht angezeigt, die einen Parameter vom Typ DispatcherPriority definieren.

Interessant ist an dieser Stelle, das die genannten Methoden den Anschein erwecken, als wären sie nicht vorhanden, jedoch ausführlich (inkl. Beispielen) in der MSDN beschrieben werden.

Verstehen muss man das nicht, oder?

msdn tv @ CeBIT2010 - Tag EINS oder “Was macht die Maus auf der CeBIT?”

02.03.2010 11:04:00 | Jan Schenk



tweetmeme_url = 'http://blogs.msdn.com/jansche/archive/2010/03/02/msdn-tv-cebit2010-tag-eins-oder-was-macht-die-maus-auf-der-cebit.aspx'; tweetmeme_source = 'jansche';

Get Microsoft Silverlight

Tag Eins auf der CeBIT und ich hab mich bei der Maus angesteckt. Das macht aber nix, dann bekommt ihr halt ein Video im guten alten Erklärstil. Die Kanzlerin Angela Merkel hat eine Hauptrolle, Achim Berg auch, und dann darf in der Runde natürlich auch Frank Fischer nicht fehlen. Während Angela und Achim nix sagen, redet Frank über Cloud Computing, aber das seht ihr euch am besten selber an.

Mehr Videos zur CeBIT findet ihr hier im Blog, oder unter:
http://msdn-online.de/cebit/


Viel Spass,
jan

ASP.NET Webforms Anwendungen und Ajax (Teil 5) Scriptservices, Page Methods und jQuery

01.03.2010 23:33:55 | Andre Kraemer

Im vierten Teil dieser Serie habe ich gezeigt, wie Pagemethods und Scriptservices mit dem ASP.NET Ajax Framework angesprochen werden können. Im Vergleich zu den vorherigen Teilen, die auf Client Callbacks bzw. das Updatepanel setzen, konnte über diesen Weg die übertragene Datenmenge erheblich verkleinert werden, da unter anderem der Viewstate nicht mehr übertragen werden musste. Außerdem wurde serverseitig nicht mehr der komplette Page Life Cycle durchlaufen, was weitere Performanceverbesserungen mit sich brachte.

Im Gegenzug zu diesen Verbesserungen mussten wir allerdings in Kauf nehmen, dass beim ersten Request drei zusätzliche JavaScript Dateien des Ajax Frameworks mit einer Gesamtgröße von 85 kb geladen wurden.

Hält man im Hinterkopf, dass der Viewstate einer Seite schnell 50 kb und mehr beträgt und dieser bei jedem Ajax Request der vorherigen Methoden hin und her übertragen wurde, lassen sich diese 85 kb jedoch sicherlich leicht verschmerzen.

Doch wie sieht es aus, wenn neben dem Ajax Framework auch jQuery in die Seite eingebunden wurde, um die Oberfläche zu tunen?

In diesem Fall stellt sich die Situation anders dar, nun ist das ASP.NET Ajax Framework clientseitig nämlich reiner Ballast. Zumindest wenn es darum geht Pagemethods und Scriptservcies aufzurufen. Das kann jQuery nämlich auch.

Also weg damit!

Wie müssen wir aber vorgehen, um Pagemethods und Scriptservices aus jQuery rufen zu können?

Zunächst kopieren wir den kompletten Code unseres letzten Beispiels. Wenn wir nun einen Blick auf den Code werfen sehen wir in der *.aspx Datei einen ScriptManager.

<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="True">
  <Services>
    <asp:ServiceReference Path="~/AjaxDemoService.asmx" />
  </Services>
</asp:ScriptManager>

Dieser war notwendig, damit das ASP.NET Ajax Framework die JavaScript Proxies erstellte, die uns Aufrufe in der Form PageMethods.Methodenname bzw. WebServiceName.Methodenname erlaubten.

Der ScriptManager ist allerdings überflüssig wenn man Pagemethods und Scriptservices via jQuery rufen möchte. Daher fliegt er raus. Weiter entfernen wir den bestehenden inline JavaScript Code der Seite und räumen Sie noch ein wenig auf. Das Ergebnis sieht wie folgt aus:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Teil5.aspx.cs" Inherits="Teil5" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title>ASP.NET Webforms Anwendungen und Ajax (Teil 5): Scriptservices mit jQuery</title>
    </head>
    <body>
        <form id="form1" runat="server">
            <h1>
                ASP.NET Webforms Anwendungen und Ajax (Teil 5): Scriptservices mit jQuery</h1>
            <p>
                <a href="#" id="StaticFileLink">Hier klicken zum Request einer statischen Datei</a><br />
                <a href="#" id="HelloWorldLink">Hier für Hello World WebService klicken </a><br />
                <a href="#" id="EchoLink">Hier für Echo WebService klicken. Geben Sie bitte vorher eine
                    Zahl in nebenstehendem Feld ein: </a>&nbsp;
                <input type="text" id="EchoTextBox" value="4711" />
            </p>
            <div id="content">
                Bitte klicken Sie auf einen der Links, damit dieser Bereich gefüllt wird.
            </div>
        </form>
    </body>
</html>

Der serverseitige Code des vorherigen Beispiels wurde übrigens nicht verändert.

Unsere Seite umfasst nun schlanke 1,6 kb, wie die folgende Abbildung zeigt:

01_Seite

Allerdings kann sie auch noch nichts ;-)

Darum werden wir uns aber in den nächsten Schritten kümmern.

jQuery let's go

Als erstes benötigen wir eine Referenz auf jQuery. Diese erhalten wir über folgenden Script Tag, den wir innerhalb des Head Bereichs der Seite einfügen:

<script src="scripts/jquery-1.3.2.min.js" type="text/javascript"></script> 

Als nächstes fügen wir den Code ein, um den Link zur Anzeige der statischen Datei zum fliegen zu bekommen. Dieser sieht wie folgt aus:

<script type ="text/javascript">
    $(document).ready(function() {
        $("#StaticFileLink").click(function(e) {
            e.preventDefault();
            $.ajax({
                type: "POST",
                url: "Teil5.aspx/ReadStaticFile",
                data: "{}",
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function(result) {
                    $("#content").html(result.d);
                }
            });
        });
	 });
</script>

Relevant für uns sind die Zeilen 5 - 14. Da es jedoch vielleicht den ein oder anderen Leser gibt, der noch nie mit jQuery gearbeitet hat, möchte ich auch zu den anderen Zeilen ein paar Worte verlieren.

Auffällig sind zunächst die vielen $-Zeichen innerhalb des Codes. Dabei handelt es sich um einen Alias für die Funktion jQuery. Überall wo ein $ steht, könnte man sich also auch jQuery denken.

Die Funktion jQuery nimmt ein DOM Element bzw. einen CSS Selektor als Argument entgegen. In Zeile 2 wird das DOM Element document, also eine Referenz auf unser eigentliches HTML Dokument übergeben. Anschließend wird an das Ereignis ready eine anonyme Funktion gehangen. Das Ereignis ready tritt übrigens auf, sobald das DOM vollständig initialisiert wurde, jedoch ehe weitere Inhalte wie Beispielsweise Bilder herunter geladen wurden. Somit hat man innerhalb des ready Ereignisses zwar Zugriff auf das vollständig initialisierte DOM, muss aber nicht den kompletten Seitenaufbau abwarten.

In Zeile 3 wird die jQuery Funktion mit dem CSS Selektor #StaticFileLink gefüllt, um das DOM Element mit der ID StaticFileLink, also unseren Link, zu selektieren. An das Ereignis click des Links wird wieder eine anonyme Funktion gehangen.

In Zeile 4 wird über e.preventDefault(); die Standardaktion des Links verhindert. In unserem Fall also, dass beim Klick auf dem Link dem Inhalt des href Attributs gefolgt wird. Stattdessen wird ab der Zeile 5 definiert, dass ein ajax Aufruf gefeuert werden muss.

Dabei werden folgende Werte an die verschiedenen Parameter der Funktion ajax übergeben:

Parameter Wert Erklärung
type POST (fix) Ajax Anfragen an Pagemethods oder Scriptsservices müssen aus Sicherheitsgründen immer vom Typ POST sein, um JSON hijacking Angriffe abzuwehren. Eine sehr gute Beschreibung hierzu gibt es im Blog von Phil Haack.
url {Seitenname.aspx}/{Methodenname} Ziel des Ajax Aufrufs. Im Falle einer Page Method nach dem Schema {Seitenname.aspx}/{Methodenname}, im Fall von ScriptServices {Servicename.asmx}/{Methodenname}. Wichtig ist, dass die entsprechende Methode im Falle von Pagemethods statisch ist und mit dem Attribut WebMethod dekoriert wurde. Im Falle eines ScriptServices ist auf die Dekorierung des Services mit dem Attribut ScriptService zu achten.
data JSON String Erwartet die Methode Parameter, sind diese hier als JSON String, und nicht als JSON Objekt zu übergeben! Falls die Methode keine Parameter erwartet, sollte stets ein leeres JSON Objekt übergeben werden (also "{}"). Andernfalls übergibt jQuery als contentType statt application/json automatisch text/html.
contentType application/json; charset=utf-8 (fix) Als Content Type ist stets application/json; charset=utf-8 zu übergeben. Dies ist das Zeichen für das ASP.NET Ajax Framework, serverseitig die Anfrage an den ScriptService Handler und nicht an den Soap Webservice Handler weiterzuleiten.
dataType json (fix). Gibt den Datentyp der Antwort an. Gültige Antworten sind unter anderem json, script, xml oder text. Im Fall von Pagemethods und ScriptServices kommt immer JSON zurück.
succes Anonyme Funktion bzw. Funktionsname Eine Anonyme Funktion bzw. der Name einer Funktion, die die Rückgabe der Methode verarbeitet.
Im Falle von PageMethods und ScriptServices wird die Antwort aus Sicherheitsgründen übrigens immer in ein Objekt Namens d verpackt (siehe auch Zeile 12 des Scripts). Die Ursache hierfür ist ähnlich wie beim Parameter type und wird auch näher in Phil Haacks Blog Eintrag erklärt.

Der Aufruf des Services sollte somit ausreichend erklärt sein. Einzig Zeile 12 bedarf noch einer kleinen Erklärung:

Via $("#Content") holt jQuery sich eine Referenz auf den Zielbereich in mithilfe der Funktion html die Antwort des Ajax Requests geschrieben wird.

Der Code zum Aufruf der beiden Webservice Methoden sieht erwartungsgemäß ähnlich aus:

            $("#HelloWorldLink").click(function(e) {
                e.preventDefault();
                $.ajax({
                    type: "POST",
                    url: "AjaxDemoService.asmx/HelloWorld",
                    data: "{}",
                    contentType: "application/json; charset=utf-8",
                    dataType: "json",
                    success: function(msg) {
                        $("#content").html(msg.d);
                    }
                });
            });

            $("#EchoLink").click(function(e) {
                e.preventDefault();
                var number = $("#EchoTextBox").val();
                var jsonData = "{ 'number' : '" + number + "'}";
                $.ajax({
                    type: "POST",
                    url: "AjaxDemoService.asmx/Echo",
                    data: jsonData,
                    contentType: "application/json; charset=utf-8",
                    dataType: "json",
                    success: function(msg) {
                        $("#content").html(msg.d);
                    }
                });
            });

Erklärenswert ist einzig Zeile 18. Hier wird ein Json String zusammen gesetzt, der später an die entsprechende Methode des Webservices übergeben wird. Dies geht im Falle eines Arguments noch ganz gut, wird aber spätestens bei zwei oder mehr Argumenten sehr lästig. Abhilfe schafft hier die Methode stringify des Objekts JSON. Die Methode überführt ein Json Objekt in einen entsprechenden String. Moderne Browser bringen dieses Objekt inkl. passender Methode gleich mit. In allen anderen Fällen hilft der JSON Parser / Stringifier Json2.

Das Ergebnis der Mühe sieht im Live-Betrieb dann übrigens wie folgt aus:

02_AjaxRequest

Zum Download der jQuery Library ist, wie auf der Abbildung gezeigt, ein weiterer Request notwendig, der knapp 58 kb umfasst. Dies sind fast 30 kb weniger als es im vorherigen Beispiel auf Basis des ASP.NET AJAX (client) Frameworks der Fall waren.

Fazit

Ajax Aufrufe werden mithilfe des jQuery Frameworks zum Kinderspiel. Gerade wenn man jQuery bereits für Oberflächenmanipulationen in einer Seite nutzt, lohnt sich die Anwendung von jQuery für Ajax Aufrufe anstatt der Nutzung des ASP.NET Ajax (Client) Frameworks.



blog.codemurai.de © André Krämer |Impressum | Abonieren

msdn tv @CeBIT2010 - Tag NULL oder “Was passiert eigentlich vor der CeBIT?”

01.03.2010 22:21:00 | Jan Schenk



tweetmeme_url = 'http://blogs.msdn.com/jansche/archive/2010/03/03/msdn-tv-cebit2010-tag-null-oder-was-passiert-eigentlich-vor-der-cebit.aspx'; tweetmeme_source = 'jansche';

Get Microsoft Silverlight


Nach der CeBIT ist vor der CeBIT heisst es so schön. Und nachdem ich auch schon das zweite Jahr für Microsoft an der CeBIT teil nehme, kann ich diesen Satz bestätigen. Und ich darf dieses Jahr auf der CeBIT sogar bewegte Bilder für euch machen. Die Gelegenheit habe ich beim Schopfe gepackt, und heute gleich mal ein Mini-Wrap-Up von dem gemacht, was vor der offiziellen Pfortenöffnung am 2. März auf dem Microsoft-Stand passiert. Und natürlich kennt man mich dort inzwischen. "Puschel" ist vielen hingegen noch nicht so vertraut. Tja, daran wird sich das Microsoft Standpersonal die nächsten 5 Tage gewöhnen müssen. msdn tv berichtet gnadenlos von den wichtigsten Themen für Entwickler von der CeBIT. In Farbe. Und Bunt.
Hier also Tag NULL als Appetizer auf die nächsten Videos, die msdn tv @ CeBIT für euch produziert. Ein bisschen trashiger als sonst, da ich alleine bin und neben Film auch noch Vorträge halte.
Euer Developer Evangelist mit dem Hut!

msdn tv - Nachrichten für Entwickler (Ausgabe 03/2010)

01.03.2010 13:45:47 | Jan Schenk

Get Microsoft Silverlight


Mit dem Engagement der Microsoft Community beschäftigt sich Moderator Jan Schenk in der aktuellen Folge von „msdn tv“. Zu Gast hat er mit Dorothea Henke und Katrin Letzel dabei zwei Microsoft-Verantwortliche, die sich im Rahmen des MVP-Programms und der Initiative CLIP um die Betreuung und Unterstützung von On- und Offline-Communities sowie von unabhängigen Experten kümmern.
In den Kurznachrichten vorab: Aktuelles zum Release Candidate von Visual Studio 2010, zum Community-Event „Born2Share ShareCamp“ sowie zwei aktuellen Dokumenten, die die wichtigsten Features des neuen SharePoint Server 2010 und von SharePoint Foundation 2010 vorstellen. Außerdem gibt’s Infos rund um neue Tutorials und Dokumentationen zum Internet Explorer 8 bei MSDN Online und zum Release Candidate von Windows Embedded Standard 7, der auf Microsoft Connect heruntergeladen werden kann [18:33]
Hinweis der Redaktion: Das in mehreren Einstellungen abgebildete lila Fläz-Möbel sowie die z.T. demonstrativ entspannte Haltung unseres Moderators sind kein Hinweis auf spätrömische Dekadenz und nicht als Diskussionsbeitrag zur aktuellen Sozialstaatsdebatte zu verstehen.

Auf der VSone Konferenz - Mi 24.02. & Do 25.02.2010

01.03.2010 13:23:26 | Jan Schenk



tweetmeme_url = 'http://blogs.msdn.com/jansche/archive/2010/03/01/auf-der-vsone-konferenz-mi-24-02-do-25-02-2010.aspx'; tweetmeme_source = 'jansche';

Eine schöne Konferenz durfte ich letzte Woche nicht nur besuchen sondern sogar betreuen. Als Contentboard-Mitglied für den ASP-Konferenz-Track habe ich das erste mal eine Konferenz - natürlich ehrenamtlich - mitgestaltet. Dementsprechend darf natürlich auch der Wrap-Up im Nachgang nicht fehlen.

Und natürlich gibt es Bilder. Ich selbst habe im unglaublichen, schier riesigen IMAX-Kino meinen Windows Azure-Vortrag halten dürfen und bin immer noch ganz baff von der Wirkung des Raumes. Leider war das aber wohl das letzte Mal, dass die VSone im Forum der Technik am Deutschen Museum in München stat gefunden hat, denn das Forum der Technik ist dem abrisstechnischen Untergang geweiht. Nächstes Jahr muss sich die Konferenz eine neue Heimat suchen. Ich bin gespannt, was und wo das sein wird, und ob es dort auch eine so grossartige Möglichkeit für einen Vortrag gibt, wie das IMAX-Kino.

Genug geredet, hier sind die Bilder von Scott Hanselman (während seiner Keynote und auf einem Segway),

_MG_0748_MG_0703

von Tom Wendel, auch im IMAX-Kino,

_MG_0781

von Ralf Westphal, der statt der Leinwand auch gerne mal auf das Flipchart zurück greift,

_MG_0771

von Chris Binder, auch im IMAX-Kino

_MG_0739

Und natürlich fanden noch 9 weitere Tracks in - zugegebener Maßen kleineren - Sälen statt. Mein persönliches Highlight (neben meinem eigenen Vortrag natürlich), war Scott Hanselmans Keynote und ein msdn tv Interview mit ihm, Chris Binders Keynote und ein sehr lustiges Interview mit Albert Weinert, der es fast nicht schafft, die .NET Cologne Konferenz anzukündigen.

Auf diese Videointerviews könnt ihr euch freuen, denn wir planen sie gerade für die nächste Ausgabe von msdn tv ein.

Viele Grüße aus dem Zug unterwegs zur CeBIT 2010!
jan

Abstraktion

01.03.2010 09:37:00 | Peter Bucher

Am 13. Oktober 2008 haben Golo Roden und ich unter dem Titel Noch Fragen, Roden? Ja, Bucher! angekündigt, jeweils zum ersten eines jeden Monats einen Kommentar zu einem vorab gemeinsam gewählten Thema verfassen zu wollen.

Bisher sind in dieser Reihe folgende Kommentare erschienen:

Heute, am 1. März 2010, ist es nun wieder so weit, und unser Thema für diesen Monat lautet:

Abstraktion

So wohl Golo wie auch ich haben uns unabhängig voneinander im Vorfeld unsere Gedanken gemacht, wie wir diesem Thema gegenüberstehen. Außerdem nimmt diesen Monat auch Roberto Bez an unserem Streitgespräch teil.

Golos und Robertos Kommentare finden sich zeitgleich in den entsprechenden Blogs, folgend nun mein Kommentar zu diesem Thema:

Der Begriff “Abstraktion” wird in vielen möglichen Bereichen genutzt, sei dies Kunst, Psychologie, Philosophie, Mathematik oder sogar in der Sprachwissenschaft.

Abstraktion hat in jedem Bereich die gleiche Bedeutung, jedoch in einem jeweils anderen Kontext.

 

Ein Beispiel aus der Psychologie:

In einem Leben wird der Mensch mit sehr viel Wissen, Tatsachen und Situationen auseinandergesetzt.
Wenn der Mensch alles im Kopf behält und das auch im Leben nutzt, wäre das Leben um einiges komplizierter.

Bspw. am Mittagstisch, entweder “Gib mir bitte die Butter” vs. “Gib mir bitte die Laco Butter mit 5% Fettanteil, die Gestern Aktion war.”

Bei zweiterem müsste der Gegenüber wohl zuerst mal überlegen, was überhaupt gefordert ist oder ob es evt. sogar ein Scherz ist.
Danach schauen ob all die Eigenschaften übereinstimmen und dann schlussendlich die Butter bringen oder eine Antwort geben.

Ihr könnt es schon denken: Das Leben wäre viel zu kompliziert.
Mit ersterem Satz weiss jedes Kind was gemeint ist und die Komplexität nimmt rapide ab.

Man kann schlussendlich immer noch sagen: “Bitte gib mir die light Butter” / “Bitte gib mir die normale Butter”, wenn eine solche Unterscheidung notwendig ist, wenn zwei Butter vorhanden sind.

Das Beispiel zu Kunst auf Wikipedia ist auch sehr interessant: http://de.wikipedia.org/wiki/Abstraktion#Kunst

Es geht also um die Generalisierung, um das weglassen von Details, wobei genau dasselbe erreicht werden kann.

 

In der Software-Entwicklung gibt es zum einen die Objektorientierte Programmierung und zum anderen Sprachkonstrukte für Generalisierung.
Auch wenn es wohl einige nicht daran denken, weil sie zufest in abstrakte Klassen und Interfaces eingefahren sind: Auch konkrete Klassen sind Abstraktionen.

Sie verbergen Details (Datenkapselung), die ja eigentlich dazugehören, aber den Client nicht interessiert, sowie einen Schutz darstellt, wenn das Klasse später noch geändert werden muss, ohne das der Clientcode bricht.

Auch bei konkreten Klassen gibt es die Generalisierung und Spezialisierung. “String” ist eine Spezialisierung vom Typ “object” und “Person” eine Generalisierung von “PoliceOfficer”.

Zusätzlich zu den Möglichkeiten der Objektorientierung gibt es in C# zwei Sprachkonstrukte, um die Nutzung von Abstraktion noch effektiver zu nutzen.

Abstrakte Klassen und Interfaces, mehr dazu könnt ihr in einem frühreren Streitgespräch lesen:

BASTA! Spring 2010: Das wars …

01.03.2010 02:32:05 | Jürgen Gutsch

Ich habe es tatsächlich geschafft und über jede besuchte Session einen Beitrag geschrieben und ich habe es geschafft, innerhalb einer Woche Robertos Beiträge von der Startseite zu verbannen :-P Fazit: Ich werd es da nächste mal definitiv nicht mehr so machen, da es zeitweise ganz schön in Stress ausarten kann. ;-)

Meine “spammerei” ist somit also rum und ich hole hiermit Robertos absolut lesenswerte Beiträge wieder nach oben:

DI / IoC Container LightCore Teil 1: Einführung
DI / IoC Container LightCore Teil 2: Registrierung über Xml Modul
DI / IoC Container LightCore Teil 3: Registrierung von Generics

Insgesamt waren es 5 Spannende und interessante Tage. Bis auf ein zwei Sessions haben sich alle Sessions gelohnt. Sehr schade war allerdings die halbe Stunde am Donnerstag Abend, die sich Abschlussveranstaltung nannte, in der die vielen Preise verlost wurden und sonst nichts mehr statt fand. Nach dieser “Abschlussverasntaltung” schien die BASTA! von einer Sekunde auf die andere vorbei, es gab keine Party, die meisten Leute waren auf einmal weg. Lediglich Gregor, Robert, Roberto, Peter und ich blieben noch eine Weile beim Bierchen sitzen, bzw. Roberto und ich quatschten noch bis um ca. 22 Uhr, bevor auch ich mich auf den Weg machte.

DotNetKicks-DE Image

Regeln | Impressum