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 projectenClass
a neve legyen SailBoat.cs
SAILBOAT.CS
- 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.




