Deep Zoom albumid koos pildiinfoga

Sain mõni päev tagasi kirja ühelt inimeselt, kes oli näinud minu MIX esitlust ning saanud sellest innustust teha mõned Deep Zoom albumid ja nüüd soovis viia albumid järgmisele tasemele lisades piltide juurde ka selgitavat teksti. Ja tõsi ta on, siia ajaveebi jõuavad ka tellitud teemad… nii, et tellige aga… kui mul vähegi aega ja huvi on, siis genereerin postituse :)

Projekti ettevalmistamine

Kõigepealt loome Deep Zoom albumi kasutades rakendust Deep Zoom Composer ning paneme piltidele külge kirjeldused ehk tagid. Seda saab teha Compose sammul valides sammu ning sisestades kirjelduse tag kastikesse.

tagimine thumb Deep Zoom albumid koos pildiinfoga

Järgnevalt tuleb see album eksportida Silverlight projektina, kusjuures eksportimisel on oluline pildid eksportida kollektsiooni (Collection), mitte kompositsioonina (Composition). Teise variandiga ekrporditakse vaid üks pilt, esimesega aga kõik pildid eraldi ning seega jääb meil ligipääs igale pildile ning tema metadatale.

image thumb7 Deep Zoom albumid koos pildiinfoga

Avades selle Silverlight projekti näeme sellist pilti. Sellest projektipuust huvitavad meid sel korral failid Page.xaml, Page.xaml.cs ning Metadata.xml, kus asuvad need meie kirjutatud kirjeldused.

image thumb8 Deep Zoom albumid koos pildiinfoga Kõigepealt vaatame Page.xaml faili ning lisame sinna tekstikasti, kus piltide kirjeldusi näidata.

Lõpptulemus võiks olla näiteks selline ja siin element MultiScaleImage x:Name=”msi” on Deep Zoom album.

<UserControl x:Class="DeepZoomProject.Page"
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 Width="Auto" Height="Auto" >
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="0.95*"/>
            <RowDefinition Height="0.05*"/>
        </Grid.RowDefinitions>
        <Border Grid.Row="0" BorderBrush="#FF727272" 
                BorderThickness="1,1,1,1">
            <MultiScaleImage x:Name="msi"/>
        </Border>
        <TextBlock x:Name="taginfo" Text="Siia tuleb pildi info." 
                   Grid.Row="1" TextWrapping="Wrap" 
                   HorizontalAlignment="Stretch" 
                   FontWeight="Bold" 
                   FontFamily="Portable User Interface"/>
    </Grid>
</UserControl>

See, et sinna loodud tekstikasti näidataks iga pildi tag väärtust koosneb kolmest sammust:

  1. Kõigepealt on meil vaja teada, milline pilt fookuses on.
  2. Siis on vaja laadida Metadata.xml fail, sest seal on kirjas iga piltide metainfo.
  3. Kui me teame, milline pilt on fookuses ja Metadata.xml fail on ka laetud, siis otsime sealt LINQ abil õige tag väärtuse välja.

Milline pilt on fookuses?

Miskipärast on nii, et Silverlight koordinaadid ja DeepZoom rakenduse koordinaadid ei kattu ja seepärast on hetkel fookuses oleva pildi leidmine üks arvutamine ja teisendamine. Samas ratast me leiutama ei pea, sest veebist leiab mitmeid ja mitmeid erinevaid viise kuidas seda arvutada.

Üks arvutusviis on järgnev:

Võttes argumendiks Deep Zoom pildi (MultiScaleImage) ning hiire asukoha, käime läbi kõik alampildid (MultiScaleSubImage) ning kontrollime, kas hiire asukoht kattub mõne pildi (ViewPort) asukohaga. Enne kui me seda teha saame, peame teisendama näidatava deep zoom ruudu (ViewPort) koordinaadid vastavateks koordinaatideks DeepZoom pildi peal ning need koordinaadid omakorda teisendame koordinaatideks Silverlight rakenduse suhtes. Need viimased koordinaadid on samas mõõtkavas, kui hiire koordinaadid ja seega saame kontrollida, kas hiire koordinaadid asuvad ühe Deep Zoom pildi peal.  Koordinaatide võrdluseks loome ühe ristküliku, mille koordinaadid vastavad pildi koordinaatidele.

