Az eddig megismertek felhasználásával már számos Model osztályt fel lehet építeni, ám rengeteg olyan WPF tulajdonság van, amit nem biztos, hogy célszerű az osztályban ugyanolyan típusúra deklarálni.
A legegyszerűbb talán egy adott elem Visibility tulajdonsága.
pl.: <Rectangle Visibility="Hidden"/>
A Visibility 3 értéket vehet fel: Hidden, Visible, Collapsed
Amennyiben kódból kell az értékét változtatni úgy az alábbiak szerint kell eljárni:
MyRectangle.Visibility = Visibility.Hidden;
A Most következő példában a "Collapsed" érték mellőzésre kerül. A láthatóságot egy bool tulajdonság segítségével lehet szabályozni. (true=Visible, false=Hidden)
Ehhez egy nagyon egyszerű Model osztályra lesz szükség:
class Model : INotifyPropertyChanged { private bool _rectVisibility; public bool RectVisibility { get { return _rectVisibility; } set { _rectVisibility = value; OnPropertyChanged("RectVisibility"); } } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } // --------------------------------------------------------------------- public Model(bool visibility) { RectVisibility = visibility; } }
A Láthatóságot a konstruktoron keresztül célszerű alaphelyzetbe hozni.
A hozzá tartozó ViewModel is pont ugyanennyire egyszerű
class ViewModel : INotifyPropertyChanged { private Model _myModel; public Model MyModel { get { return _myModel; } set { _myModel = value; OnPropertyChanged("MyModel"); } } public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } public ViewModel() { MyModel = new Model(true); } }
A View kód:
public partial class MainWindow : Window { private readonly ViewModel _viewModel; public MainWindow() { InitializeComponent(); _viewModel = new ViewModel(); DataContext = _viewModel; } }
Legvégül az alap XAML
<Window x:Class="Wpf06_Converter.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> <StackPanel Orientation="Horizontal" Height="30"> <Rectangle Width="100" Height="30" Fill="Red"/> </StackPanel> </Grid> </Window>
Az egyenlőre egyetlen darab piros négyzet kirajzolására szolágló kód hamarosan kibővül számos új elemmel, amelyek mind-mind a négyzet láthatóságát fogják szabályozni.
Jelen pillanatban van egy Model osztály, amelynek egyetlen bool típusú publikus tulajdonsága van (RectVisibility). Ezt kell valamilyen módon összepárosítani a Rectangle Visibility tulajdonságával.
Ahhoz, hogy mindezt elérjük, egy konverter osztályra lesz szükség. Ez az osztályt egy külön DLL-ben lesz elhelyezve (ez nem szükséges).
Hozzunk létre új Class Library project-et. A neve legyen: Converter.
Töröld ki az automatikusan létrehozott class file-t, és adj a projekt-hez egy új osztályt VisibilityConverter néven.
A Library-hez az alábbi referenciákat kell hozzáadni (jobb klikk a References lenyíló menün, Add refference): PresentationCore, PresentationFrameWork
Az osztály kódja:
namespace Converter { public class VisibilityConverter : IValueConverter { // ** Model konvertálása az UI felé public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if ((bool)value) return Visibility.Visible; else return Visibility.Hidden; } // ** UI konvertálása a Model felé public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { return value; } } }
A fenti namespace és osztály elnevezések pontosan egyezzenek! Természetesen a későbbiekben tetszőleges elnevezést lehet használni, de a példa futtatásához ez most nélkülözhetetlen.
Mivel az osztály másik szerelvényben található ezért az osztály kötelezően publikus, hogy a későbbiekben is elérhető maradjon.
Az osztály használatához szükség van az IValueConverter interface implementálására. Ehhez szükség van a System.Windows.Data namespace-re.
using System.Windows.Data;
Az interface két metódus meglétét követeli meg. A tényleges konvertálás ezeken keresztül történik.
public object Convert
public object ConvertBack
A Convert metódus konvertál minden a Model osztályban deklarált tulajdonságot olyan formára, ahogy azt az UI elvárja.
Jelen esetben egy bool tulajdonság a bement, és az alapján dől el a visszatérési érték, amely már feldolgozható a Rectangle Visibility tulajdonsága számára.
A WPF projekthez referenciaként hozzá kell adni az előbb létrehozott Converter szerelvényt.
A hozzáadás után érdemes egy fordítást végezni a kódon, mivel a Wpf számtalanszor nem találja meg elsőre a beimportált elemeket.
Az XAML kód pedig az alábbiak szerint változik.
Egy új xml namespace deklarációval a konvertert deklarálni kell.
xmlns:converter="clr-namespace:Converter;assembly=Converter"
Ezért volt fontos, hogy az namespace és osztály nevek egyezzenek a példában leírtakkal.
Ez a sor megmondja, hogy melyik DLL és melyik namespace kell a kód működéséhez a továbbiakban.
Következő lépésként a Resource-ban definiálni kell a konvertert.
<Grid.Resources>
<converter:VisibilityConverter x:Key="RectVisibilityConverter"/>
<converter:VisibilityConverter x:Key="RectVisibilityConverter"/>
</Grid.Resources>
A converter(az elöbb lett definiálva) a Converter namespace alatt található VisibilityConverter osztályra mutat, az x:Key pedig egy tetszőlegesen elnevezett hivatkozási nevet definiál.
A Rectangle az alábbiak szerint változik.
<Rectangle Width="100" Height="30" Fill="Red" Visibility="{Binding MyModel.RectVisibility, Mode=OneWay, Converter={StaticResource RectVisibilityConverter}}"/>
Az adatkapcsolás a Model osztály RectVisibility tulajdonságát használja.
A Mode=OneWay utasítja a keretrendszert, hogy az adatkapcsolás csak egyirányú, azaz csak a Model osztály irányából a Rectangle felé. (az ezt megelőzően egy textboxba írt szöveg tartalmát a framework bemásolta a Model osztály tulajdonságába)
A Converter a Grid.Resource-ban definiált konverterre mutat, ami a bool értéket alakítja át olyan típusra, amit a Rectangle Visibility tulajdonsága értelmezni tud.
Az XAML jelenleg itt tart:
<Window x:Class="Wpf06_Converter.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:converter="clr-namespace:Converter;assembly=Converter" Title="MainWindow" Height="350" Width="525"> <Grid> <Grid.Resources> <converter:VisibilityConverter x:Key="RectVisibilityConverter"/> </Grid.Resources> <StackPanel Orientation="Horizontal" Height="30"> <Rectangle Width="100" Height="30" Fill="Red" Visibility="{Binding MyModel.RectVisibility, Mode=OneWay, Converter={StaticResource RectVisibilityConverter}}"/> </StackPanel> </Grid> </Window>
Lefordítva és lefuttatva a négyzet továbbra is látható. A ViewModel osztály konstruktorában egyetlen sor található: MyModel = new Model(true);
Amennyiben a true értékét false-ra cseréljük a program futtatásakor a négyzet láthatatlan lesz.
Egészítsük ki a XAML kódot egy CheckBox-al.
<CheckBox Content="Rect visibility" IsChecked="{Binding MyModel.RectVisibility, Mode=TwoWay}"/>
Mivel az IsChecked bool típust vár ezért nincs szükség konverter használatára.
A Mode=TwoWay (default) miatt a CheckBox változtatásával a Model osztály RectVisibility tulajdonsága is változik.
<Window x:Class="Wpf06_Converter.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:converter="clr-namespace:Converter;assembly=Converter" Title="MainWindow" Height="350" Width="525"> <Grid> <Grid.Resources> <converter:VisibilityConverter x:Key="RectVisibilityConverter"/> </Grid.Resources> <StackPanel Orientation="Horizontal" Height="30"> <Rectangle Width="100" Height="30" Fill="Red" Visibility="{Binding MyModel.RectVisibility, Mode=OneWay, Converter={StaticResource RectVisibilityConverter}}"/> <CheckBox Content="Rect visibility" IsChecked="{Binding MyModel.RectVisibility, Mode=TwoWay}"/> </StackPanel> </Grid> </Window>
Az eddig megismertek segítségével tetszőleges tulajdonságot lehet bármilyen más típusra alakítani.
A következőkben a User Interface-n történt változtatást fogjuk a Model osztály számára feldolgozni.
A VisibilityConverter osztály ConvertBack metódusát az alábbiak szerint kell megváltoztatni.
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { var sValue = value as string; if (sValue != null) { if (sValue == "igen") return true; if (sValue == "nem") return false; } return value; }
Az XAML-ben pedig egy TextBox-ot kell elhelyezni, amely bemenetként az igen vagy a nem szavakat várja.
<TextBox Text="{Binding MyModel.RectVisibility, Mode=OneWayToSource, Converter={StaticResource RectVisibilityConverter}}" Width="50"/>
A TextBox szintén a Model osztály RectVisibility tulajdonságát használja adatkötésre.
A Mode=OneWayToSource beállítással elérhető, hogy a TextBox tartalmának változásával a Model osztály RectVisibility tulajdonsága megváltozzon, de ha a tulajdonság bárhol máshol megváltozna, azt a TextBox nem követi.
Fontos, hogy ez a VisulStudio szerkesztőjében NullReferenceException-t okozhat, de lefuttatva működni fog. Ha zavaró a hibaüzenet, a beállítás nyugodtan törlésre kerülhet.
A TextBox konvertálásra ugyanazt az osztályt használja mint a Rectangle, csak most visszafelé kell konvertálni.
A végleges XAML kód:
<Window x:Class="Wpf06_Converter.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:converter="clr-namespace:Converter;assembly=Converter" Title="MainWindow" Height="350" Width="525"> <Grid> <Grid.Resources> <converter:VisibilityConverter x:Key="RectVisibilityConverter"/> </Grid.Resources> <StackPanel Orientation="Horizontal" Height="30"> <Rectangle Width="100" Height="30" Fill="Red" Visibility="{Binding MyModel.RectVisibility, Mode=OneWay, Converter={StaticResource RectVisibilityConverter}}"/> <CheckBox Content="Rect visibility" IsChecked="{Binding MyModel.RectVisibility, Mode=TwoWay}"/> <TextBlock Margin="20,0,0,0" Text="Látható(ird be igen vagy nem):"/> <TextBox Text="{Binding MyModel.RectVisibility, Mode=OneWayToSource, Converter={StaticResource RectVisibilityConverter}}" Width="50"/> <Button Content="click"/> </StackPanel> </Grid> </Window>
A szövegmező után elhelyezett gomb azért kell, mert a tulajdonság frissítése csak a fókusz elvesztése után történik meg.
Ebben a példában egyetlen tulajdonságot 3 különböző elemhez kapcsoltunk hozzá különböző módon, követve, hogy az adatkötés ténylegesen csak abba az irányba történjen,amelyre feltétlenül szükség van.
A koverter természetesen számos más célra is felhasználható, de a lényege ugyanaz marad. Két tulajdonság között értelmezhető kapcsolat keletkezzen.
Nincsenek megjegyzések:
Megjegyzés küldése