Urmatoarele controale sunt considerate “standard” in WPF:
System.Windows.Controls.Border
System.Windows.Controls.Button
System.Windows.Controls.CheckBox
System.Windows.Controls.ComboBox
System.Windows.Controls.Grid
System.Windows.Controls.Image
System.Windows.Controls.Label
System.Windows.Controls.ListBox
System.Windows.Controls.RadioButton
System.Windows.Controls.StackPanel
System.Windows.Control.TabControl
System.Windows.Controls.TextBox
System.Windows.Controls.Canvas
System.Windows.Controls.DockPanel
System.Windows.Controls.Frame
System.Windows.Controls.Menu
System.Windows.Controls.ToolBar
System.Windows.Controls.Primitives.StatusBar
System.Windows.Controls.DocumentViewer
System.Windows.Controls.FlowDocumentPageViewer
Despre unele dintre aceste controale am discutat deja, de exemplu Border. Voi reveni si asupra controalelor deja discutate completand acolo unde este cazul informatiile omise si folosindu-le in exemple care sa faciliteze si usureze intelegerea rolului lor. Aceste controale vor fi prezentate pe parcursul a cateva capitole: deoarece vreau sa fac prezentarea lor prin construirea unei aplicatii ordinea in care voi introduce si prezenta controalele nu este cea din lista ci o sa fie ordinea in care respectivele controale vor fi introduse in aplicatie; unele controae vor fi folosite nu pentru ca aduc un plus de functionalitate exemplului pe care il voi contrui, ci doar pentru a fi prezentate. Asupra tuturor controalelor voi reveni in momentul in care voi ajunge sa scriu despre DataBinding si despre template/style. Voi incerca sa introduc elemente noi progresiv, revenind la ceea ce deja am scris si imbunatatind sau completand informatia prezentata.
Aplicatia pe care o coi construi se va numi “image Browser” si va fi o aplicatie care va permite utilizatorului sa navigheze printre fisierele si folderele din calculator si sa afiseze imagini. Aplicatia va arata la finalul acestui capitol ca in imaginea de mai jos, urmand ca in cpitolul urmator sa ii completez functionalitatea. Inca nu vreau sa folosesc elemente despre care nu am scris, precum Binding sau stiluri. Vreau sa raman la nivel de prezentare a controalelor deocamdata.

Sa incepem:
In Visual Studio se creaza un nou proiect WPF. Eu am numit acest proiect IB (initialele de la Image Browser). Se deschide fisierul MainWindow.xaml si se fac urmatoarele modificari in cosul XAML: se schimba dimensiunea ferestrei si se da un titlu potrivit ferestrei. Dupa aceste modificari, codul XAML este:
<Window x:Class="IB.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Image Browser" Height="300" Width="550"> </Window>
De ce folosesc dimeniuni relativ mici pentru fereastra? Dintr-un motiv simplu: in editor, cand scriu cod xaml, prefer sa vad cat mai mult din continutul ferestrei al carei cod il sciru. In final voi modifica, probabil, dimensiunile initiale ale ferestrei la ceva mai potrivit aplicatiei (probabil 1000×800);
Asa cum am procedat si pana acum, fiecare panel va di colorat diferit pentru a fi mai usor sa vedem unde apare in fereastra repsectivul panel. La fel voi proceda si pentru diverse alte controale daca voi considera ca prin colorare se vede mai bine pozitionarea lor in fereastra. Voi incerca sa nu folosesc culori prea tipatare astfel incat sa nu iasa o fereastra papagal!
Inainte de a incepe sa scriu cod as vrea sa descriu ceea ce vreau sa obtin. Vreau o aplicatie care sa imi permita sa navighez printre fisiere si foldere si care sa imi afiseze ori toate imaginile din folderul selectat, ori o imagine specifica. Pare simplu!
Pentru asta voi construi o fereastra cu urmatorul schelet: un DockPanel este continutul ferestrei. El va gazdui un numar de 4 Panels (in aceasta etapa 2 StackPanel si 2 Grid). Fiecare dintre aceste Panel-uri vor avea rolul de a prezenta diversele zone din aplicatie: zona de afisare a imaginilor, zona de navigare, o zona de tip meniu + toolbar si o zona de tip status bar (info). S-ar putea ca pe parcurs sa apara modificari – nu am toata aplicatia scrisa in momentul acesta si e posibil ca pe parcurs sa schimb pe ici, pe colo… in punctle esentiale!
Codul XAML pana in aceasta etapa este urmatorul:
<Window x:Class="IB.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Image Browser" Height="300" Width="550"> <DockPanel LastChildFill="True"> <StackPanel DockPanel.Dock="Top" Background="LightGoldenrodYellow" Height="30" x:Name="pnlMenu" Orientation="Horizontal"> </StackPanel> <StackPanel DockPanel.Dock="Bottom" Height="23" Background="Bisque" x:Name="pnlButtom"> </StackPanel> <Grid DockPanel.Dock="Left" Width="150" Background="AliceBlue" x:Name="pnlLeft"></Grid> <Grid Background="Beige"></Grid> <DockPanel> </Window>
La rulare vom vedea urmatoarea fereastra (Am adaugat numere pentru a vedea mai clar regiunile ferestrei – aceste numere nu sunt desenate prin intermediul XAML):