using System.Xml.Linq;
using System.IO;
using System.Text;
using System.Xml;
 
//Lisada viide järgmistele teekidele:
 

System.XML;

System.XML.Linq;

System.Linq;

 
//Põhineb: //http://jimlynn.wordpress.com/2008/10/28/silverlight-deep-zoom-collections-and-hit-testing/
bool GetImageTag(MultiScaleImage aMsi, Point p){
    bool gotHit = false;
    for (int i = 0; i < aMsi.SubImages.Count; i++)
    {
        MultiScaleSubImage subimage = aMsi.SubImages[i];
        
        // DeepZoom pildid on jagatud ruutudeks 
        // järgnev on hetkel kontrollitava ruudu vasaku ülemise nurga koordinaat.         // Seda hetkel näidatava pildi suhtes, 
        // mitte Silverlight rakenduse suhtes, 
        // ega ka mitte terve Deep Zoom pildi suhtes.         Point topLeft = subimage.ViewportOrigin;  
        //Võttes arvesse zoom taset,         //arvutame, kus on selle ruudu vasak ülemine nurk DeepZoom pildi suhtes.
        topLeft.X = -(topLeft.X / subimage.ViewportWidth); 
        topLeft.Y = -(topLeft.Y / subimage.ViewportWidth); 
        // Tekitatava ruudu kõrgus
        double width = 1 / subimage.ViewportWidth;
	
        // Tekitatava ruudu laius
	double height = width / subimage.AspectRatio;

	// Tekitatava ruudu ülejäänud kaks koordinaati
	Point bottomright = new Point(topLeft.X + width, topLeft.Y + height);

        // Meil on olemas ruudu koordinaadid Deep Zoom pildi suhtes,
        // teisendame need Silverlight koordinaatideks	topLeft = aMsi.LogicalToElementPoint(topLeft);
        bottomright = aMsi.LogicalToElementPoint(bottomright);
        // Kontrollime, kas hiire koordinaadid (p) on meie loodud ruudu sees
        Rect r = new Rect(topLeft, bottomright);
        if (r.Contains(p))
        {
        gotHit = true;
        // Otsime varem laetud Metadata.xml failist (muutuja metadata)
// õige pildi tag väärtuse ning seame selle tekstikasti väärtuseks.
        List<string> tags = (from image in metadata.Descendants("Image")
                            where int.Parse(image.Element("ZOrder").Value) == i + 1
                            select image.Element("Tag").Value).ToList();
        this.taginfo.Text = tags.First().ToString();
       }
    }
return gotHit;
}

Laeme Metadata.xml-i

Selleks, et me saaks XML failist infot otsida, tuleb see fail kõigepealt rakendusse laadida:

bool metadataLoaded = false;
XDocument metadata = new XDocument();

private void LoadMetadataXML()
{
    WebClient webclient = new WebClient();    webclient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(MetadataLoaded);
    webclient.DownloadStringAsync(new Uri("GeneratedImages/Metadata.xml", UriKind.RelativeOrAbsolute));
}

 

Kui fail on laetud, loeme tema sees oleva XML-i muutujasse metadata.

private void MetadataLoaded(object sender, DownloadStringCompletedEventArgs e)
{
    if (e.Error == null)
    {
	string xmlData = e.Result;

	MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(xmlData));
	XmlReader reader = XmlReader.Create(ms);
	metadata = XDocument.Load(reader);

       	metadataLoaded = true;
    }
}

XML-i laeme kohe rakenduse laadimisel:

void Page_Loaded(object sender, RoutedEventArgs e)
{
    LoadMetadataXML();
}

Nüüd ei olegi muud üle jäänud, kui hiire liigutamisel see meie GetImageTag meetod välja kutsuda:

this.MouseMove += delegate(object sender, MouseEventArgs e)
{
	GetImageTag(msi, e.GetPosition(this.msi));
	if (mouseButtonPressed)
       	{
		mouseIsDragging = true;
	}
	this.lastMousePos = e.GetPosition(this.msi);
};

