Step-by-step Silverlight Virtual Earth Control tutorial DRAFT (in Hungarian)

Bevezetés

(A távolabbi cél, a közvetít? alkalmazás létrehozása, hogyan épül az eddigiekre)

Miért Silverlight (.NET, grafikus, jól támogatott eszközökkel, cross platform, cross browser, kliensként is tud futni, média file-ok támogatása stb.)

Hozzuk létre a projecteket, és tegyünk meg néhány kezdeti lépést, aztán szeretnék beszélni a munkamódszerünkr?l

Kezdeti beállítások

  • Silverlight Application project solution-höz adása
  • A Web projecthez linkelés létrehozása
  • Legyen a Web project a Startup poject

Iterációkban fogunk haladni, m?köd? funkcionalitás a cél mindig.

Általában az elképzelés után, egy kezdeti nem m?köd? prototípust tervezünk, ebb?l is több verziót

Ezt követ?en kamu adatokkal elkészítem a felület m?köd?képes verzióját az Expression Studio használatával

És csak ezután akasztom él? adatokra a programot

Az id? rövidsége miatt most más megközelítést alkalmazunk

A rendelkezésre álló adatokhoz fogunk egy egyre gazdagabb megjelenítést létrehozni

Meglátjuk meddig jutunk..

 

A vitorlásunk követése

 
A vitorlás adatainak elérése
MAINPAGE.CS
  • egy field-et létrehozunk az egyedi id-nk tárolására, 
    • ez azonosít minket a redszerben, 
    • ez köt össze a hajónkkal
    • KÓD:

const int UserId = xxx;

  • Az adatforrásunk a Dáviddal írt webservice lesz, ezért hozzáadjuk a projecthez:
    • Add Service Reference a projectünkön
    • Discover
    • namespace: SailingCompetitionService
    • OK

using MapApplication.SailingCompetitionService

  • Kliens objektumot hozunk létre, amin keresztül a webmetódusokat hívni fogjuk majd:
    • KÓD:
SailingCompetitionService.ServiceClient SailingDataClient
    = new SailingCompetitionService.ServiceClient();

  • Meghívjuk a hajónk adatait visszaadó webservice-t:
    • Ez egy aszinkron hívás, ezért az értékek visszatérését egy event jelzi, rakjunk rá egy handler függvényt
    • KÓD:

SailingDataClient.GetUnitTrackCompleted

+= new EventHandler<GetUnitTrackCompletedEventArgs>

(SailingDataClient_GetUnitTrackCompleted);

    • Miután van ahol majd kiolvassuk a visszatér? értékeket, hívjuk is meg a függvényt
    • A függvény paraméterének adjuk meg az eltárolt id-nket:
    • KÓD:
SailingDataClient.GetUnitTrackAsync(UserId);

    • Ellen?rizzük le, hogy alóban érkeznek-e adatok
    • Tegyünk a handler záró kapcsos zárójelére egy breakpoint-ot
    • F5
    • Az e.Results-ban láthatóak a visszatért értékek
 
Kliens oldali modell létrehozása

 

Ahhoz, hogy a beérkez? adatokat megjelenítsük tárolnunk kell ?ket a kliens oldalon

Ehhez modell osztályokat hozunk létre

  • SailBoat class létrehozása:

    Add New Item a Silverlight projecten

    Class

    a neve legyen SailBoat.cs

SAILBOAT.CS

  1. A vitorlás tulajdonságainak létrehozása:

EL?SZÖR CSAK A TÉRKÉPEN AKARJUK ELHELYEZNI AZ AKTUÁLIS POZÍCIÓJÁRA, ehhez összesen egy koordináta párra, és az id-jére van szükség

Szükségünk lesz hosszúságra, szélességre és egy azonosítóra

