2013. március 31., vasárnap

Wpf #3 MVVM

Az előző két bejegyzésben található példák segítségével egy alap Wpf adatkötés már felépíthető. A kód legszebb és végleges formájához még egy fontos lépés hiányzik.

Legyen adott egy osztály, amely csak adatokat tartalmaz, illetve a benne tárolt adatok kezelését felügyeli. Ez lesz a Model osztály. Az előzőekben bemutatott deklaráció ide kerül át. 



A Model osztályra csak és kizárólag egy helyen történik hivatkozás, ez pedig a ViewModel osztály. Minden Model osztály egymástól független, zárt egységet alkot. A ViewModel osztály több Model osztályra is hivatkozhat.
A ViewModel osztály ennek ismeretében az alábbi:



A fenti kód egy gyűjteményt hoz létre a Model osztályból. Továbbra is ez az osztály lesz a DataContext az XAML számára. Mivel az XAML - és annak mögöttes kódja - tartalmazza mindazt, amit látunk ezért a továbbiakban ezt View-nak nevezzük. Az XAML-hez tartozó kód nem változik az előzőekben leírtakhoz.



A View csak a ViewModel osztályra hivatkozik, a Model osztályról nem tartalmaz semmiféle referenciát.  Ezt az osztályhármat nevezk Model-View-ViewModel, röviden Mvvm mintának.
- A Model nem tartalmaz semmilyen referenciát egyik osztályra sem
- A ViewModel tartalmaz referenciát a Modelra, és tartalmazhat referenciát a View-ra
- A View tartalmaz referenciát a ViewModel-re

Az XAML kód az alábbi:


A XAML DataContext-je jelen pillanatban a _viewModel;
A ViewModel tartalmaz egy gyűjteményt: MyModelCollection. A listbox ebből szedi az adatokat (ItemsSource="{Binding MyModelCollection}")
Mindez automatikusan megtörténik.

A Listboxban található ItemTemplate leírja, hogy egy ListBox Item hogy nézzen ki. 
Jelenleg mindössze egy TextBlock-ot tartalmaz.
A ListBox a MyModelCollection gyűjteményből szedi az adatait, ami Model típusú.
A Model-nek van egy property-je: TextValue
Ez látható a TextBlock Text attribútumához kapcsolva (<TextBlock Text="{Binding TextValue}" Height="15"/>)

2013. március 29., péntek

Wpf #2 Új DataContext

Folytatva az előző blogban elkezdett adatkötést elég nyilvánvaló, hogy a DataContext viszonylag ritkán lesz a XAML leíráshoz tartozó mögöttes kód. Az új beállításhoz az eddig létrehozott adatokat egy új osztályban kell tárolni.



Az újonnan létrehozott osztálynak mindenképp meg kell valósítania az INotifyProperty interface-t. Az Interface megköveteli a PropertyChanged eseményt. A WPF ezen az eseményen keresztül kap értesítést, hogy egy tulajdonság értéke megváltozott.

Az eddigi publikus tulajdonság deklaráció is változtatást igényel. A privát adatmezőhöz tartozó publikus tulajdonság tartalmaz egy egyszerű get és set elérést. A set-ben látható értékadást mindenképpen követnie kell az előbb említett eseményt meghívó metódusnak. Az átadott paraméter pedig a publikus tulajdonság neve kell, hogy legyen

Mindezek után az eddig kód az alábbiakban változik:


A ViewModel létrhozása után a DataContext felveszi az értékét. Mivel az osztálynak van egy publikus tulajdonsága TextValue névvel, így az XAML-ben található adatkötés továbbra is megtalálja és megjeleníti.

Az XAML kód változatlan marad:

Wpf #1 adatkötés

A WPF használata során előbb vagy utóbb felmerül a kérdés, hogy az egyes adatok vizuális megjelenítéséhez nem-e létezik egyszerűbb módszer? Az adatkötés fogalma hosszú utat járt be mire a procedurális kódot felváltotta a deklaratív megvalósítás, és ez az egyik hatalmas erőssége a WPF-nek, amelyet azonban sajnos nagyon kevesen használnak ki. 

Kódból szerkesztve az alábbi pár sor könnyen kezelhetőnek tűnik és elég sokszor még profi fejlesztők is használják, leginkább a látszólagos gyorsasága miatt.
<TextBox Name="MyTextBox" Text=""/>
MyTextBox.Text = "tetszőleges szöveg";

A fenti kód egyik leggyengébb része, hogy amennyiben a TextBox szöveg részét a programunkban több helyen is változtatni szeretnék, a kódunk mindannyiszor ismételni kell. Ugyan a értékadó kód elhelyezhető egy metódusban, de a TextBoxok számának növelésével ez nagyon gyorsan kezelhetetlenné válik.

További nagy probléma, hogy amennyiben a TextBox tartalmát más szálból kell változtatni, úgy a Dispatchert kell igénybe venni vagy a Task befejeztével új task-ot kell indítani ami a a WPF saját szálljában fut le

 Lényegesen egyszerűbb az adatkötést igénybe venni és minden további teendőt a WPF-re hagyni.
A legegyszerűbb adatkötés mindössze pár sort igényel.

A mögöttes kód:
public partial class MainWindow : Window
{
    public int TextValue { get; set; }

    public MainWindow()
    {
        TextValue = 5;
        InitializeComponent();
        DataContext = this;
    }
}

Az XAML kód pedig:
<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBox Width="100" Height="20" Text="{Binding TextValue}"/>
    </Grid>
</Window>

Az adatkötés három fontos eleme:
- Egy publikus tulajdonság. Egy tagváltozó publikussá tétele nem elég, a WPF tulajdonságokon keresztül kommunikál. (Ez most jelen esetben a TextValue)
- Az adatforrás beállítása. (DataContext = this). A DataContext nem csak a dokumentum egészére,hanem bármely WPF elemre egyénileg beállítható. Pl. GridName.DataContext = this
- A kötés beállítása. (Text="{Binding TextValue}").

A TextValue property bármilyen típusú lehet, a WPF elvégzi a szükséges konvertálást, hogy a TextBox Text attributuma felvehesse az értékét. Nem számít, hogy az double, float vagy bool. Az aktuális értéke lesz látható a képernyőn.

Az adatkötéshez mindössze ezen alapok ismeretére van szükség. Használatával a kód szebb és jobban áttekinthetőbb, könnyebben nyomon követhetőbbé válik.