Ja ongi valmis, nüüd on meil teada ka lisainfo piltide kohta. Muidugi võiks seda infot kuvada kuidagi palju peenemalt, aga ma mõtlen, et kood võiks siin näidetes võimalikult lihtsaks jääda :)

Tip #2: Silverlight täisekraanile

Silverlight template rakendused, mille loovad Expression Blend ja Visual Studio, võtavad vaikimisi ekraanil 640 x 400 pikslit. Selleks, et rakendus võtaks veebilehel ruumi nii palju kui võtta on tuleb teha järgnevat:

Page.xaml failis tuleks igasuguste paigutushaldurite (näiteks UserControl ja Grid) kõrguseks ja laiuseks panna Auto – see tähendab, et nii palju kui sisu ruumi võtab.

Et Silverlight päris täisekraanile saada tuleb kirjutada järgnevalt:

1:  Application.Current.Host.Content.IsFullScreen = true;

Kusjuures turvalisuse kaalutlustel ei saa seda teha rakenduse laadides, sest muidu teeks keegi windowsi klooni ja varastaks kõigi paroolid ära :)

Täisekraaniga on seotud ka üks sündmus: FullScreenChanged, seda võib kasutada näiteks täisekraanile viiva nupu näitamiseks ja peitmiseks:

Lisame sündmusekuulari:

1:  Application.Current.Host.Content.FullScreenChanged += new EventHandler(Content_FullScreenChanged);

Sündmusehaldur:

1:  void Content_FullScreenChanged(object sender, EventArgs e)
2:  {
3:      if (Application.Current.Host.Content.IsFullScreen)
4:      {
5:          fullscreenButton.Visibility = Visibility.Collapsed;
6:      }
7:      else {
8:          fullScreenButton.Visibility = Visibility.Visible;
9:      }
10:  }

Salavõti Deep Zoom rakendusesse

Hard Rock Cafe memrobilia veebileht on üks väga lahe näide Deep Zoom rakendusest. Äge on veel see, et sinna on sisse programmeeritud salavõti! Minge vajutage V tähte ja vaadake, mis juhtub ;) . Äge ju… aga kui keeruline seda teha on? Proovime.

Kõigepealt on meil vaja üht DeepZoom veebilehte ning kuna me tahame selle käitumist ise muuta ekpordime selle Silverlight rakendusena.

Lisame Page.xaml.cs faili sündmusekuulari klahvivajutustele:

void msi_Loaded(object sender, RoutedEventArgs e)
{
     this.KeyUp += new KeyEventHandler(Page_KeyUp);
}

Ja kogu “maagia” seisneb suurenduse ja selle asukoha (vasaku ülemise nurga) paika panekus. Otsustame ka, et salavõtmeks on meil V klahv.

void Page_KeyUp(object sender, KeyEventArgs e)
{
	if (e.Key == Key.V)
	{
            //zoomi asukoht
	    this.msi.ViewportOrigin = new Point(0.63691, 0.408636);
            //zoomi tase, mida väiksem number, seda rohkem pildi sees me oleme
	    this.msi.ViewportWidth = 0.0001;
	}
}
Ja ongi kõik, tulemust saab uurida siit.
Siin on väga hea blogipostitus, mis selgitab, mida muutujad ViewportOrigin ja ViewportWidth täpselt tähendavad.

Silverlight lumesadu

Lumesaju tekitamiseks on meil kõigepealt vaja lumehelbeid. Lume tegemist õppisime postitustes Kuidas luuakse User Controle ja User Control samm edasi.

Kõigepealt XAML kood sellest, milline rakendus esialgu välja näeb:

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="Animatsioonid.Page"
    Width="Auto" Height="Auto"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
    <Grid x:Name="LayoutRoot" Background="White"                               HorizontalAlignment="Stretch">
        <Canvas x:Name="helbed" Canvas.ZIndex="1"/>
        <Image Source="talv.jpg" Stretch="UniformToFill" />
     </Grid>
</UserControl>

Siin Canvas.ZIndex = 1 tähedab seda, et see Canvas ning objektid tema sees asuvad kõige eespool, sest helbed objekti ZIndex on kõige suurem (vaikimisi 0, aga temal määratud 1ks)