Ne a gyors módszerrel hozzátok létre a property-ket, mert kés?bb még vissza fogunk rájuk térni

    • KÓD:

        double_Latitude;

        public doubleLatitude

        {

            get{ return_Latitude; }

            set

          
{

                _Latitude = value
            }

        }

        double_Longitude;

        public doubleLongitude

        {

            get{ return_Longitude; }

            set

          
{

                _Longitude = value;

            }

        }

        int_Id;

        public intId

        {

            get{ return_Id; }

            set

          
{

                _Id = value;

            }

        }

    • Az osztály konstruktorának legyen az id a paramétere
    • KÓD:
    public SailBoat(int id)
        {
            Id = id;
        }

    • A pozíció adatok feltöltéséhez egy függvényt is definiálunk, ez a kés?bbiekben majd jól fog szolgálni:

    • KÓD

   public void SetPosition(double latitude, double longitude)
        {
            Latitude = latitude;
            Longitude = longitude;
        }

A modell feltöltése adatokkal

 

MAINPAGE.CS

  • Hozzunk létre egy SailBoat objektumot, amibe a hajónk adatait fogjuk tárolni:
  • KÓD
    SailBoat MySailBoat { get; set; }

  • a konstruktorban példányosítsuk meg az id-nkel paraméterként
  • KÓD
    MySailBoat = new SailBoat(UserId);
  • A webszerviz hivásunk visszatérési értékei közül a LEGFRISEBBET (ez a 0-ik) a completed event handlerében töltsük az új objektumunkba:
    void SailingDataClient_GetUnitTrackCompleted    (object sender, GetUnitTrackCompletedEventArgs e)
        {
            MySailBoat.SetPosition(e.Result[0].Latitude,                Result[0].Longitude);
        }
  • Az el?bbiekben kirakott breakpoint az event handler záró kapcsára, most is jó helyen lesz
  • F5
  • Nézzük meg, ahogy feltelt az objektum adatokkal
 
Az adatok frissítése

 

Mivel a cél az él? követés, id?r?l id?re újra le kell kérdeznünk az adatokat.

Erre és a kliens oldali modell adatokkal szinkronban tartására vannak már kifinomultabb módszerek, mint például a .NET RIA Services,

de ha a webszervíz réteg nem a mi kezünkben van, mint az interneten sok esetben, vagy csak egyszer?bb webservice réteg áll rendelkezésünkre, akkor pollozásra kényszerülünk,

azaz adott id?közönként rá-rákérdezünk az adatokra

  • Ehhez mindenekel?tt szükségünk van egy órára, aminek az ütéseire elmegyünk újra az adatokért

A Silverlight-ban bár többféle óra típus is rendelkezésünkre áll, de a legpontosabb és teljesítmény szempontból a legkedvez?bb választás egy StoryBoard használata

  • Hozzunk létre egyet:
  • KÓD
   Storyboard TimerStoryboard = new Storyboard();
  • Állítsunk be neki egy id?tartamot
  • Rakjunk rá egy handler-t ami az ütéseket jelzi
  • majd indítsuk el:
  • KÓD
TimerStoryboard.Completed    += new EventHandler(TimerStoryboard_Completed);
TimerStoryboard.Duration = new Duration(new TimeSpan(0,0,5));
TimerStoryboard.Begin();
  • Hívjuk meg a webserviceünket a Completed handerben, hogy minden óraütésre friss adatokért menjen
  • Húzzuk fel újra az órát a StoryBoard újraindításával:
  • KÓD
    void TimerStoryboard_Completed(object sender, EventArgs e)
        {
            SailingDataClient.GetUnitTrackAsync(UserId);

            TimerStoryboard.Begin();
        }

  • F5
  • Breakpoint marad ahol volt
  • Látható, ahogy minden óraütésre friss adatok érkeznek
 
Az érkez? adatok megjelenítése

 

A BreakPoint-nál lehet emberbarátabb megjelenítése is az adatoknak.

Korábban ezt szövegmez?k kihajigálásával tettem, de a Silverlight 3-al egy szuper új vezérl? családot kaptunk, amik jelent?sen megkönnyítik az üzleti alkalmazások fejlesztését.

