offline
- Srki94
- Mod u pemziji
- Pridružio: 14 Feb 2008
- Poruke: 12403
|
Revizija 1
Indeks :
0 Izmene
1 Kreiranje Canvasa i drugih kontrola
1.2 Kreiranje drugih kontrola
2 Podešavanje kontrola
3.Data Binding
3.1 Povezivanje preko IDEa
3.2 Povezivanje preko XAML-a
4. Programiranje
4.1 Animiranje Canvasa kodom
4.2 Funkcija za animiranje ikonica
4.3 Funkcija za repozicioniranje ikonica
#0 Izmene
- Dodat deo aplikacije sa opcijama
- Animiranje prikaza tog dela
- Animiranje stanja ikonica (mouse over, mouse leave, click) upotrebom animation sistema
WIP Pregled :
Trenutni tech plan :
- Kreiranje canvasa za opcije
-- Podešavanje kontrola na njemu
-- Bindovanje kontrola
- Pisanje animacije za otvaranje i zatavaranje prozora
-- Kreiranje animacije kodom
-- Kreiranje animacije u XAML-u
- Povezivanje opcija sa prethodno hardkodiranim vrednostima
-- Pisanje funkcije za novo crtanje svih ikonica sa novim vrednostima
- Animacije ikonica
-- Pisanje funkcije koja će sadržati sve animacije u programu i koju ćemo pozvati prilikom eventa a koja će primeniti animaciju na prosleđeni objekat
#1 Kreiranje Canvasa i drugih kontrola
U prethodnom tutorijalu smo hardkodirali vrednosti poput veličine ikonica, offseta između njih, animacija itd. Želim da oslobodim te vrednosti pa ćemo napraviti mali set opcija koji će se prikazati kada ih pozovemo iz context menija na samom launcheru.
Prvi deo ove sekcije je "lickanje" izgleda i podešavanje kontrola po želji.
#1.1 Kreiranje Canvasa
Prvo što ćemo uraditi jeste kreiranje Canvas kontrole. Ona je jedan od mnogih tipova "Panela" u WPF-u i omogućiće nam da grupišemo sve kontrole na njoj i da ih po želji pomeramo ukoliko za to ima potrebe.
WPF ima mnogo Panel-like kontrola koje rade mnogo različitih sortiranja za vas inače...
Preporučujem da bacite pogled na ovo ako vas baš interesuje :
https://msdn.microsoft.com/en-us/library/ms754152%28v=vs.110%29.aspx
http://www.codeproject.com/Articles/140613/WPF-Tut.....yout-Trans
Elem :
1. Dizajner > Selektujte grid > Toolbox > Canvas > Dupli klik
Raširite Canvas po želji da odgovara vašem projektu.
2. Dok je selektovan Canvas > Properties kartica > Brush > Solid Color ili Gradient > Podesite boju > Properties Kartica > Name > canvas1
Ukoliko ste ispratili dva koraka iznad, sada imate kontrolu canvas1 koja se jasno vidi na prozoru.
Ukoliko ipak ne vidite canvas, uverite se da je Canvas "child" Grida i da je prozor (Window) dovoljno širok ili dugačak...
#1.2 Kreiranje drugih kontrola
Sada ćemo kreirati druge kontrole koje će nam trebati :
Slider x2 i textbox x2- Za veličinu ikonica i offset između istih
3x combobox - Za izbor teme, mouse over efekta i mouse click efekta
Slider - za podešavanje transparentnosti launchera
Label - Za tekstove i informacije
Iz Toolboxa birajte odgovarajuće kontrole i prevucite ih na prozor. Uverite se da je svaka od navedenih kontrola "Child" canvas1 kontrole. Ukoliko kontrola nije Child, jednostavno je prevucite na Canvas u Document Outline kartici.
Trenutno canvas izgleda ovako :
Vi naravno možete da pravite ono što vam odgovara ali ako želite da pratite tutorijal, savetujem da prekopirate sve kontrole koje ja imam na prozoru.
Svaka od kontrola ima u Properties prozoru mnogo opcija za izgled pa možete i tu da "svratite" kako bi ulepšali iste. Ja sam dobio ovakav izgled samo menjajući boje u Brush sekciji Properties kartice.
#2 Podešavanje kontrola
Pretpostaviću da ste do ovog trenutka napravili kanvas i na njemu napravili kontrole koje sam spomenuo iznad.
Prvo ću preimenovati neke od kontrola jer će nam trebati ime u kodu kasnije.
Kliknite na svaku od kontrola koju spomenem i promenite parametar "Name" :
Klizač za providnost launchera - opacitySlider
Klizač za veličinu ikonice - iconSizeSlider
Klizač za razmak između ikonica - iconOffsetSlider
Strelicama sam obeležio kontrole i mesto gde menjate naziv istih.
Ostalo je još samo da podesimo neke vrednosti.
Na primer, iako se Opacity vidi u Properties kartici kao 0-100, vrednost je zapravo 0-1.
Stoga moramo da izmenimo Dock Opacity klizač (opacitySlider).
1. Kliknite na opacitySlider > Properties > Common :
Large Change : 0.1
Maximum : 1
Minimum : 0
Small Change : 0.1
Tick Frequency : 0.1
Ispod tog klizača se nalazi jedan Label. On će nam govoriti kolika je vrednosti klizača.
2. Klik na taj label > Properties kartica > ContentStringFormat :
Upišite u polje : {0:N2}%
To će nam dodatno formatirati unos kasnije.
Ideja je za sada da ovaj combo box na sredini, ispod natpisa "Theme" sadrži resurse u vidu GFX elementa koji su predefinisani i koji će menjati pozadinu launchera.
To ćemo možda kasnije zameniti nekom kontrolom i generisati oblike kodom, međutim za sada nam treba samo prikaz svih tema koje se nalaze u resursima.
Ukoliko ste pratili prvi tutorijal znate da samo napravili GFX element i sačuvali ga u resursima aplikacije.
Sada ćemo dodati nove unose u kolekciju Theme combo boxa.
1. Klik na Theme Combo Box > Properties > Common > Items > ... (dugme)
2. (Novi prozor) Combo box > Other Type > Search box > System.Windows.Controls.Image >
Selektujte kontrolu > OK
3. U combo boxu će se pojaviti unos "Image", selektujte ga i kliknite na Add.
4. Selektujte novi unos na Items listi, desno će se pojaviti properties > Common :
Source : Izaberite grafički element
Stretch : Fill
StretchDirection : Both
Layout >
Width : 504
Height : 67
Vrednosti odgovaraju mom combo boxu i u suštini će ispuniti combo box grafičkim elementom tako d
5. Kada potvrdite sa OK, kliknite ponovo na Combo Box i u Common kartici promenite vrednost polja "Selected Index" sa -1 na 0
#3. Data Binding
Sada bi u Windows Formsu morali da napišemo event kod koji bi menjao polje svaki put kada bi pomerili klizač, na primer. Međutim to nije slučaj u WPF-u.
Iako to možemo da uradimo - nećemo, već ćemo iskoristiti prednost Bindinga.
DataBinding nam omogućava da povežemo dva elementa, bilo da su ta dva elementa na UI-u ili duboko u logici koda.
Jednom povezani, elementi će uvek prepoznati izmene i ažurirati sebe, bez potrebe da se napiše kod koji obrađuje event.
Mi ćemo sada povezati klizač za providnost launchera sa grafičkim elementom. Povezaćemo vrednost klizača na vrednost opacity osobine tog elementa. Svaki put kada korisnik pomeri klizač, Opacity polje će se ažurirati u skladu sa klizačem !
Zatim ćemo povezati preostala dva klizača sa textbox kontrolama.
Binding možemo uraditi na par načina.
Ja ću pokazati kako se može uraditi iz XAML-a i samog Editora.
#3.1 Povezivanje opacity vrednosti na value vrednost slidera preko interfejsa
1. Kliknite na grafički element launchera
2. Properties kartica > Opacity > Kockica pored polja za unos > Create Data Binding
3. Element Name > opacitySlider > Value > OK
Pokrenite aplikaciju i pomerite opacity klizač. Videćete da se vrednost transparentnosti grafičkog elementa menja u skladu sa vrednošću klizača.
#3.2 Povezivanje vrednosti klizača za veličinu ikonice na tekst vrednost tekst polja preko XAML-a
Drugi način da povežemo dve kontrole je da napišemo kod u XAML-u.
1. Kliknite na txtIconSize kontrolu > Otvorite XAML pregled
2. U definiciji text kontrole, dopišite :
Text="{Binding Value, ElementName=iconSizeSlider}
Pokrenite aplikaciju i pomerite klizač - videćete da je vrednost klizača povezana.
Međutim ovo je ipak kozmetički prikaz korisniku, mi ćemo morati drugačije da iskoristimo ove podatke.
Bilo kojom metodom, povežite ostale vrednosti klizača sa odgovarajućim kontrolama na isti način.
- Selektujete kontrolu gde želite da prikažete vrednost
- Povežete vrednost po izboru
Evo kako izgleda forma, strelicama sam označio polja i slajdere koje trebate povezati :
Treba naglasiti da je naravno moguće i kodom podesiti Binding, više o tome : https://msdn.microsoft.com/en-us/library/ms742863%28v=vs.110%29.aspx
U slučaju da ste negde zapeli, evo gotovog XAML koda za nove kontrole koje sam dodao sa svim podešavanjima primenjenim do sada :
+ XAML<Canvas x:Name="canvas1" HorizontalAlignment="Left" Margin="32,50,0,0" Width="1422" Panel.ZIndex="-1" Height="210" VerticalAlignment="Top">
<Canvas.Background>
<LinearGradientBrush EndPoint="0.5,1" MappingMode="RelativeToBoundingBox" StartPoint="0.5,0">
<GradientStop Color="#FF3B3A46" Offset="1"/>
<GradientStop Color="#FF3A3332"/>
<GradientStop Color="#FF1B181F" Offset="0.929"/>
</LinearGradientBrush>
</Canvas.Background>
<Label Content="Icon Settings :" RenderTransformOrigin="2.5,3.269" Height="27" Width="101" Canvas.Left="26" Canvas.Top="32" FontWeight="Bold" Background="{x:Null}" Foreground="White"/>
<Label Content="Size :" RenderTransformOrigin="2.5,3.269" Height="27" Width="42" Canvas.Left="34" Canvas.Top="67" Background="{x:Null}" Foreground="White"/>
<TextBox x:Name="txtIconSize" Height="23" TextWrapping="Wrap" Width="32" Canvas.Left="81" Canvas.Top="71" Text="{Binding Value, ElementName=iconSizeSlider}">
<TextBox.BorderBrush>
<LinearGradientBrush EndPoint="0,20" MappingMode="Absolute" StartPoint="0,0">
<GradientStop Color="#FFABADB3" Offset="0.05"/>
<GradientStop Color="#FFE2E3EA" Offset="0.07"/>
<GradientStop Color="#FF0080FF" Offset="1"/>
</LinearGradientBrush>
</TextBox.BorderBrush>
</TextBox>
<Label Content="Offset :" RenderTransformOrigin="2.5,3.269" Height="27" Width="47" Canvas.Left="29" Canvas.Top="135" Background="{x:Null}" Foreground="White"/>
<TextBox x:Name="txtIconOffset" Height="23" TextWrapping="Wrap" Text="{Binding Value, ElementName=iconOffsetSlider}" Width="32" Canvas.Left="81" Canvas.Top="137"/>
<Label Content="px" RenderTransformOrigin="2.5,3.269" Height="27" Width="25" Canvas.Left="113" Canvas.Top="72" Foreground="White"/>
<Label Content="px" RenderTransformOrigin="2.5,3.269" Height="27" Width="25" Canvas.Left="113" Canvas.Top="135" Foreground="White"/>
<Label Content="Animations :" RenderTransformOrigin="2.5,3.269" Height="27" Width="101" Canvas.Left="267" Canvas.Top="32" FontWeight="Bold" Background="{x:Null}" Foreground="White"/>
<Label Content="Icon Mouse Over :" RenderTransformOrigin="2.5,3.269" Height="27" Width="126" Canvas.Left="155" Canvas.Top="72" Background="{x:Null}" Foreground="White"/>
<Label Content="Icon Click :" RenderTransformOrigin="2.5,3.269" Height="27" Width="68" Canvas.Left="194" Canvas.Top="106" Background="{x:Null}" Foreground="White"/>
<ComboBox Width="101" Canvas.Left="267" Canvas.Top="77" SelectedIndex="0">
<ComboBox.Background>
<LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#FFD7DDEA" Offset="0"/>
<GradientStop Color="#FFEBEBEB" Offset="0.5"/>
<GradientStop Color="#FFBABCBF" Offset="0.5"/>
<GradientStop Color="#FF4A4F5B" Offset="1"/>
</LinearGradientBrush>
</ComboBox.Background>
</ComboBox>
<ComboBox Width="101" Canvas.Left="267" Canvas.Top="109" SelectedIndex="0">
<ComboBox.Background>
<LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#FFD7DDEA" Offset="0"/>
<GradientStop Color="#FFEBEBEB" Offset="0.5"/>
<GradientStop Color="#FFBABCBF" Offset="0.5"/>
<GradientStop Color="#FF4A4F5B" Offset="1"/>
</LinearGradientBrush>
</ComboBox.Background>
</ComboBox>
<Label Content="Theme :" RenderTransformOrigin="2.5,3.269" Height="27" Width="66" Canvas.Left="642" Canvas.Top="32" FontWeight="Bold" Background="{x:Null}" Foreground="White"/>
<Label Content="Dock Opacity :" RenderTransformOrigin="2.5,3.269" Height="27" Width="97" Canvas.Left="443" Canvas.Top="153" Background="{x:Null}" Foreground="White"/>
<ComboBox Width="504" Canvas.Left="443" Canvas.Top="66" Height="67" Opacity="0.8" SelectedIndex="0">
<ComboBox.Background>
<LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#FFD7DDEA" Offset="0"/>
<GradientStop Color="#FFEBEBEB" Offset="0.5"/>
<GradientStop Color="#FFBABCBF" Offset="0.5"/>
<GradientStop Color="#FF4A4F5B" Offset="1"/>
</LinearGradientBrush>
</ComboBox.Background>
<Image HorizontalAlignment="Right" Height="67" Source="Resources/GFXLauncher.png" Stretch="Fill" Width="504"/>
</ComboBox>
<Slider x:Name="opacitySlider" Canvas.Left="563" Canvas.Top="158" Width="370" BorderThickness="0" Maximum="1" TickFrequency="0.1" LargeChange="0.1" Value="1"/>
<Slider x:Name="iconSizeSlider" Canvas.Left="34" Canvas.Top="104" Width="104" Height="17" Maximum="512" Minimum="16" />
<Slider x:Name="iconOffsetSlider" Canvas.Left="34" Canvas.Top="167" Width="104" Height="17"/>
<Label ContentStringFormat="{}{0:N2}%" RenderTransformOrigin="2.5,3.269" Height="30" Width="51" Canvas.Left="697" Canvas.Top="170" Background="{x:Null}" Foreground="White" Content="{Binding Value, ElementName=opacitySlider}"/>
<Label Content="Dock :" RenderTransformOrigin="2.5,3.269" Height="27" Width="66" Canvas.Left="1123" Canvas.Top="32" FontWeight="Bold" Background="{x:Null}" Foreground="White"/>
<Label Content="Top : " RenderTransformOrigin="2.5,3.269" Height="27" Width="42" Canvas.Left="1028" Canvas.Top="67" Background="{x:Null}" Foreground="White"/>
<TextBox x:Name="txtIconSize_Copy" Height="23" TextWrapping="Wrap" Width="32" Canvas.Left="1075" Canvas.Top="71" Text="{Binding Value, ElementName=dockTopOffsetSlider}">
<TextBox.BorderBrush>
<LinearGradientBrush EndPoint="0,20" MappingMode="Absolute" StartPoint="0,0">
<GradientStop Color="#FFABADB3" Offset="0.05"/>
<GradientStop Color="#FFE2E3EA" Offset="0.07"/>
<GradientStop Color="#FF0080FF" Offset="1"/>
</LinearGradientBrush>
</TextBox.BorderBrush>
</TextBox>
<Label Content="px" RenderTransformOrigin="2.5,3.269" Height="27" Width="25" Canvas.Left="1107" Canvas.Top="72" Foreground="White"/>
<Slider x:Name="dockTopOffsetSlider" Canvas.Left="1028" Canvas.Top="104" Width="104" Height="17" Maximum="512" />
<Label Content="Left:" RenderTransformOrigin="2.5,3.269" Height="27" Width="42" Canvas.Left="1014" Canvas.Top="147" Background="{x:Null}" Foreground="White"/>
<TextBox x:Name="txtWindowPosLeft" Height="23" TextWrapping="Wrap" Width="32" Canvas.Left="1061" Canvas.Top="151" Text="{Binding Value, ElementName=dockLeftOffsetSlider}">
<TextBox.BorderBrush>
<LinearGradientBrush EndPoint="0,20" MappingMode="Absolute" StartPoint="0,0">
<GradientStop Color="#FFABADB3" Offset="0.05"/>
<GradientStop Color="#FFE2E3EA" Offset="0.07"/>
<GradientStop Color="#FF0080FF" Offset="1"/>
</LinearGradientBrush>
</TextBox.BorderBrush>
</TextBox>
<Label Content="px" RenderTransformOrigin="2.5,3.269" Height="27" Width="25" Canvas.Left="1093" Canvas.Top="152" Foreground="White"/>
<Slider x:Name="dockLeftOffsetSlider" Canvas.Left="1123" Canvas.Top="121" Width="25" Height="82" Maximum="512" SmallChange="1" Orientation="Vertical" />
<Label Content="Width : " RenderTransformOrigin="2.5,3.269" Height="27" Width="60" Canvas.Left="1183" Canvas.Top="67" Background="{x:Null}" Foreground="White"/>
<TextBox x:Name="txtIconSize_Copy2" Height="23" TextWrapping="Wrap" Width="32" Canvas.Left="1230" Canvas.Top="71" Text="{Binding Value, ElementName=dockWidthSlider}">
<TextBox.BorderBrush>
<LinearGradientBrush EndPoint="0,20" MappingMode="Absolute" StartPoint="0,0">
<GradientStop Color="#FFABADB3" Offset="0.05"/>
<GradientStop Color="#FFE2E3EA" Offset="0.07"/>
<GradientStop Color="#FF0080FF" Offset="1"/>
</LinearGradientBrush>
</TextBox.BorderBrush>
</TextBox>
<Label Content="px" RenderTransformOrigin="2.5,3.269" Height="27" Width="25" Canvas.Left="1262" Canvas.Top="72" Foreground="White"/>
<Slider x:Name="dockWidthSlider" Canvas.Left="1183" Canvas.Top="104" Width="104" Height="17" Maximum="1980" Minimum="16" Value="1488" />
<Label Content="Height :" RenderTransformOrigin="2.5,3.269" Height="27" Width="60" Canvas.Left="1183" Canvas.Top="135" Background="{x:Null}" Foreground="White"/>
<TextBox x:Name="txtIconSize_Copy3" Height="23" TextWrapping="Wrap" Width="32" Canvas.Left="1230" Canvas.Top="137" Text="{Binding Value, ElementName=dockHeightSlider}">
<TextBox.BorderBrush>
<LinearGradientBrush EndPoint="0,20" MappingMode="Absolute" StartPoint="0,0">
<GradientStop Color="#FFABADB3" Offset="0.05"/>
<GradientStop Color="#FFE2E3EA" Offset="0.07"/>
<GradientStop Color="#FF0080FF" Offset="1"/>
</LinearGradientBrush>
</TextBox.BorderBrush>
</TextBox>
<Label Content="px" RenderTransformOrigin="2.5,3.269" Height="27" Width="25" Canvas.Left="1262" Canvas.Top="138" Foreground="White"/>
<Slider x:Name="dockHeightSlider" Canvas.Left="1183" Canvas.Top="170" Width="104" Height="17" Maximum="512" Minimum="16" Value="50" />
</Canvas>
Ninja izmena :
Zaboravio sam da vam kažem da vežete još dve vrednosti :
Vežite Height i Width vrednosti grafičkog elementa na value vrednost slidera za Width i Height
1. Klik na grafički element launchera > Properties > Margin >
4. Programiranje
Sada kada imamo sve kontrole spremne, počećemo sa programerskim delom posla.
Pre svega želimo da prikažemo korisniku ovaj canvas svaki put kada izabere "Options" iz context menija. Takođe želimo da animiramo prikaz Canvasa.
Prvo ćemo dodati novi unos u Context Meniju kog smo napravili u prvom tutorijalu.
1. XAML Pregled > Window.Resources > Context Menu > Ispod linije koja definiše prvi unos u meniju kopiramo :
Dakle, samo smo dodali unos u Context Meni koji je već povezan sa prozorom i napravićemo handler koji će pozvati funkciju za prikaz opcija.
2. Prikaz C# koda > Napravite novi handler :
private void ShowOptions_Click(object sender, RoutedEventArgs e)
{
ShowOptionsAnim();
}
// VS je mogao sam da vam napravi handler ukoliko ste, dok je selektovan naziv eventa u XAML-u, pritisnuli F12
3. Odmah ispod njega, napravite novu funkciju sa nazivom "ShowOptionsAnim"
void ShowOptionsAnim()
{
}
#4.1 Animiranje Canvasa kodom
ShowOptionsAnim će kreirati animacije, povezati ih na Canvas, izmeniti svojstva ukoliko je to potrebno i pustiti ih.
Kada je sama animacija u pitanju, želim da se Canvas proširi sa svoje visine na određenu visinu i da vremenom postaje "vidljiv".
Za ovo će nam trebati dve različite double animacije.
Njih možemo ovako deklarisati :
Doubleanimation foldout = new DoubleAnimation();
Animaciji moramo da definišemo nekoliko kritičnih parametara :
From
To
Duration
Dakle, od kog broja/koje vrednosti animacija počinje, dokle i koliko će trajati.
To možemo da uradimo ovako :
foldout.From = 2;
foldout.To = 5;
foldout.Duration = new Duration(TimeSpan.FromSeconds(.25))
Ovako :
DoubleAnimation foldout = NewAnimation(2, 5, Duration(TimeSpan.FromSeconds(.25)));
Ili ovako :
DoubleAnimation foldout = NewAnimation()
{
From = 2,
To = 5,
Duration = Duration(TimeSpan.FromSeconds(.25))
}
Kako god preferirate i kako god vam je čitljivije...
Za upotrebu animacija će nam trebati namespace : System.Windows.Media.Animation, možete ga dodati ručno ili preko VS-a :
Dakle trebaće mi animacija koja će proširiti visinu canvasa od trenutne vrednosti Canvasa do fiksne vrednosti.
Definisaću animaciju foldout koja će proširiti vrednost od Canvas1.height vrednosti do fiksne vrednosti :
DoubleAnimation foldout = new DoubleAnimation(canvas1.Height, 258, new Duration(TimeSpan.FromSeconds(.25)));
Trebaće mi i animacija za opacity vrednost :
DoubleAnimation fadeIn = new DoubleAnimation(0, 1, new Duration(TimeSpan.FromSeconds(.50)));
Na kraju, zbog toga što mi kontrole nisu vezane za canvas po pitanju prikaza, moraću da napravim još jednu animaciju koja će biti zaslužna za sam prozor :
DoubleAnimation winFoldout = new DoubleAnimation(mainWindow.Height, 258, new Duration(TimeSpan.FromSeconds(.25)));
Animacije ćemo dodati u novi Storyboard koji će nam omogućiti da lako kontrolišemo više animacija, prvo ću definisati novi Storyboard pa ću dodati prethodne animacije u isti :
Storyboard storyBoard = new Storyboard();
storyBoard.Children.Add(foldout);
storyBoard.Children.Add(fadeIn);
storyBoard.Children.Add(winFoldout);
Sada moram da podesim ciljane vrednosti i ciljanu kontrolu naših animacija.
Ovo mogu da uradim preko Storyboard klase uz pomoć funkcija SetTargetName, koja će pripojiti animaciju nekoj kontroli i SetTargetProperty koja će precizirati tip vrednosti koju ciljamo.
Storyboard.SetTargetName(foldout, canvas1.Name);
Storyboard.SetTargetName(fadeIn, canvas1.Name);
Storyboard.SetTargetProperty(fadeIn, new PropertyPath(OpacityProperty));
Storyboard.SetTargetProperty(foldout, new PropertyPath(HeightProperty));
Storyboard.SetTargetName(winFoldout, mainWindow.Name);
Storyboard.SetTargetProperty(winFoldout, new PropertyPath(HeightProperty));
Jednom kada podesimo ciljani property i kontrolu, možemo da pozovemo animiaciju, međutim ja to još neću uraditi.
Kako će se ovaj prozor prikazivati i skrivati, želim da napravim "kontra animaciju" koja će sakriti prozor sa opcijama ukoliko je prikazan, na isti način na koji smo ga prikazali.
Za ovo će mi trebati jedan bool koji ćemo koristiti kao okidač svaki put kada pustimo animaciju.
Definišite bool na početku klase
bool optionsShown = false;
i vratite se nazad u ShowOptionsAnim funkciju, te nastavite odmah ispod poslednje linije.
:
if (!optionsShown)
{
foldout.To = 258;
winFoldout.To = 258;
fadeIn.From = 0;
fadeIn.To = 1;
storyBoard.Begin(this);
optionsShown = true;
}
else
{
foldout.To = 0;
winFoldout.To = 60;
fadeIn.From = 1;
fadeIn.To = 0;
storyBoard.Begin(this);
optionsShown = false;
}
Taj deo koda proverava vrednost optionsShown booleana i u skladu sa tome menja vrednosti animacija, pusta animaciju i menja vrednost boola za sledeću upotrebu.
Pokrenite prozor i videćete da animacija radi.
Ceo kod za ovu metodu :
void ShowOptionsAnim()
{
DoubleAnimation foldout = new DoubleAnimation(canvas1.Height, 258, new Duration(TimeSpan.FromSeconds(.25)));
DoubleAnimation fadeIn = new DoubleAnimation(0, 1, new Duration(TimeSpan.FromSeconds(.50)));
DoubleAnimation winFoldout = new DoubleAnimation(mainWindow.Height, 258, new Duration(TimeSpan.FromSeconds(.25)));
Storyboard storyBoard = new Storyboard();
storyBoard.Children.Add(foldout);
storyBoard.Children.Add(fadeIn);
storyBoard.Children.Add(winFoldout);
Storyboard.SetTargetName(foldout, canvas1.Name);
Storyboard.SetTargetName(fadeIn, canvas1.Name);
Storyboard.SetTargetName(winFoldout, mainWindow.Name);
Storyboard.SetTargetProperty(fadeIn, new PropertyPath(OpacityProperty));
Storyboard.SetTargetProperty(foldout, new PropertyPath(HeightProperty));
Storyboard.SetTargetProperty(winFoldout, new PropertyPath(HeightProperty));
if (!optionsShown)
{
foldout.To = 258;
winFoldout.To = 258;
fadeIn.From = 0;
fadeIn.To = 1;
storyBoard.Begin(this);
optionsShown = true;
}
else
{
foldout.To = 0;
winFoldout.To = 60;
fadeIn.From = 1;
fadeIn.To = 0;
storyBoard.Begin(this);
optionsShown = false;
}
}
Pre nego što krenemo na ozbiljnije poslove, sredićemo još dve sitnice :
0. Ukoliko već niste, imenujte glavni prozor aplikacije iz Document Outline kartice na "mainWindow"
1. Klik na topOffsetSlider > Properties > Events > Value changed dupli klik , da napravite handler za value changed
2. Upišite kod :
mainWindow.Top = dockTopOffsetSlider.Value;
3. Napravite handler i za leftOffsetSlider te kopirajte kod :
mainWindow.Left = dockLeftOffsetSlider.Value;
Oba handlera izgledaju ovako :
private void dockTopOffsetSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
mainWindow.Top = dockTopOffsetSlider.Value;
}
private void dockLeftOffsetSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
mainWindow.Left = dockLeftOffsetSlider.Value;
}
Većina interfejsa sada radi.
Klizači za širinu i visinu pravilno pomeraju grafički element.
Klizač za transparentnost pravilno radi.
Klizači za pomeranje prozora rade.
Rade pravilno i animacije opcija.
Sada imamo još dva posla :
1. Da napišemo funkciju koja će da primeni animacije na ikonicu koja se nalazi pod kursorom
2. Da napišemo funkciju koja će repozicionirati sve ikonice prema novim vrednostima sa klizača
#4.2 Funkcija za primenu animacije na ikonicu
Prvi tutorijal je imao kodiranu "animaciju" koja je samo povećavala ikonicu.
Kreiraću dve promenljive :
int iconMouseOverAnimID,
iconClickAnimID;
One će čuvati index selektovanog itema u izborniku animacija.
Napravite novi SelectionChanged handler za ComboBox :
private void cbAnimUpdate(object sender, SelectionChangedEventArgs e)
{
ComboBox thisObj = (ComboBox)e.Source;
if (thisObj.Name == "cbMouseOverAnim")
{
iconMouseOverAnimID = thisObj.SelectedIndex;
}
else if (thisObj.Name == "cbClickAnim")
{
iconClickAnimID = thisObj.SelectedIndex;
}
}
Bitno je da vam se izbornici zovu : "cbMouseOverAnim" i "cbClickAnim".
Sada želim da omogućim korisniku da izabere animaciju koja će se primeniti dinamično na ikonicu koja se nalazi ispod kursora.
Za ovo ćemo napisati posebnu funkciju 0 PlayIconAnimation koja će primiti tri parametra :
int animID - ID prema kom ćemo pozvati određenu animaciju
int animState - ID prema kom ćemo menjati razna stanja animacije - npr. možemo imati posebnu animaciju za mouse in, mouse leave itd. u sklopu jednog animID-a
RoutedEventArgs e - Samo ćemo proslediti informaciju sa MouseEnter i MouseLeave handlera
void PlayIconsAnimation(int animID, int animState, RoutedEventArgs e)
{
}
Prvo ću pokupiti image kontrolu preko GetIcon funkcije koju smo napisali u prošlom tutorijalu.
Zatim ću registrovati ime objekta privremeno, kako bi mogli da ga koristimo za primenu animacije i deklarisaću novi Storyboard kako bi ga koristili kasnije.
System.Windows.Controls.Image senderObj = GetIcon(e);
senderObj.Name = "tmpAnimObject";
RegisterName(senderObj.Name, senderObj);
Storyboard sb = new Storyboard();
Zatim ćemo proveriti šta je prosleđeno i prema tome ćemo pisati različite animacije.
switch (animID)
{
case 0: // Zoom In
break;
}
Prva animacija - Zoom In je radije jednostavna.
Kada miš pređe preko ikonice želim da je povećam, kada izađe da je smanjim.
Koristićemo sličnu animaciju onoj koju smo napisali za Opcije :
#4.2.1 Zoom In
case 0 : // Zoom In
DoubleAnimation increaseSizeW = new DoubleAnimation()
{
From = senderObj.Width,
To = 48,
Duration = new Duration(TimeSpan.FromSeconds(.25)),
};
DoubleAnimation increaseSizeH = new DoubleAnimation()
{
From = senderObj.Height,
To = 48,
Duration = new Duration(TimeSpan.FromSeconds(.25)),
};
if (animState == 2)
{
increaseSizeH.To = 32;
increaseSizeW.To = 32;
}
sb.Children.Add(increaseSizeW);
sb.Children.Add(increaseSizeH);
Storyboard.SetTargetName(increaseSizeW, "tmpAnimObject");
Storyboard.SetTargetName(increaseSizeH, "tmpAnimObject");
Storyboard.SetTargetProperty(increaseSizeH, new PropertyPath(HeightProperty));
Storyboard.SetTargetProperty(increaseSizeW, new PropertyPath(WidthProperty));
sb.Begin(this);
break;
Dakle, dve animacije za širinu i visinu unutar jednog Storyboarda.
Proveravamo animState takođe i u slučaju da je animState 2, menjamo vrednosti obe animacije kako bi dobili okrenutu animaciju.
#4.2.2 Swing
Swing animacija je drugačija. Koristićemo DoubleAnimation opet da bi pomerili vrednost ali ovog puta moramo da pristupimo RenderTransform-u kako bi dobili podatak o uglu Image kontrole.
Da bi uopšte pristupili toj vrednosti, moramo da dodelimo RotateTransform samoj kontroli.
case 1: // Swing anim
if (animState == 1) {
var rt2 = new RotateTransform();
senderObj.RenderTransform = rt2;
RotateTransform tempSP = senderObj.RenderTransform as RotateTransform;
Sada možemo da pristupimo vrednosti ugla i napravimo animacije prema njoj :
DoubleAnimation rotation = new DoubleAnimation()
{
From = tempSP.Angle,
To = 30,
Duration = new Duration(TimeSpan.FromSeconds(.50))
};
DoubleAnimation rotation1 = new DoubleAnimation()
{
From = 30,
To = 0,
Duration = new Duration(TimeSpan.FromSeconds(.50)),
};
Međutim sada nećemo koristiti storyboard, već ćemo pokrenuti animaciju na samom property-u
No pre nego što to uradim, želim da napravim handler za kraj animacije.
Ova animacija će pustiti prvi deo koji će je rotirati za 30 stepeni, čim se ta animacija završi pokrenućemo kontra animaciju. Za ovo nam treba handler koji će se aktivirati kada se prva animacija završi.
Želim da mi kod ostane u ovoj funkciji pa ću koristiti malu prečicu da definišem handler :
rotation.Completed += (o, s) =>
{
rotation1.From = tempSP.Angle;
senderObj.RenderTransform.BeginAnimation(RotateTransform.AngleProperty, rotation1);
};
Na kraju, pozvaću animaciju :
senderObj.RenderTransform.BeginAnimation(RotateTransform.AngleProperty, rotation);
}
break;
#4.2.3 Swing360
Swing 360 se zasniva na istom kodu samo što su stepeni različiti :
case 2: // Swing 360
if (animState == 1) {
var rt3 = new RotateTransform();
senderObj.RenderTransform = rt3;
RotateTransform tempSP = senderObj.RenderTransform as RotateTransform;
DoubleAnimation rotation360 = new DoubleAnimation()
{
From = tempSP.Angle,
To = 360,
Duration = new Duration(TimeSpan.FromSeconds(3)),
};
senderObj.RenderTransform.BeginAnimation(RotateTransform.AngleProperty, rotation360);
}
else if (animState == 2)
{
RotateTransform tempSP = senderObj.RenderTransform as RotateTransform;
DoubleAnimation rotation360 = new DoubleAnimation()
{
From = tempSP.Angle,
To = 360,
Duration = new Duration(TimeSpan.FromSeconds(3))
};
senderObj.RenderTransform.BeginAnimation(RotateTransform.AngleProperty, rotation360);
}
break;
#4.2.4 Glow
Na kraju, Glow animacija će zapravo dodeliti effect samoj slici - Drop Shadow.
Prvo ću definisati DropShadowEffect, zatim ću promeniti njegove vrednosti - poput boje, debljine senke i slično. Na kraju ću ga dodati kontroli. Kada kursor izađe sa ikonice samo ćemo obrisati sve efekte sa kontrole.
case 3: // Glow
if(animState == 1){
System.Windows.Media.Effects.DropShadowEffect tmpEffectShadow = new System.Windows.Media.Effects.DropShadowEffect();
System.Windows.Media.Color tmpColor = new System.Windows.Media.Color();
tmpColor.R = 255;
tmpColor.G = 255;
tmpColor.B = 255;
tmpEffectShadow.ShadowDepth = 2;
tmpEffectShadow.Color = tmpColor;
senderObj.Effect = tmpEffectShadow;
}
else if (animState ==2)
{
senderObj.Effect = null;
}
break;
Na kraju funkcije ću ukloniti naziv privremene kontrole i obrisati registrovano ime :
senderObj.Name = null;
UnregisterName("tmpAnimObject");
Cela funkcija :
void PlayIconsAnimation(int animID, int animState, RoutedEventArgs e)
{
System.Windows.Controls.Image senderObj = GetIcon(e);
senderObj.Name = "tmpAnimObject";
RegisterName(senderObj.Name, senderObj);
Storyboard sb = new Storyboard();
switch (animID)
{
#region ZoomIn
case 0 : // Zoom In
DoubleAnimation increaseSizeW = new DoubleAnimation()
{
From = senderObj.Width,
To = 48,
Duration = new Duration(TimeSpan.FromSeconds(.25)),
};
DoubleAnimation increaseSizeH = new DoubleAnimation()
{
From = senderObj.Height,
To = 48,
Duration = new Duration(TimeSpan.FromSeconds(.25)),
};
if (animState == 2)
{
increaseSizeH.To = 32;
increaseSizeW.To = 32;
}
sb.Children.Add(increaseSizeW);
sb.Children.Add(increaseSizeH);
Storyboard.SetTargetName(increaseSizeW, "tmpAnimObject");
Storyboard.SetTargetName(increaseSizeH, "tmpAnimObject");
Storyboard.SetTargetProperty(increaseSizeH, new PropertyPath(HeightProperty));
Storyboard.SetTargetProperty(increaseSizeW, new PropertyPath(WidthProperty));
sb.Begin(this);
break;
#endregion
#region Swing
case 1: // Swing anim
if (animState == 1) {
var rt2 = new RotateTransform();
senderObj.RenderTransform = rt2;
RotateTransform tempSP = senderObj.RenderTransform as RotateTransform;
DoubleAnimation rotation = new DoubleAnimation()
{
From = tempSP.Angle,
To = 30,
Duration = new Duration(TimeSpan.FromSeconds(.50))
};
DoubleAnimation rotation1 = new DoubleAnimation()
{
From = 30,
To = 0,
Duration = new Duration(TimeSpan.FromSeconds(.50)),
};
rotation.Completed += (o, s) =>
{
rotation1.From = tempSP.Angle;
senderObj.RenderTransform.BeginAnimation(RotateTransform.AngleProperty, rotation1);
};
senderObj.RenderTransform.BeginAnimation(RotateTransform.AngleProperty, rotation);
}
break;
#endregion
#region Swing360
case 2: // Swing 360
if (animState == 1) {
var rt3 = new RotateTransform();
senderObj.RenderTransform = rt3;
RotateTransform tempSP = senderObj.RenderTransform as RotateTransform;
DoubleAnimation rotation360 = new DoubleAnimation()
{
From = tempSP.Angle,
To = 360,
Duration = new Duration(TimeSpan.FromSeconds(3)),
};
senderObj.RenderTransform.BeginAnimation(RotateTransform.AngleProperty, rotation360);
}
else if (animState == 2)
{
RotateTransform tempSP = senderObj.RenderTransform as RotateTransform;
DoubleAnimation rotation360 = new DoubleAnimation()
{
From = tempSP.Angle,
To = 360,
Duration = new Duration(TimeSpan.FromSeconds(3))
};
senderObj.RenderTransform.BeginAnimation(RotateTransform.AngleProperty, rotation360);
}
break;
#endregion
#region Glow
case 3: // Glow
if(animState == 1){
System.Windows.Media.Effects.DropShadowEffect tmpEffectShadow = new System.Windows.Media.Effects.DropShadowEffect();
System.Windows.Media.Color tmpColor = new System.Windows.Media.Color();
tmpColor.R = 255;
tmpColor.G = 255;
tmpColor.B = 255;
tmpEffectShadow.ShadowDepth = 2;
tmpEffectShadow.Color = tmpColor;
senderObj.Effect = tmpEffectShadow;
}
else if (animState ==2)
{
senderObj.Effect = null;
}
break;
case 4:
if (animState == 1)
{
}
else
{
}
break;
}
#endregion
senderObj.Name = null;
UnregisterName("tmpAnimObject");
}
Na kraju, izmenićemo MouseOver i MouseLeave + iz prvog posta private void Icon_MouseEnter(object sender, MouseEventArgs e)
{
System.Windows.Controls.Image thisObject = GetIcon(e);
thisObject.Width += 20;
thisObject.Height += 20;
Grid.SetZIndex(thisObject, 99);
}
private void Icon_MouseLeave(object sender, MouseEventArgs e)
{
System.Windows.Controls.Image thisObject = GetIcon(e);
thisObject.Width -=20;
thisObject.Height -=20;
Grid.SetZIndex(thisObject,0);
}
tako da odgovaraju novom "sistemu" :
private void Icon_MouseEnter(object sender, MouseEventArgs e)
{
PlayIconsAnimation(iconMouseOverAnimID, 1, e);
System.Windows.Controls.Image thisObject = GetIcon(e);
Grid.SetZIndex(thisObject, 99);
}
private void Icon_MouseLeave(object sender, MouseEventArgs e)
{
System.Windows.Controls.Image thisObject = GetIcon(e);
Grid.SetZIndex(thisObject, 0);
PlayIconsAnimation(iconMouseOverAnimID, 2, e);
}
private void Image_MouseUp(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Right)
{
lastClicked = (System.Windows.Controls.Image)e.Source;
}
else
{
PlayIconsAnimation(iconClickAnimID, 0, e);
IconObjectClass ikona = iconObjects.Find(x => x.imgControl == e.Source);
Process.Start(ikona.iconPath);
}
}
#4.3 Funkcija za repozicioniranje ikonica
Ovo je ujedno i poslednja funkcija za ovu reviziju.
Ova funkcija će samo da repozicionira ikonice u odnosu na nove vrednosti veličine i offseta.
Primaće dva parametra : veličinu ikonicu, offset.
Proći će kroz listu naše klase i repozicionirati ikonice.
private void RepositionIcons(int iconSize, int iconOffset)
{
int counter = 0;
foreach (var s in iconObjects)
{
s.imgControl.Width = iconSize;
s.imgControl.Height = iconSize;
if (counter != 0 && iconObjects.Count >=1)
{
s.imgControl.Margin = new Thickness()
{
Left = iconObjects[counter-1].imgControl.Margin.Left + iconObjects[counter-1].imgControl.Width + iconOffset,// offset
Top = 0,
};
}
else
{
iconObjects[0].imgControl.Margin = new Thickness() { Left = 60, Top = 0 };
}
counter++;
}
}
Dakle, primenjujemo novu veličinu na svaku Image kontrolu, zatim računamo novu poziciju svake ikonice tako što na x poziciju prethodne dodajemo njenu širinu i offset, i pozicioniramo tu ikonicu.
Izuzetak je prva ikonica koja ima hardkodiranu vrednost - 60.
Funkciju želim da pozovem svaki put kada se vrednost klizača za veličinu ikonice ili piksela offseta, pa ću tako napraviti novi handler :
private void iconSizeSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (mainWindow.IsLoaded)
RepositionIcons(Convert.ToInt32(iconSizeSlider.Value), Convert.ToInt32(iconOffsetSlider.Value));
}
i povezati ga sa dva klizača levo.
Testirajte aplikaciju - sve radi kako treba.
|