Järgmisena on meil vaja tekitada sadu või tuhandeid lumehelbeid:

private void createSnow(double intensity)
{       Random r = new Random();
    double top = 0;
    double left = 0;
    for (double i = 0; i < intensity; i++)
    {
         top = r.NextDouble() * 10;
         left = r.NextDouble() * 640;
         Snowflake flake = new Snowflake();
         flake.Width = top;
         flake.Height = top;
         flake.SetValue(Canvas.LeftProperty, left);
         flake.SetValue(Canvas.TopProperty, top*(r.Next(-1,1)));
         this.helbed.Children.Add(flake);
     }
}

Ja siis on vaja need lumehelbed langema panna. Selleks kinnitame iga lumehelbe külge ühe animatsiooni, mis liigutab helbe ekraani ülaservast alaserva… Uus kood alates 17. reast ;)

1:  private void createSnow(double intensity)
2:  {
3:      Random r = new Random();
4:      double top = 0;
5:      double left = 0;
6:      for (double i = 0; i < intensity; i++)
7:      {
8:          top = r.NextDouble() * 10;
9:          left = r.NextDouble() * this.LayoutRoot.ActualWidth;
10:          Snowflake flake = new Snowflake();
11:          flake.Width = top;
12:          flake.Height = top;
13:          flake.SetValue(Canvas.LeftProperty, left);
14:          flake.SetValue(Canvas.TopProperty, top*(r.Next(-1,1)));
15:          this.helbed.Children.Add(flake);
16:
17:          Storyboard storyboard = new Storyboard();
18:          storyboard.RepeatBehavior = RepeatBehavior.Forever;
19:          DoubleAnimation animation = new DoubleAnimation();
20:
21:          // kaua animeerime  
22:          Duration duration = new Duration(TimeSpan.FromSeconds(r.NextDouble()*10 + 5));
23:          storyboard.Duration = duration;
24:          animation.Duration = duration;
25:
26:          // keda me animeerime  
27:          Storyboard.SetTarget(animation, flake);
28:
29:          // kelle mida me animeerime  
30:          Storyboard.SetTargetProperty(animation, new PropertyPath("(Canvas.Top)"));
31:
32:          // kuidas animeerime  
33:          animation.To = this.LayoutRoot.ActualHeight;
34:
35:          // animatsioonid ressursside sekka  
36:          storyboard.Children.Add(animation);
37:          LayoutRoot.Resources.Add("unique_id" + i.ToString(), storyboard);
38:
39:          // saagu lund              
40:          storyboard.Begin();
41:      }
42:  }

Olulised kohad siin koodis on 9. ning 33.rida, kus ma kasutan this.LayoutRoot.ActualWidth ja ActualHeight väärtusi, et seada paika, kust lumehelbed oma teekonda alustada ning kus lõpetada võivad. Kuna me algus ja lõpppunktid on dünaamilised siis on nii, et kui me veebiakna suurust muudame, kohandub lumesadu end vastavalt uutele mõõtmetele.

Nüüd on vaja ainult veel createSnow meetod väljakutsuda, aga kus? Esimene idee oli mul kasutada konstruktorit, ent selle tulemusena olid kõik 1000 lumehelvest punktis 0,0 ehk siis this.LayoutRoot.ActualWidth väärtust ei olnud veel olemas.

Järgmine idee oli kutsuda meetod välja pärast seda, kui kogu Page.xaml on laetud, ehk siis Page_Loaded meetodis, ent seegi ei andnud tulemust.

Lõpuks jõudsin selleni, et createSnow kutsutakse välja, siis kui muutujad this.LayoutRoot.ActualWidth ja ActualHeight muutuvad, mis annab ka selle lisaboonuse, et lumesadu kohandub vastavalt veebiakna suurusele.

1:  public Page()
2:  {
3:      // Required to initialize variables   
4:      InitializeComponent();
5:      this.SizeChanged += new SizeChangedEventHandler(Page_SizeChanged);
6:  }
7:
8:  void Page_SizeChanged(object sender, SizeChangedEventArgs e)
9:  {
10:      createSnow(1000);
11:  }