Köztülük most az automatikus form generálót fogjuk használni.

Rádobva a modell objektumunkat ? automatikusan legenerálja a tartalmához ill? megjelenítést.

Ezzel együtt azt is látni fogjuk, hogy hogyan lehet grafikus elemeket kihelyezni és mainpuláni pusztán kódból.

  • A Silverlight project-hez adjunk egy új Referenciát: System.Windows.Controls.Data.DataForm

using System.Windows.Controls

  • A konstruktorunkban hozzunk létre egy DataForm objektumot
  • CurrentItem ként adjuk meg a hajónk modelljét
  • és adjuk a DataFormot a LayoutRoot-hoz
  • a LayoutRoot, egy nekünk automatikusan létrehozott elem, erre kerül ki minden felhaszálói felület egység
  • KÓD
   LayoutRoot.Children.Add(
                new System.Windows.Controls.DataForm()
                {
                    CurrentItem=MySailBoat
                });
  • F5
  • Látható ahogy csak az els? értékadásra változnak az értékek. Mit?l van ez?
  • A control nem kap értesítést a property-k megváltozásáról
  • Erre való a INotifyPropertyChanged interface, amit a modell osztályunkban kell megvalósítanunk

SAILBOAT.CS

  • KÓD

using System.ComponentModel

public class SailBoat: System.ComponentModel.INotifyPropertyChanged

  • jobb klikk: implement interface
  • lent látható létrehozta a PropertyChanged eventet egy régióba
  • Minden property írásakor süssk el az eventet, event argumentumként a property nevét adjuk meg
  • Ne felejtsük el a null vizsgálatot
  • KÓD
        double _Latitude;
        public double Latitude
        {
            get { return _Latitude; }
            set
            {
                _Latitude = value;
                if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Latitude"));
            }
        }
        double _Longitude;
        public double Longitude
        {
            get { return _Longitude; }
            set
            {
                _Longitude = value;
                if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Longitude"));
            }

        }

        int _Id;
        public int Id
        {
            get { return _Id; }
            set
            {
                _Id = value;
                if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Id"));
            }
        }
  • F5
  • Mostmár változnak az értkékek, az event hatására a control tudomást szerez róla, ha frissítenie kell magát
  • Tovább nem lesz szükségünk a DataForm-ra, töröljük ki:
  • KÓD
//LayoutRoot.Children.Add(
//    new System.Windows.Controls.DataForm()
//    {
//        CurrentItem=MySailBoat
//    });

 
A hajónk megjelenítése térképen

 

  • Ehhez szükségünk lesz a Vistual Earth Silverlight control-ra, amit a Stuff könyvtárban találtok
  • Ezt referencként adjátok hozzá a Silverlight project-hez

És végre áttérünk XAML-re!

Ez az ok, amiért Silverlight-tal kezdtem foglalkozni.

Egy nyitott, xml alapú grafikus leíró nyelv.

A nyitottsága garancia a jó eszközámogatásra, de arra is, hogy forrás szinten belenyúlhassak a grafikáimba.

Emellett hatékonyantámogatja a megjelenítés és viselkedés elkülönítését az alkalmazás logikától.

Aztán mint id?vel számomra is leesett ennél sokkal több, sorosított kód gyakorlatilag. A .NET következ? verzióhánál ez már sokkal nyilvánvalóbb lesz.

Mindenesetre XAML debuggolásánál nem árt ezt fejeben tartani.

Vágjunk bele…