Dupa cum se vede, am dat si nume catorva containere pentru a-mi fi usor sa le identific cand voi scrie metode care sa faca aplicatia functionala.
Pentru inceput ma voi ocupa de partea de “browse” in sistemul de fisiere. Pentru asta voi folosi containerul cu numele pnlLeft, conatainer care va ocupa partea din stanga a ferestrei. Codul XAML pentru asta este prezentat in continuare:
<Grid DockPanel.Dock="Left" Width="150" Background="AliceBlue" x:Name="pnlLeft">
<Border CornerRadius="4" BorderBrush="#621E90FF" BorderThickness="2" Margin="2" Padding="2">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="21"></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition Height="21"></RowDefinition>
</Grid.RowDefinitions>
<ComboBox Grid.Row="0" x:Name="cboDrive" SelectionChanged="cboDrive_SelectionChanged">
</ComboBox>
<ListView x:Name="lstFiles" Grid.Row="1" MouseDoubleClick="lstFiles_MouseDoubleClick" KeyDown="lstFiles_KeyDown" SelectionMode="Single">
</ListView>
<StackPanel Grid.Row="2" Orientation="Horizontal">
<CheckBox Margin="4" Checked="CheckBox_Checked" Unchecked="CheckBox_Checked" IsChecked="True">Jpg</CheckBox>
<CheckBox Margin="4" Checked="CheckBox_Checked" Unchecked="CheckBox_Checked" IsChecked="True">Gif</CheckBox>
<CheckBox Margin="4" Checked="CheckBox_Checked" Unchecked="CheckBox_Checked" IsChecked="True">Png</CheckBox>
</StackPanel>
</Grid>
</Border>
</Grid>
Explicatii: Codul de mai sus descrie (realizeaza) panoul din stanga, cel in care voi permite navigarea in sistemul de fisiere. Acest panou este de tip Grid – am folosit Grid pentru ca am nevoie de un container care sa imi permita intinderea continutului pentru intregului spatiu disponibil. Continutul Grid-ului, Border, va avea dimensiunea (aproximativ) egala cu cea a Grid-ului. Am preferat sa folosesc un Broder pentru a diferentia zonele ferestrei – incadrarea fiecareia in propriul contur le face oarecum distincte iar separarea mai uor de inteles. Acest contur (Border) are setate urmatoarele atribute: CornerRadius=”4″ BorderBrush=”#621E90FF” BorderThickness=”2″ Margin=”2″ Padding=”2″, care reprezinta: raza cloturilor – colturile nu sunt o intersectie de doua linii perpendiculare cu sunt rotunjite, culoarea liniei de contur, grosimea liniei de contur (BorderThickness), spatiul dintre contur si elementele inconjuratoare (in cazul nostru elementul parinte, Grid), spatiul dintre contur si continutul propriu (Padding).
Elementul Border contine un nou Grid in care am definit 3 randuri (GridRow), primul si ultimul rand au specificat parametrul Height – vreau sa fie de inaltime fixa. Cel din mijloc va ocupa tot spatiul ramas liber. In randul de sus voi pune un control de tip ComboBox, care va afisa unitatile de disk existente in calculator. In randul de jos voi pune cateva CheckBox-uri cu ajutorul carora utilizatorul poate alege ce tip de fisiere imagine sunt afisate – aceste CheckBox-uri nu sunt chiar utile aplicatiei, as fi putut sa incars in mod prestabilit toate tipurile de imagine, ci au doar rolul de a exemplifica folosirea acestui tip de control: CheckBox.
A se observa ca am folosit, pentru a stabili fiecarui control locatia, proprietatea Grid.Row (de tip dependency property).
Ultima bucatica neocupata e cea din mijloc. Aici voi gazdui un ListView care va fi populat cu numele fisierelor si folderelor printre care utilizatorul poate sa se deplaseze.
O noua remarca: unele dintre controale au nume pentru a fi usor de gasit in partea de “code behind”.
Deocamdata ma opresc aici cu XAML-ul, si vreau sa scriu primele metode care sa populeze UI-ul realizat pana acum cu date. Voi incepe cu o metoda care sa imi populeze ComboBox-ul cu unitatile de disk aflate in calculatorul pe care rulez. Aceasta se scrie asa:
private void PopulateDriveCbo()
{
DriveInfo[] drives = DriveInfo.GetDrives();
for (int i = 0; i < drives.Length; i++)
{
if (drives[i].IsReady)
cboDrive.Items.Add(drives[i]); //adaoga in lista unitatea de disk.
}
cboDrive.SelectedIndex = 0; //selectez prima unitate de disk.
// Aceasta declanseaza si evenimentul SelectionChanged="cboDrive_SelectionChanged" care va incarca fisierele/folderele
}
Evenimentul “SelectionChanged” executa urmatoarea metoda:
private void cboDrive_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
}
Voi scrie mai tarziu corpul acestei metode. Pentru a compila si rula aplicatia mai avem nevoie de inca niste motode, pentru tratarea evenimentelor legate de lista de fisiere si de comboBox-urile din ultimul rand. Aceste metode su urmatoarea semnatura:
private void lstFiles_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
}
private void lstFiles_KeyDown(object sender, KeyEventArgs e)
{
}
private void CheckBox_Checked(object sender, RoutedEventArgs e)
{
}
In acest moment aplicatia poate fi compilata. Pentru a vedea lista de unitati de disk incarcata in comboBox ar trebui modificat constructorul ferestrei in modul urmator:
public MainWindow()
{
InitializeComponent();
PopulateDriveCbo();
}
Linia evidentiata e linia nou adaugata. Daca totul a mers bine ar trebui sa obtinem o imagine asemanatoare cu imaginea urmatoare:

Voi continua construirea UI. As vrea, in partea de jos a ferestrei, un Label care sa imi poata arata ca un fel de status bar, locatia unde sunt acum. Pentru a realiza asta voi scrie urmatorul cod XAML:
<StackPanel DockPanel.Dock="Bottom" Height="23" Background="Bisque" x:Name="pnlButtom">
<Label x:Name="lblStatus" />
</StackPanel>
Acum am un Label (care are numele lblStatus) unde pot sa afisez diverse mesaje in functie de comportamentul utilizatorului. Pot sa afisez acolo, de exemplu, calea completa spre folderul/imaginea incarcat/a. Voi realiza asta imediat, dupa ce voi completa si codul XAML pentru partea principala a ferestrei, respectiv locul unde imaginile vor fi afisate.
<Grid Background="Beige">
<Border CornerRadius="4" BorderBrush="#621E90FF" BorderThickness="2" Margin="2" Padding="2">
<Grid>
<Image Stretch="Uniform" x:Name="imgImage" StretchDirection="DownOnly" Visibility="Collapsed" />
<ScrollViewer>
<WrapPanel x:Name="grdImages" />
</ScrollViewer>
</Grid>
</Border>
</Grid>
Asa cum am procesat si in panoul din stanga, acestui panou central i-am desenat un contur, cu aceiasi parametrii (linie, culoare, margini etc). In interiorul conturului voi gazdui un Grid, care va avea, la randul lui, doua controale a caror vizibilitate va alterna. Acestea sunt un introl de tip Image, unde vom afisa imaginea selectata in ListBox-ul din stanga, si un control de tip ScrollViewer care contine un WrapPanel unde voi afisa imaginile intregului folder in cazul in care obiectul din lista selectat este un folder.
In urmatoarea linie:
<Image Stretch="Uniform" x:Name="imgImage" StretchDirection="DownOnly" Visibility="Collapsed" />
avem cateva atribute interesante (sau cel putin care nu au mai fost intalnite pana acum): Stretch=”Uniform” – va redimensiona imaginea continuta asfel incat ea sa incapa in suprafata vizibila, pastrand proportia originala a imaginii. Alte posibile valori pentru acest atribut sunt: None, Fill, UniformToFill. StretchDirection este un alt atribut nou. Acesta va stabili directia in care se face redimensionarea, valoarea curenta fiind DownOnly – ceea ce inseamna ca imaginea va fi redimensionata numai daca redimensionarea insemna micsorarea ei. Alte valori posibile sunt UpOnly sau Both. Ultima portiune de cod XAML este cea care defineste containerul unde vor fi gazduite imaginile folderului selectat:
<ScrollViewer>
<WrapPanel x:Name="grdImages" />
</ScrollViewer>
Am adaugat un element ScrollViewer deoarece vreau, in momentul in care sunt mai multe imagini de prezentat decat ar incapea in suprafata vizibila, sa am o bara de derulare care sa imi permita sa derulez pentru a vedea toate imaginile.
In momentul acesta proiectul nu poate fi compilat cu succes deoarece nu am scris metodede de tratare a evenimentelor. Voi incheia acest capitol fara a scrie continutul acestor metode, ramanand ca acest lucru sa fie facut in partea a doua. Voi da acum numai semnatura metodelor (sau metoda fara corp) pentru a ajunge la o aplicatie care poate fi compilata.
private void cboDrive_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
}
private void lstFiles_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
}
private void lstFiles_KeyDown(object sender, KeyEventArgs e)
{
}
private void CheckBox_Checked(object sender, RoutedEventArgs e)
{
}
In incheiere voi da o tema: Sa se scrie codul XAML care sa deseneze o fereastra de tipul ferestrei Run din windows (numai XAML, nu si codul care se executa in spatele UI-ului):

In locul desenului (imaginii de deasupra label-ului cu textul Open) se va desena un dreptunghi. Primul care trimite pe comentariu sau pe email zeltera[at][yahoo][punct]com rezolvarea temei (daca doreste) va fi trecut la lista de contribuitori ai acestui tutorial.
Multumesc.
Bogdan says:
Salutare,
La doi ani distanta raspund eu cu o incercare.
Nu am stiut sa-i pun butonul de Help Request.
Nu am reusit nici sa-i scriu textul pe 2 randuri.
Type the name of a program, folder, document, or Internet resource, and Windows will open it for you.
Open:
Open
Cancel
Browse
Sugestii?