Veel lisasin createSnow meetodi algusesse rea, mis enne 1000 uue lumehelbe lisamist eemaldab kõik eelnevad, sest muidu kasvas lumesadu väga kiiresti läbinähtamatuks tormiks ja minu kena taustapilt ei paistnud üldse välja.

1:  private void createSnow(double intensity)
2:  {
3:      // eemaldame olemasolevad helbed   
4:      helbed.Children.Clear();
5:        ...

Lõpptulemus on näha siin (Silverlight Live Streaming):

Lähtekood on siin (uuendatud 20:17, 14.12.2008): Lumesadu.zip

User Control error: Value does not fall within the expected range.

Olukord: Mul on UserControl nimega Snowflake ning ma püüan neid programselt oma lehele lisada:

Random r = new Random();
double top = 0;
double left = 0;
for (int i = 0; i < 100; i++)
{
    top = r.NextDouble()*500;
    left = r.NextDouble()*500;
    Snowflake flake = new Snowflake();
    flake.SetValue(Canvas.LeftProperty, left);
    flake.SetValue(Canvas.TopProperty, top);
    this.helbed.Children.Add(flake);
}

See aga annab mulle vea:

Error: Value does not fall within the expected range.

image thumb2 User Control error: Value does not fall within the expected range.

 

Viga tuleneb sellest, et kasutajakontrollis Snowflake on mul juurelemendil x:Name määratud ning jah tõesti Silverlight rakendustes ei saa olla 100 ühe sama x:Name väärtusega objekti.

Seega lahendus on lihtne:

Eemalda kasutajakontrolli juurelemendi x:Name väärtus.

UserControl error: member names cannot be the same as their enclosing type ja Snowflake.xaml

Error    1    ‘Snowflake’: member names cannot be the same as their enclosing type    \Snowflake.g.cs

See on üks error, mida ma näen tihedamini kui ma tahaksin, sest noh loomulikult ju ei või member name sama olla kui enclosing type aga XAML maailmas ma tihtilugu ikka täiesti kogemata teen nii aga äkki pärast blogimist enam mitte?

Kuidas see viga tekib?

Olgu meil üks tore User Control (kasutajakontroll)

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    x:Class="Animatsioonid.Snowflake">
        <Path x:Name="Snowflake" Width="Auto" Height="Auto"               S
              tretch="Fill" Fill="#FFD9F3F2"
              Data="F1 M 20.205,19.59L 20.205,17.7075L 18.765,
                    16.8L 17.3775,17.7075L 17.3775,19.59L
                    18.765,20.4975L 20.205,19.59 Z M 37.5825,24L 
                    34.275,24L 32.115,20.64L 29.1375,20.64L
                    31.2975,24L 27.9825,24L 25.8225,20.64L 
                    21.885,20.64L 23.805,23.8575L 27.7425,24L
                    29.4225,26.88L 25.44,26.925L 26.925,29.61L 
                    30.9075,29.76L 32.5425,32.64L 28.56,32.355L
                    29.52,33.9825L 26.31,35.805L 25.395,34.2225L" />
</UserControl>

Kõik on korras ja ühtegi viga eelnev kood ei anna… seni kuni me seda kusagil kasutada ei püüa.

Kui kasutame hakkame:

<u:Snowflake/>

Saame vea:

Error    1    ‘Snowflake’: member names cannot be the same as their enclosing type  

Mis on ilmselgelt tingitud sellest, et klassinimi on Animatsioonid.Snowflake ja Pathi selle sees ma nimetasin ka Snowflake’ks, kuigi tegelikult ei ole sellel Pathil üldse nime vaja ja kui ongi, siis ei tohiks see kindlasti olla sama kui UserControli nimi. Aga jah selle veani on võimalik jõuda siis kui ollakse liiga agar ja kõikidele asjadele nimed antakse :)

Ja neile, kes jõudsid siia otsides lumehelbe xaml-i, siis terve lumehelbe xaml kood on siin failis: Snowflake.xaml

User Control – samm edasi