MAINPAGE.XAML

  • ami a using a C# kódnak, az az xml namespace a XAML-nek
  • hozzunk is létre egyet a Virtual Earth control eléréséhez a többi xmlns közé:
  • KÓD
   xmlns:map="clr-namespace:Microsoft.VirtualEarth.MapControl;   assembly=Microsoft.VirtualEarth.MapControl"

  • A LayoutRoot-ba hozzuk létre a térképet
  • A neve legyen BalatonMap
  • és állítsuk be neki a Balatont kezd? pontként, hiszen itt folyik a verseny
  • A kezd?pont beállítása a View struktúra megadásával történik:

    (Szélesség, Hosszúság, Magasság Nagyítás Elforgatás)

    Egy speciális sorosított formátumként adtuk meg a View-t, amit aztán a XAML Parser fog struktúrává alakítani

  • KÓD
   <map:Map x:Name="BalatonMap"
                 View="46.826375,17.698975,0.0 9.0 0.0">
   </map:Map>
  • F5
  • Látható a térkép a Balatonnal a középpontban
    • Ha hibaüzenetet kap valaki, próbálja meg másik böngész?ben meghívni az oldalt az internet explorer cím sávjából át másolva a másik böngész?be az oldal url-jét.
  • Szereténk, ha a tékép legközelebb a teljes böngész?abalakot kitöltené, ezért kitöröljük a UserControl méret határait:
  • Ügyeljünk, hogy a záró kacsacs?rt ne töröljük ki!
  • KÓD
<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:map="clr-namespace:Microsoft.VirtualEarth.MapControl;    assembly=Microsoft.VirtualEarth.MapControl"
    x:Class="MapApplication.MainPage"
    Width="400" Height="300">
  • A térkép controlban MapLayer-ekre lehet objektumokat pakolni, ezért hozzunk létre egy InfoOverlay nev? layer-t
  • És belé pedig egy TextBlock elemet
  • A Text tulajdonsága legyen “My ship”
  • a színét a Foreground tulajdnosgáon keresztül tudjuk megadni, én pirosat fogok, Red beírásával
  • KÓD
   <TextBlock x:Name="TestBoat"
                           Text="MyShip"
                           Foreground="Red"
                           />
  • Ahhoz, hogy a térkép pozicionálja is a rárakott objektumunkat, koordinátákat kell hozzárendelnünk, ezt a következ?képpen tehetjük meg:

A Silverlight-ban lehet?ség van egy objektumra ráragasztani egy olyan tulajdonságot, ami egy másik objektum birtokol és ellen?riz.

Ezt a koncepciót hívják AttachedProperty-nek.

úEz Úgy m?ködik, mint például a mozijegy.

Az ember alapvet?en nem mozijeggyel születik, nem része a saját tulajdonságainak, és lehet soha be sem fogja tenni a lábát egy moziterembe, tehát teljesen felesleges is lenne már születésekor kezébe nyomni egyet.

Viszont, ha úgy dönt, hogy mégis elmegy egybe, akkor vesz egy jegyet, ami onnantól hozzá kapcsolódva jelzi, hogy melyik el?adásra mehet el.

A jegyeket, bárkihez is legyen csatolva pedig a mozi ellen?rzi.

Itt a MapLayer osztogat MapPosition nev? tulajdonságokat, amir?l akik megkapják nem is kell tudjanak, de ha véletlenül rákerülének a MapLayer-re, akkor automatikusan a MapPosition által meghatározott földrajzi koordináta felett fognak megjelenni.

  • El?ször rakjuk mi is a TextBlock-unkat a térkép kezd?pontjára.
  • A hajónk valódi pozíciójával való összekötés még további munkát igényel majd, mert két double ként tároljuk és nem egy, a MapPosition-nek megfelel? Location típusú objektumként.
  • KÓD
   <TextBlock Text="MyShip"
              Foreground="Red"
              map:MapLayer.MapPosition="46.826375,17.6989750"
              />
  • F5 (vagy build és refresh, ha pl firefox)
  • A TextBlock megjelenik a térkép közepén, és együtt mozog a térképpel
  • Hogyan tudnánk megoldani, hogy a TextBlock a hajónak megfelel? pozícióra kerüljön minden frisítéskor?

Erre való az érték kötés a Silverlight-ban, azaz a binding

