János's profileJános JankaPhotosBlogListsMore ![]() | Help |
|
May 27 WPF - Model-View-ViewModel bevezetőA Microsoft azért adta ki az MVVM Toolkit-et, hogy egy egyszerűbb és jobban áttekinthető megoldást nyújtson minden WPF fejlesztő számára. Ez annyira igaz, hogy elvileg része lesz az eljövendő RTM verziónak, illetve a WPF 4.0 parancsrendszerét is megreformálják pont emiatt. Voltak páran akik megkértek mostanában, hogy meséljek erről az MVVM-ről néhány szót. Mivel ez a téma elég szerteágazó és kisezer megközelítés létezik, hozzávetőlegesen megpróbálom bemutatni a Microsoft-os WPF MVVM elképzelést, mely pont az egyszerűséget és könnyen érthetőséget hivatott megcélozni. Először is a lényege az MVVM-nek, akárcsak az ősének az MVC-nek, hogy szeparálja a kód logikát a felhasználói felülettől. Egy jól tervezett alkalmazás ismérve a könnyű fejleszthetőség, tesztelhetőség, illetve fenntarthatóság. Model ViewModel A sorrend nagyon fontos !
Haladjunk sorjában: Először is készítünk egy adatbázist. Ez egy egyszerű kis adatbázis, mindössze 1 táblát tartalmaz (Products) néhány mezővel, mint Name, Description, Price. Néhány tesztadatot érdemes felvenni bele. Jön a model réteg. Itt készítünk egy ProductData osztályt, ami a meglévő EF Product entitás osztályunkat fogja becsomagolni, illetve kibővíti azt más tulajdonságokkal. Ebbe a rétegbe visszük le a validációs logikát is. Minden adatot reprezentáló model osztály implementálja az INotifyPropertyChanged, illetve IDataErrorInfo interfészeket. Jelen esetben én ezt leegyszerűsítettem egy ObservableObject és ValidableObject segítségével. Ugyanitt kerül implementálásra a ProductBook osztály. Ez reprezentál egy terméklista manager osztályt. Ő már maga tárolja a becsomagolt termék objektumokat, de semmilyen állapotadatot nem tárol, mint pl. ki van kijelölve. Direkt NotificationCollection-be vannak téve a termék adatok, hogy ne függjön a kód a WPF-től. Ebbe az osztályba kerülnek megvalósításra az alapvető műveletek is, mint pl. új termékadat felvétele, egy termékadat törlése, illetve a módosítások mentése. ViewModel Itt alapvetően két darab ViewModel osztály létezik, az egyik a MainViewModel, a másik pedig a ProductBookViewModel. Készíthetnénk külön ViewModel osztályt magának a ProductData-nak is, de jelen esetben ez szükségtelen. Az annyit tenne mindössze, hogy magát a ProductData-t is becsomagolnánk egy ProductDataViewModel osztályba és ezt használnánk a ProductBookViewModel-ben, de ez nem szükséges, mivel a validáció a modelben van és nincs szükség bővíteni vizuális állapotinformációkkal ezt. Mint láthatjuk a kódban, a ProductBookViewModel konstruktora példányosítja a model (ProductBook) manager osztályt és feliratkozik annak a kollekciójának CollectionChanged eseményére, hogy diszpécselje a változásokat a model listájából a ViewModel ObservableCollection-be. Tehát magyarul szinkronban tartjuk a modellünk kollekcióját a view modellünk kollekciójával, ami már egy WPF specifikus kollekció (ObservableCollection), ugyanis ezt fogjuk bekötni a view objektumaink lista vezérlőibe, pontosabban ezeknek egy nézetét (CollectionViewSource). Tehát most ott tartunk, hogy a ViewModel-ünknek van egy példánya a hozzá tartozó modelből: röviden a ProductBookViewModel objektumunk ismeri a ProductBook model objektumot. Következő lépésben minden commandot kipakolunk ide. Azt, hogy épp ki van kijelölve a SelectedProductData tulajdonság határozza meg a ViewModel-be. Tehát a törlés parancsunk például így néz ki: View Ha megnézzük a ProductBookView.xaml fájlt máris megértünk mindent. Látható, hogy a lista control be van kötve a view model osztályunk megfelelő tulajdonságaiba. A kötésben az adatforrás ilyenkor a legközelebbi ráeső DataContext, mely jelen esetben a UserControl-unk DataContext-je lesz, ami ugye nem más lesz, mint egy ViewModel objektum. <ContentPresenter _logics = new Dictionary<LogicType, LogicTypePair>(); May 19 WPF konverterekKészítettem egy gyors módszert a konverterek használatához. Először is, ugye ahhoz, hogy konvertereket tudjunk használni mindig fel kell vennünk őket az erőforrások közé, majd StaticResource segítségével bekötni őket. Ezzel csak az a probléma, hogy egy idő után fárasztóvá válik a dolog. Tehát, az első akadályozó tényezőre a megoldás XAML markup extension-ök használata. Csinálunk először is egy generikus bázis osztályt, ami az összes konverterünk őse lesz markup támogatással: using System; using System.Globalization; using System.Windows.Markup; using System.Windows.Data; namespace VVMF.Core.WPF.Converters { [MarkupExtensionReturnType(typeof(IValueConverter))] public abstract class ConverterMarkupExtension<T> : MarkupExtension, IValueConverter where T: class, IValueConverter, new() { private static T _converter = null; public override object ProvideValue(IServiceProvider serviceProvider) { if (_converter == null) _converter = new T(); return _converter; } #region IValueConverter Members public abstract object Convert(object value, Type targetType, object parameter, CultureInfo culture); public abstract object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture); #endregion } } Ezt követően azért, hogy az értéktípusokat/nullázható típusokat is könnyedén tudjuk kezelni, készítettem egy egyszerű kis segédosztályt: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace VVMF.Core.WPF.Converters { public static class ConverterHelper { public static TValueType GetValue<TValueType>( object obj, TValueType defaultValue) where TValueType : struct { TValueType value = defaultValue; if (obj is TValueType) { value = (TValueType)obj; } else if (obj is TValueType?) { var nullable = (TValueType?)obj; value = nullable ?? defaultValue; } return value; } public static TValueType GetValue<TValueType>( object obj) where TValueType : struct { return GetValue<TValueType>(obj, default(TValueType)); } } } Majd tesztnek készítünk egy egyszerű kis szám inkrementáló konvertert: using System; using System.Windows.Data; using System.Globalization; namespace VVMF.Core.WPF.Converters { [ValueConversion(typeof(int), typeof(int))] public class IntegerIncrementerConverter : ConverterMarkupExtension<IntegerIncrementerConverter> { public override object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return ConverterHelper.GetValue<int>(value) + ConverterHelper.GetValue<int>(parameter, 1); } public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { return ConverterHelper.GetValue<int>(value) - ConverterHelper.GetValue<int>(parameter, 1); } } } Ezután már XAML-be mindössze ennyit kell írnunk: <TextBlock Grid.Column="0" Text="{Binding SelectedIndex, Converter={coreconverters:IntegerIncrementerConverter}, Ehelyett: <UserControl.Resources> <coreconverters:IntegerIncrementerConverter <TextBlock Grid.Column="0" Text="{Binding SelectedIndex, Converter={StaticResource IntegerIncrementerConverter}, ElementName=dgOrganizations}" Margin="5"/> May 12 Delphi Prism májusi releaseA májusi kiadás már megpróbál bevezetni egy-két újdonságot még a .NET 4.0 és C# 4.0 előtt. Az új feature-k részletes leírása itt megtalálható. Ezen a listán szerepel a volatile fieldek, a generic type variance–ok, illetve újabb LINQ operátorok támogatása is, mint pl. skip, while, take és take while. May 08 WPF IntelliSense: hol volt, hol nem voltEgyes CTP-k telepítése után érhet bennünket meglepetés, mint pl. eltűnik a XAML IntelliSense a VS-ből. Mondanom sem kell, hogy nem éppen kellemes meglepetés volt a dolog. Mondom a megoldást máris:
May 07 Windows® API Code Pack for Microsoft® .NET Framework (v0.85)Érkeznek az utángyártott managelt könyvtárak a Windows 7 újdonságainak kihasználáshoz is többek között. Na meg persze a Vista olyan szolgáltatásaihoz is, melyekhez nem voltak managelt könyvtárak (lsd. DWM). Úgy látom, hogy mostanában ez a divat, akárcsak a Sync Framework esetében (minden megy natív kódba és arra húznak még egy managelt réteget). Letöltés itt. |
|
|