Eelmises postituses on kirjas, mis kasutajakontrollid on ning kuidas neid luua. SIin posituses tuleb juttu sellest, kuidas olemasolevate kasutajakontrollide välimust muuta ning neile funktsionaalsust lisada.

Eelmises postituses lõime kasutajakontrolli nimega Snowflake, mida sai kasutada järgnevalt: <u:Snowflake/>, mis kuvas 40 x 40 piksli suuruse helesinise lumehelbe.

Laiendades kirjutist muutes suurust või taustavärvi:

<u:Snowflake x:Name="aFlake" Height="100" Width="100" Background="Orange"/>

ei saa me oodatud tulemust, sest lumehelves paistab sama suur ning värvuselt on ta jätkuvalt helesinine.

Üks võimalus oleks läheneda probleemile programmikoodis, modifitseerides objekti aFlake (üks konkreetne lumehelves) muutuja _flakePath (_flakePath on selle Path objekti x:Name, mis asub Snowflake.xaml user control’is) suurust ja laiust:

aFlake._flakePath.Width = 100; aFlake._flakePath.Height = 100;

Kuid palju mugavam oleks ju see xaml koodis kirja panna. Et see võimalik oleks, tuleb muuta esialgse kasutajakontrolli koodi.

Hetkel on nii Snowflake UserControl juurelemendis kui ka Path elemenis kirjas nii laius kui ka kõrgus:

<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x= . . .
     Width="400" Height="300">
    <Path x:Name="_flakePath" Width="40" Height="40" . . . />
</UserControl>

Kui need Width ja Height ära kustutada siis edaspidi tuleb meie lumehelbeke täpselt nii suur, kui tema xaml koodis kirjas on – näiteks 100 x 100 pikslit.

<u:Snowflake x:Name="mySnowFlake" Width="100" Height="100" />

Laiendame XAML-i

Erivärviliste lumehelvestega on veidi keerulisem, sest <u:Snowflake Background=”Red” /> ei mõju, sest see värviks kasutajakontrolli tausta mitte kasutajakontrolli sees oleva lumehelbe tausta. Seda, mida teeb sõna Background XAML koodis, me muuta ei saa, küll aga saame kasutajakontrollile ise muutujaid lisada:

Failis Snowflake.xaml.cs tuleb lisada isendimuutuja lumehelbekese värvi määramiseks:

public Brush Fill
{
    get
    {
        return this._flakePath.Fill;
    }
    set
    {
        this._flakePath.Fill = value;
    }
}

Seejärel saame kirjutada nii:

<u:Snowflake x:Name="aFlake" Height="100" Width="100" Fill="Snow" />

Ja saamegi lumevärvi lumehelbekese suurusega 100 x 100 pikslit :)

Kuidas luuakse User Control’e

Mis need on?

User Controlid ehk kasutajakontrollid (?) on viis kasutajaliidese ja ka loogika kaspeldamiseks Silverlight ja ASP.NET rakendustes.

Lihtsaim näide sellest on tavaline vorm aadressi sisestamiseks – teate ju küll neid (riik, maakond, linn/küla,indeks, maja, korter), selle tegemine nõuaks mingi ~10 rida XAML koodi ilmselt. Aga kujutagem ette stsenaariumit, kus on vaja kaht sellist vormi näiteks arve aadressi ja postiaadressi jaoks, siis läheks ju juba ~20 rida XAML koodi + ehk on veel ka mingi loogika, mis kontrollib, kas vormid on hästi täidetud. Et vähem koodi oleks, on meil vaja aadressivorm kapseldada kasutajakontrolliks nii et seda saaks taaskasutada!

Kes tahab teada, kuidas see aadressi vormide näide täpselt edasi käib, võib lugeda Scott Guthre’i blogipostitust, mina jätkan näitega, kus mul on väga paljudest Path punktidest koosnev lumehelves, mida ma tahaks sadu kordi kloonida, et tuleks korralik lumesadu!

Miks neid vaja läheb?

Esialgne lumehelves on selline, see koosneb 1857 tähemärgist, ehk siis on piisavalt suur, et ma ei tahaks seda 100 kordi lõigata ja kleepida:

<Path x:Name="Snowflake" Width="40" Height="40" Stretch="Fill"
Fill="#FFD9F3F2" Data="F1 M 20.205,19.59L 20.205,17.7075L />
18.765,16.8L 17.3775,17.7075L 17.3775,19.59L
18.765,20.4975L 20.205,19.59 Z M 37.5825,24L
34.275,24L 32.115,20.64L 29.1375,20.64L
31.2975,24L 27.9825,24L 25.8225,20.64L
21.885,20.64L 23.805,23.8575L 27.7425,24L
29.4225,26.88L 25.44,26.925L 26.925,29.61L
30.9075,29.76L 32.5425,32.64L 28.56,32.355L
29.52,33.9825L 26.31,35.805L 25.395,34.2225L
23.4225,37.92L 21.7575,34.9275L 23.6775,31.3275L
22.275,28.8L 20.3025,32.64L 18.63,29.58L
20.55,25.845L 18.6075,22.515L 16.755,25.7775L
18.6225,29.3325L 16.9425,32.16L 15.0675,28.6575L
13.5825,31.245L 15.4575,34.755L 13.8225,37.5825L
11.955,34.08L 11.04,35.6625L 7.8225,33.84L
8.7825,32.205L 4.6575,32.355L 6.2925,29.52L
10.4175,29.3775L 11.9025,26.835L 7.7775,26.925L
9.4575,24.09L 13.5375,23.9475L 15.5025,20.5425L
11.805,20.5425L 9.69,23.9025L 6.285,23.9025L
8.4,20.5425L 5.565,20.5425L 3.45,23.9025L
0.0449994,23.9025L 2.16,20.5425L 0.3375,20.5425L 
0.3375,16.845L 2.16,16.845L 0,13.3425L 3.2625,13.3425L 
5.475,16.845L 8.4,16.845L 6.24,13.3425L 9.5475,13.3425L
11.7075,16.845L 15.645,16.845L 13.7775,13.5825L 9.795,
13.44L 8.16,10.56L 12.0975,10.56L 10.6125,8.085L 
6.675,7.8975L 5.04,5.1825L 8.9775,5.28L8.0625,3.675L 
11.28,1.875L 12.195,3.4575L 14.115,0L 15.855,2.7825L
13.8675,6.3675L 15.315,8.88L 17.28,5.28L 18.96,8.1975L 17.01,11.7825L
18.9225,15.12L 20.835,11.8575L 18.96,8.355L 20.64,5.475L 22.4625,9.0225L
23.955,6.435L 22.125,2.925L 23.76,0.0974998L 25.5825,3.6L 26.5425,1.965L
29.715,3.7575L 28.8,5.28L 32.925,5.28L 31.29,8.1375L 27.165,8.235L
25.68,10.845L 29.805,10.56L 28.125,13.305L 24,13.44L 22.08,16.8L
25.8225,16.8L 27.9375,13.44L 31.245,13.44L 29.1375,16.8L 32.115,16.8L
34.2225,13.44L 37.485,13.44L 35.3775,16.8L 37.245,16.8L 37.245,20.64L
35.3775,20.64L 37.5825,24 Z" />

Uue kasutajakontrolli loomine

Selleks on kaks võimalust. Kasutades programmi Expression Blend tuleb valida need objektid, mida kasutajakontrolliks kapseldada soovitakse, teha paremklikk ning valida Make Control. ScreenShot001Selle tulemusena avaneb veel üks aken, mis küsib kasutajakontrollile nime ning, mis tuleks teha esialgse sisuga (meie puhul, siis selle 1857 tähemärgiga) – kas asendada kasutajakontrolli koodiga või jätta nii kuis on.

ScreenShot002 Lõpuks saame faili Snowflake.xaml, mille sisuks on kõik see, mis üleeelmises sammus valitud sai (aadressi vormi puhul, siis kõik vormi väljad, nende kirjeldused …).

<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc=http://schemas.openxmlformats.org/markup-compatibility/2006
             x:Class="Projekt.Snowflake">
   <Path Width="40" Height="40" Stretch="Fill" Fill="#FFD9F3F2"
         Data="F1 M 20.205,19.59L 20.205,17.7075L 18.765,16.8L..."/>
</UserControl>