A binding lehet?vé teszi, hogy két értéket összekössünk.  Így a logikai modell egy property-jének értékét összeköthetjük az ?t ábrázoló vezérl? egy tulajdonságával.

Több féle binding-ot támogat a Silverlight, mi itt most az egyirányú kötést, a logikai modell fel?l a control felé hatót fogjuk használni.

  • Bindingcsak kompatibilis típusú tulajdonságok között hozható létre. Ebben segítségünkre lehet a konverter objektumok használata, de most egy egyszer?bb utat választunk

SAILBOAT.CS

  • A logikai hajó modellünknek ezért létrehozunk egy Location típusú property-t, Position néven.
  • Ez a property is eventet dob ha változik az értéke
  • KÓD

using Microsoft.VirtualEarth.MapControl;

   Location _Position;
        public Location Position
        {
            get { return _Position; }
            set
            {
                _Position = value;
                if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Position"));
            }
        }
  • a SetPosition függvény ezt a property-t is tölse föl mostantól
  • KÓD
   public void SetPosition(double latitude, double longitude)
        {
            Latitude = latitude;
            Longitude = longitude;

            Position =
                new Microsoft.VirtualEarth.MapControl.Location()
                {
                    Latitude = latitude,
                    Longitude = longitude
                };
        }

MAINPAGE.CS

  • Kötés létrejöttéhez explicit párosítanunk kell az objektumokat futási id?ben
  • Ez az objektumok DataContext-jének beállításával történik
  • A DataContext objetum az amiben a számára kötésként kijelölt property-ket keresi egy vezérl?. Ha nem talál saját DataContext-et a szül? DataContext-jét próbálja használni, és így tovább felfelé.
  • Mi a hajó logikai modelljét adjuk meg DataContext-ként az egész térképre. Így annak minden gyermeke, tehát a mi TextBlock-unk is is a MySailBoat objektumot fogja adatforrásként használni:
  • A konstruktorba írjuk a következ?t:
  • KÓD

BalatonMap.DataContext = MySailBoat;

MAINPAGE.XAML

  • Most pedig a TextBlock MapPosition tulajdonságát kössük össze a MySailBoat-unk Position property-jével:
  • Figyeljünk oda a kapcsoszárójelekre:
  • KÓD
<TextBlock x:Name="TestBoat"
           Text="{Binding Path=Id}"
           Foreground="Red"
           map:MapLayer.MapPosition="{Binding Path=Position}"
                           />
  • F5
  • A térképen látható, ahogy a TextBlockunk 5 másodperces frissüléssel a megfelel? pozíció felett lebeg.

A Silverlight egy nagy el?nye, hogy megkönnyíti az együttm?ködést az alkalmazáson dolgozó szakemberek között.

Amíg mi a térképen dolgoztunk, a Designer kollégánk már el is készülhetett egy hajó grafikával, amit egy controlként máris használatba vehetünk, és a kés?bbiekben akár dinamikus viselkedést is adhatunk neki.

  • A Stuffból referencáljuk be MapControls dll-t a Silverlight projectbe
  • Hozzuk be a namespace-ét a xaml-be:
xmlns:MapControls="clr-namespace:MapControls;assembly=MapControls" 

  • A TextBlockunkat cseréljük le a kapott control-ra:
  • És állítsuk be rajta is a megfelel? kötéseket:
  • A MapPositionMethod beállításával azt jelöljük ki, hogy a control melyik pontja felejen meg a MapPosition-ben megadott koordinátának:
  • KÓD
<!–<TextBlock
              Text="{Binding Path=id}"
              Foreground="Red"
              map:MapLayer.MapPosition="{Binding Path=Position}"
              />–>

<MapControls:SailingBoatControl
              BoatId="{Binding Path=Id}"
              map:MapLayer.MapPositionMethod="BottomCenter"
              map:MapLayer.MapPosition                               ="{Binding Path=Position}"/>

  • F5
  • A hajó vidáman körözget a tavon.

Happy 2009 Animation

I did this originally for my company, but I put all my heart in it. So let me greet you and wish you a happy new year with the following animation:

http://www.szili.net/Happy2009

Our application at Microsoft VORTEX 2008

I had the chance to demo our Silverlight application at Microsoft’s virtual CEE Remix event (thanks Dénes!).

It’s a web application for companies with many employees on the move.

Using the system you can track details like position, speed, driving behavior of moving units real-time or with reports. You also have a personal security function, with real-time alerting and messaging.

This solution called DIWICON-M is tracking more than 20 000 units worldwide. If you are interested have a look at it on my company’s website.

You can also download the demo video from here!

 

Live demo: http://dwminterface.diwicon.com

 

P.S. I also speak CEE English because of the event.. ; D

Journey to the West

Album artwork

I read about the new Gorillaz album this morning. Being a Jamie Hewlett fan and watching the YouTube clips it had me hooked in a whim.

On the official site it turned out that it’s a much richer act than just an album as it comes with an opera and a short film also. 

So if you love animation, progressive music, Chinese culture and well.. opera, see you in London at the evening show on the 22nd of November!
(And you can get the album for 8 EUR without DRM.)

London restaurant tips are welcome!

Remembering Füles

Saying goodbye

I was upgrading my posted Silverlight projects when I ran into my oldest one.

One and a half year ago Füles was with us in the living room, wagging his tail just like in the animation I was showing to my family.
It was a great thing as he had just recovered from a serious stroke endured last summer. 

Since then he passed away but the time we had with him was a true gift.

You can watch the animation titled ‘Sunrise’ here.

Laputa Photosynth

Today I toyed around a bit with Photosynth and my Laputa robot form my Japan trip this summer.
Check out the results:

image 
Photosynth using the given set of photos (right) automatically creates a panorama-like 3D environment.
Moving around you can discover the details of the place pictured by the uploaded images (middle).
The coolest feature is unfortunately hidden: pressing the control button Photosynth shows the recognized 3D structure of the place (left). It works unbelievably well.

Imagine this on a mobile device with a GPS, internet connection and real-time.
It could be an interesting medium.

Google Chrome and Silverlight

It seems like it’s kinda working. Input lags seriously (I mean it clicks minutes after I clicked) but it looks ok otherwise.

My character recognition Silverlight app running in Google Chrome:

googlechromesilverlight

A Hungarian DeepZoom experience

It’s a joy to see such a polished Hungarian Silverlight solution as the recently launched site of our 14th century chronicle by Eyedea.

It puts a really good use of Silverlight’s DeepZoom technology by synchronizing audio and text commentary with the pages creating an engaging and authentic experience.
It’s only in Hungarian yet, but I hope there will be an English version.

Find out more about the chronicle on Wikipedia:

The Illuminated Chronicle (in Hungarian: Képes Krónika) is a medieval illustrated chronicle from the Kingdom of Hungary from the fourteenth century. It represents the international artistic style of the royal courts in the court of Louis the Great.

SilverBites 1: Adding metadata to Xaml in design-time

This little lolcat will show you a cool feature I discovered recently.

Using its ‘Tag’ property you can add metadata to a FrameworkElement (so practically every graphical element Silverlight provides) and read it out in code as a string.

Even better, you can set Tag property in design-time with Expression Blend support!

This is a start of my new project, SilverBites. It’s a series of bite sized video tutorials on Silverlight 2 with a maximum length of 90 seconds.
I’m pretty microphone shy yet, but watch my alterego in the coming parts!

Data Binding in Silverlight and XamlParseException

Playing with data binding I had the System.Windows.Markup.XamlParseException whenever I ran my app.

It turns out the problem was putting a binding statement into a <Run … /> element.
Silverlight supports data binding only on FrameworkElements and the Run class contrary to the Textblock is not a descendant.