Kasutajakontrolli loomine Visual Studio abil on samuti lihtne. Tuleb Silverlight projektis valida Add New Item ning seejärel suure hulga valikute seast leida üles Silverlight User Control ning anda talle nimi. Kui Expression Blendis oli kood juba õiges kohas, siis Add new Item meetodit kasutades tuleb õige kood ise Grid märgendite vahele kleepida.

image thumb Kuidas luuakse User Control’e

Kuidas iganes see kasutaja kontroll ka loodud sai, selle kasutamine on õige lihtne :)

Kuidas kasutada?

Esmalt tuleb XAML faili päises kasutajakontrollile viidata:

Untitled Süntaks selleks on xmlns:MINU_ENDA_VALITUD_LÜHEND=””clr-namespace:PROJEKTINIMI”

Näiteks projektis nimega Projekt näeb see asi välja nii:

xmlns:u="clr-namespace:Projekt"

Nüüd edaspidi võin luua lumehelbeid nii:

<u:Snowflake/>

Mis asendab kõik need 1857 tähemärki või mitu neid oligi.

A ja see kurikuulus lumehelbeke näeb välja selline:

image thumb1 Kuidas luuakse User Control’e

1200 kordne suurendus … vektorgraafika ruulib :)

Animatsioonide loomine C# koodis

Üks asi, mida ma pidevalt dokumentatsioonist järgi vaatan on animatsioonide programne loomine, no ma ei tea, igakord on mingi näpukas sees.

Seega siin on kood lihtsa animatsiooni loomiseks:

private void Rectangle_MouseEnter(object sender, MouseEventArgs e) {

 
Rectangle animatedRect = sender as Rectangle;
            
Storyboard storyboard = new Storyboard();
DoubleAnimation widthAnimation = new DoubleAnimation();
DoubleAnimation heightAnimation = new DoubleAnimation();
// kaua animeerime
Duration duration = new Duration(TimeSpan.FromSeconds(1));
storyboard.Duration = duration;
widthAnimation.Duration = duration;
heightAnimation.Duration = duration;
// keda me animeerime
Storyboard.SetTarget(widthAnimation, animatedRect);
Storyboard.SetTarget(heightAnimation, animatedRect);
// kelle mida me animeerime
Storyboard.SetTargetProperty(widthAnimation, new PropertyPath("(Width)"));
Storyboard.SetTargetProperty(heightAnimation, new PropertyPath("(Height)"));
 
// kuidas animeerime
widthAnimation.To = animatedRect.ActualWidth * 2;
heightAnimation.To = animatedRect.ActualHeight * 2;
// animatsioonid ressursside sekka
storyboard.Children.Add(widthAnimation);
storyboard.Children.Add(heightAnimation);
LayoutRoot.Resources.Add("unique_id", storyboard);
// saagu valgus
storyboard.Begin();
}

Sama asi dokumentatsioonis

Silverlight Toolkit – kuidas kasutada?

Eile väljatulnud Silverlight kasutajaliidese elemendid ei ole Silverlight-i sisseehitatud nagu kõik teised, vaid nad need tuleb Codeplexist allalaadida. Aga kuidas nad siis sinu projekti saavad?

Lihtne!

Selleks tuleb kõigepealt Toolkit Codeplex projekti lehelt allalaadida.

Seejärel Visual Studios paremklikk projekti peal ning valida Add Reference ning sealt omakorda sirvida kataloogi, kus vajalikud dll-id asuvad. Toolkit/Binaries kataloogis nätieks.

reference thumb Silverlight Toolkit – kuidas kasutada?

Iga dll sisaldab siis erinevaid elemente, lisada siis need mida konkreetselt vaja läheb.

Järgmisena peab XAML failis ka mainima, et tahame kasutada ressursse just sellest konkreetsest dll-ist:

ScreenShot001Selleks loome XAML faili päises uue nimerumi, trükkides xmlns:midagi ja oodates koodivihjamist, kes pakub erinevaid dll-e. Sealt valida, see millele just viite lisasime.

Ja ongi valmis, nüüd saame selle dll-i ressursse kasutada kirjutades <t:

ScreenShot002

Vanemad