İlkay İlknur

just a developer...

C# 5.0 Windows Runtime Desteği ve Windows Runtime Componentleri Geliştirme

Windows 8 ile beraber gelen WinRT altyapisi üzerinde bulunan en güzel özelliklerden biri de hiç süphesiz ki üzerinde pek çok programlama diliyle uygulama gelistirilebilmesi. Örnegin C, C++, C# veya VB bilen bir developer arayüz tarafinda da XAML kullanarak uygulamasini gelistirebilirken ayni zamanda Javascript ve HTML bilen bir front-end developer da artik Windows 8 üzerinde uygulama gelistirebilmekte. Peki ayni uygulama içerisinde bu dillerden ikisini birden kullanabiliyor muyuz ? sorusu eminim bir çogumuzun aklina geliyordur. :) Örnek olarak, bir Windows 8 uygulamasi gelistirirken data katmani bir C# developer tarafindan gerçeklestirilse ve arayüz kismi da javascript ve HTML ile yapilsa ortaya efsanevi senaryolar çikabilir :)  Peki bunu yapmak mümkün mü ? Evet mümkün :) Simdi gelin bunu nasil gerçeklestirebilecegimizi inceleyelim :)

WinRT (Windows Runtime) Components

Normalde uygulamalarimizi gelistirirken gerek baska uygulamalarin kullanmasi amaciyla gerekse kendi uygulamamiz içerisinde bir takim kavramlari dogrudan uygulama içerisine gömmek yerine yazdigimiz kodlari yeniden kullanabilmek amaciyla class libraryleri kullanmaktayiz. Windows Store uygulamalari tarafina baktigimizda ise bahsettigimiz senaryolarda kullanmak üzere adresimiz yine class library olmakta. Ancak Windows Store tarafinda yazmis oldugunuz class library'i hangi programlama dili ile yazdiysaniz bu class library'i kullanan Windows Store uygulamasi da class library'i yazdiginiz programlama dilinde olmali. Yani C# ile yazdigimiz bir class libraryi HTML & Javascript kullanarak yazilmis bir Windows Store uygulamasinda kullanamiyoruz.

Iste tam bu noktada karsimiza Windows Runtime Componentleri çikiyor. Windows Runtime Componentleri temelde class libraryler gibi yazmis oldugumuz kodun farkli uygulamalar tarafindan kullanilmasini saglarken bu gelistirmis oldugumuz komponentler ayni zamanda kendi yazildiklari programlama dili disinda yazilan uygulamalar tarafindan da kullanilabilmekte.

Windows Runtime Component ismi ilk olarak Visual Studio 2012 içerisinde uygulama yaratma penceresini açtigimizda Windows Store Apps bölümüne baktigimizda karsimiza çikmakta.

Projeyi seçip yarattigimizda karsimiza çikan sinif içerisinde dikkatimizi çeken ilk nokta yaratilan sinifin sealed olmasi !

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WinRTComponent
{
    public sealed class Class1
    {
    }
}

Öncelikli olarak Windows Runtime Component'i gelistirme konusunda söylemem gereken ilk sey yazdigimiz komponentin pek çok farkli programlama dili ile yazilmis olan uygulamalarda kullanilmasi nedeniyle gelistirme kisminda ne yazik ki bir takim sinirlamalarla karsilasmaktayiz. Çünkü her programalama dilinin kendine has bazi özellikleri ve kullanim detaylari bulunmakta bu nedenle de ortak bir paydada bulusabilmek ve yazilan komponentin tüm dilleri tarafindan düzgün olarak kullanilabilmesi için bu konulan kurallara uymak zorundayiz :)

Evet sinirlamalarin nedenini de açikladiktan sonra gelelim Visual Studio 2012'nin yaratmis oldugu default sinifta karsimiza çikan sealed keywordüne :) WinRT Componeneti gelistirmesi sirasinda karsilasacagimiz ilk kural Windows Runtime Component'i içerisinden disari açacagimiz siniflarin mutlaka sealed olmasi kurali :)  Ancak burada dikkat etmemiz gereken nokta bu kuralin sadece Windows Runtime Component'i içerisinden disari açacagimiz siniflarda geçerli olmasi. Yani eger sinifinizi public olarak tanimlamazsaniz ve sadece komponent içerisindeki iç islemlerde kullanirsaniz bu noktada siniflarinizda istediginiz sekilde inheritance kullanabilirsiniz. ;)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WinRTComponent
{
    //Windows Runtime bu duruma kizmaz :)
    class SealedOlmayanClass : List<string>
    {
    }
}

Simdi gelelim Windows Runtime Componenti içerisinde bulunan tiplerimizin içerisindeki metotlara. Çok basit olarak yazdigimiz Windows Runtime Component'in bir DataAccess componenti oldugunu düsünelim ve su sekilde bir metot yazalim.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WinRTComponent
{
    public sealed class DataAccess
    {
        public static List<Speaker> GetSpeakerList()
        {
            return new List<Speaker>             {                 new Speaker{NameSurname="Daron Yöndem",Subject="Azure"},                 new Speaker{NameSurname="Umut Erkal",Subject="Kinect"},                 new Speaker{NameSurname="Yusuf Öztürk",Subject="Powershell"},             };
        }

        public sealed class Speaker
        {
            public string NameSurname { getset; }
            public string Subject { getset; }
        }
    }
}
Gördügünüz gibi oldukça basit bir sekilde DataAccess isimli bir tip içerisine GetSpeakers isminde bir static metot ekledik ve bu metot içerisinde de hizli bir sekilde bir List içerisine dummy olarak datalari doldurup bu listi metottan döndürdük. Simdi bu yazdigimiz kodu derleyelim ve ne ile karsilasacagiz bakalim  :)

"Error 1 Method 'WinRTComponent.DataAccess.GetSpeakerList()' has a parameter of type 'System.Collections.Generic.List<WinRTComponent.Speaker>' in its signature. Although this generic type is not a valid Windows Runtime type, the type or its generic parameters implement interfaces that are valid Windows Runtime types. Consider changing the type 'System.Collections.Generic.List<T>' in the method signature to one of the following types instead: 'System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T>, System.Collections.Generic.IEnumerable<T>'. C:\Users\ilkayilknur\AppData\Local\Temporary Projects\WinRTComponent\DataAccess.cs 11 37 WinRTComponent "

Yukarida yazanlar aslinda bize Windows Runtime Componenti içerisinde uygulamamiz gereken bir kurali basitçe hatirlatiyor. Nedir bu kural derseniz Windows Runtime Componenti içerisinde bulunan tipler içerisindeki public olarak tanimlanmis olan metotlarin imzalarinda mutlaka Windows Runtime tipi kullanilmalidir. Yani public olarak disari açtigimiz metotlarimizin parametrelerinin tipleri ile metodun dönecegi tip mutlaka Windows Runtime içerisinde bulunan bir tip olmalidir.

Bizim örnegimizde kullanmis oldugumuz tip aslinda baktigimizda bir .NET Framework tipidir. Ancak Windows Runtime interface tabanli bir altyapi oldugu için List tipinin Windows Runtime tarafindaki karsiligi IList interface'idir. Öyleyse yazdigimiz kodu su sekilde degistirirsek artik metodumuzu gelistirdigimiz komponent içerisinden disari açabiliriz.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WinRTComponent
{
    public sealed class DataAccess
    {
        public static IList<Speaker> GetSpeakerList()
        {
            return new List<Speaker>()
            {
                new Speaker{NameSurname="Daron Yöndem",Subject="Azure"},
                new Speaker{NameSurname="Umut Erkal",Subject="Kinect"},
                new Speaker{NameSurname="Yusuf Öztürk",Subject="Powershell"},
            };
        }
        //Windows Runtime buna da kizmaz :)
        private static List<Speaker> GetSpeakerListPrivate()
        {
            return new List<Speaker>()
            {
                new Speaker{NameSurname="Daron Yöndem",Subject="Azure"},
                new Speaker{NameSurname="Umut Erkal",Subject="Kinect"},
                new Speaker{NameSurname="Yusuf Öztürk",Subject="Powershell"},
            };
        }
    }
    public sealed class Speaker
    {
        public string NameSurname { getset; }
        public string Subject { getset; }
    }
}

Simdi kodumuz düzgün bir sekilde derlendi :) Simdi gelin yazmis oldugumuz komponenti HTML ve JS kullanarak yazacagimiz uygulamamiz da kullanalim.

Öncelikle projemizi yaratalim.

Projemizi yarattiktan sonra hizli bir sekilde ayni dll referansi eklyormusuz gibi Add Reference diyerek yazmis oldugumuz komponenti projemize referans olarak ekleyelim.

Ilk olarak default.html içerisine basit olarak bir table yerlestirelim ve bu tablo içerisinde Windows Runtime Component'i içerisinden gelecek datalari görüntüleyebilecek sekilde düzenlemeler yapalim.

<!DOCTYPE html>
<html>
<head>
    <meta charset=&quot;utf-8&quot; />
    <title>ComponentConsumer</title>

    <!-- WinJS references -->
    <link href=&quot;//Microsoft.WinJS.1.0/css/ui-dark.css&quot; rel=&quot;stylesheet&quot; />
    <script src=&quot;//Microsoft.WinJS.1.0/js/base.js&quot;></script>
    <script src=&quot;//Microsoft.WinJS.1.0/js/ui.js&quot;></script>

    <!-- ComponentConsumer references -->
    <link href=&quot;/css/default.css&quot; rel=&quot;stylesheet&quot; />
    <script src=&quot;/js/default.js&quot;></script>
</head>
<body>
    <table>
        <thead>
            <tr>
                <td>Isim</td>
                <td>Konu</td>
            </tr>
        </thead>
        <tbody id=&quot;table-body&quot;>
        </tbody>

    </table>
</body>
</html>

Simdi ise geldik Windows Runtime Componentimizi kullanacagimiz Javascript tarafina. Javascript tarafinda hemen default.js tarafina geçelim ve kodumuzu yazmaya baslayalim. Komponentin namespace'i olan WinRTComponent namespace'i  javascript tarafindan dogrudan erisilebilir durumda. Öyleyse hemen hizlica Windows Runtime Component'imizi kullanan ve ilgili tabloyu dolduran javascript kodumuzu yazalim.

(function () {
    "use strict";

    WinJS.Binding.optimizeBindingReferences = true;

    var app = WinJS.Application;
    var activation = Windows.ApplicationModel.Activation;

    app.onactivated = function (args) {
        if (args.detail.kind === activation.ActivationKind.launch) {
            if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
                var speakers = WinRTComponent.DataAccess.getSpeakerList();

                for (var i = 0; i < speakers.length; i++) {
                    var speaker = speakers[i];

                    var body = document.getElementById("table-body");

                    body.innerHTML += "<tr><td>"+ speaker.nameSurname + "</td><td>"+ speaker.subject + "</td></tr>";
                }
            } else {

            }
            args.setPromise(WinJS.UI.processAll());
        }
    };

    app.oncheckpoint = function (args) {
    };

    app.start();
})();

"Öncelikle yazmis oldugum javascript ve html'i okuyan front-end developerlara bu konuda oldukça tecrübesiz ve kötü oldugumu bildirmemde fayda var. :) (Sonra böyle kod mu olur seklinde serzenislerde bulunmayin :) )"

Neyse konumuza dönersek yukarida hizli bir sekilde kodumuzu yazdik ancak bu noktada sizlerin dikkatini çekmek istedigim önemli bir nokta var.

Farkettiyseniz yukarida yazmis oldugumuz C# kodlarinda metodumuzun adi GetSpeakerList'ti. Ayni sekilde propertylerimizin ismi de NameSurname ve Subject'ti. Ancak javascript tarafina geçtigimizde gördügünüz gibi metotlarimizin ve propertylerimizin ismi javascript tarafinda kullanilan casing'e göre yeniden düzenlendi ve böylece HTML ve JS tarafinda bulunan developerlarin bu isimlendirmelerde hiç bir sekilde sikinti çekmemesi saglandi. Microsoft'un development deneyimi konusunda yapmis oldugu en güzel hareketlerden biri olarak bu noktayi belirtmeden geçemedim ;)

Evet uygulamamizi gelistirdik simdi bir de uygulamamizi çalistiralim ve çalistigini görelim :)

Gördügünüz gibi HTML ve Javascript ile yazdigimiz uygulamamiz içerisinde C# ile yazmis oldugumuz Windows Runtime Componentini kullanabilmekteyiz. Windows Runtime Componentlerini aslinda pek çok farkli noktalarda devreye sokup uygulamalarimizi gelistirebilmekteyiz. Örnegin bu senaryomuzda oldugu gibi DataAccess tarafinda Windows Runtime Componentleri kullanabilecegimiz gibi hesaplama kisimlarinda, parse  vb..  gibi pek çok farkli noktada yine Windows Runtime Componentleri kullanabilmeteyiz. Hatta Windows Runtime Component'i kullanarak bir Windows Store projesini tüm yükü tek developera vermemek adina back-end kismini C# developera yaptirabilir arayüz tarafini da backend'den gelen metotlari çagirarak bir HTML & Javascript uygulamasi olarak gelistirebilirsiniz. Burada önemli olan Windows Runtime Componentlerini dogru zamanda devreye sokabilmek.

Bir kaç Windows Runtime Component Gelistirme Kurali Daha...

Yazimizin sonlarina gelirken yukarida bahsetmis oldugum Windows Runtime Component'i gelistirirken dikkat etmemiz gereken kurallara 2-3 ufak kurali daha ekleyerek yazimiza son verelim :)

  • Windows Runtime Component'i içerisinde disariya açilan structlarin sadece public alanlari olmalidir. Içerisinde private alanlar barindiramazlar. Ayrica disariya açilan structlar içerisinde propertyler de bulunamaz.
  • Windows Runtime Componentleri içerisinde sadece sistem içerisinde tanimli olan generic tipler kullanilabilir.
  • Windows Runtime Component'i içerisinde disariya sunulan tipler sealed olmalidir. Tek istisna XAML kontrolleridir. XAML kontrollerinde inheritance kullanilabilir.

Evet kurallarimiz bu kadar.

Umarim faydali bir yazi olmustur.

Hepinize kolay gelsin !



Windows 8 Metro Style Uygulamalarda Semantic Zoom - C# & XAML

Merhaba Arkadaslar,

Windows 8 ile beraber baktigimizda hayatimiza kullanici deneyimi bakimindan pek çok yenilik gelmekte. Bu yeniliklerin en dikkat çekici olanlarindan biri de hiç süphesiz ki Semantic Zoom kavrami.

Semantic Zoom, zoom-in ve zoom-out islemleri ile kullaniciya elindeki data üzerinde gerek bütün olarak veri üzerinde dolasabilmeye imkan verirken gerekse veriyi gruplayarak veya özetleyerek bu gruplanmis veya özetlenmis veri kümesi üzerinde kullanicinin dolasmasina imkan saglamakta. Böylece kullanici aslinda önünde bulunan veri kümesi üzerinde zoom-out islemi yaptigi zaman görmüs oldugu verinin daha küçük gruplanmis veya özetlenmis halini görerek bu sekilde belki de daha hizli bir biçimde istedigi dataya ulasabilmekte. Su anda Windows 8 üzerinde Semantic Zoom'un kullanildigi en önemli yerlerden biri de Start Screen. Start Screen üzerinde Zoom-in ve Zoom-out yaptiginizda StartScreen içerisinde bulunan itemlar ekranda daha ufak bir biçimde gösterilerek kullanicinin Start Screen içerisinde bulunan tüm gruplari görebilmesi saglanmakta.

Not : Semantic Zoom aslinda touch screen bir cihazda klasik zoom gesturelari ile saglanirken touch screen olmayan cihazlarda ise Ctrl tusu basili tutularak mouse scroll ile ayni deneyim saglanabilmekte.

 

Hiç süphesiz ki Windows 8 içerisinde kullanilan bu deneyiminin bizim gelistirdigimiz uygulamalarda da olmasi hem kullanicilara büyük bir kolaylik ve deneyim saglayacak hem de bizim uygulamamiza ayri bir deger katacaktir. Simdi gelelim uygulamalarimiza semantic zoom'u nasil entegre edecegimiz konusuna. (Biz semantic zoom'u önceki yazilarimizda da gerçeklestirimini yaptigimiz yemek uygulamasi üzerinde yapiyor olacagiz.)

Uygulamamiza baslamadan önce karar vermemiz gereken noktalardan biri de semantic zoom'u nasil bir konseptte implemente edecegimiz. Yani kullanici elimizdeki data üzerinde zoom-out yaptiginda ne yapacagimiza karar vermemiz gerekiyor. Böyle bir durumda biz kullaniciya sadece yemek kategorilerini gösteriyor olacagiz. Böylece kullanici istediginde de ilgili kategoriye tiklayarak o kategori içerisindeki yemekleri görebiliyor olacak. Kategorileri gösterdigimiz durumda da eger kullanici zoom-in yaparsa elimizdeki tüm yemek listesini bir gridview içerisinde gösterecegiz.

Bu karari da verdikten sonra simdi sira geldi uygulamamizi gelistirme kismina. Hemen bos bir Metro Style Application yaratalim ve uygulamamizi gelistirmeye baslayalim.

Ilk olarak sahnemize sol taraftaki toolboxtan bir SemanticZoom kontrolü sürükleyerek uygulamaya baslayalim.

<SemanticZoom>
    <SemanticZoom.ZoomedInView>
        <GridView/>
    </SemanticZoom.ZoomedInView>
    <SemanticZoom.ZoomedOutView>
        <ListView/>
    </SemanticZoom.ZoomedOutView>
</SemanticZoom>

SemanticZoom kontrolünü sahneye ekledikten sonra olusan XAML kodumuz yukaridaki sekilde. Bu olusan XAML kodunun detaylarina indigimizde ise aslinda karsimiza oldukça basit bir sekilde 2 property çikmakta. Bunlardan biri ZoomedInView digeri de ZoomedOutView. Aslinda anlamlari adlarindan da anlasilacagi gibi oldukça basit. Kullanici Zoom-in yaptiginda olusacak görünümü ZoomedInView'a koyacagiz, yine kullanici zoom-out yaptiginda da olusacak görünümü de ZoomOutView'a koyacagiz :) Hatta yol göstermek amaciyla Visual Studio bizim ZoomedInView'imiz içerisine bir GridView yerlestirmis. ZoomedOutView'a da ayni sekilde bir ListView yerlestirmis. :) O zaman bizde bu yolu takip ederek devam edelim.

ZoomedInView aslinda bizim uygulamamiz açildiginda da gösterilecek olan default görünüm olacak. Bu nedenle burada bir GridView kontrolü kullanarak ilerlememiz bizim için en dogru çözüm. Bu nedenle burada daha önceki yazilarimizdan birinde inceledigimiz gruplanmis GridView kontrolünü yerlestirmemiz bizim için en dogrusu olacaktir. Bunun için gerekli olan templatelarimizi ve servis kodumuzu hemen projemize ekliyoruz. (Ekledigimiz tüm bilesenleri ve kodu açiklamalariyla beraber buradaki yazida bulabilirsiniz.)

<Page
    x:Class="SemanticZoom.MainPage"
    IsTabStop="false"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:SemanticZoom"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    <Page.Resources>
        <CollectionViewSource  x:Name="foodDataSource" ItemsPath="Foods" IsSourceGrouped="True"/>
        <DataTemplate x:Key="FoodTemplate">
            <Grid>
                <Image HorizontalAlignment="Left" Height="246" VerticalAlignment="Top" Width="250" Stretch="UniformToFill" Source="{Binding ImageUrl}"/>
                <Border BorderThickness="1" HorizontalAlignment="Left" Height="22.393" Margin="0,223.607,0,0" VerticalAlignment="Top" Width="250" Background="Black" Opacity="0.4">
                    <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top" Margin="3,2,0,0" Text="{Binding FoodName}"/>
                </Border>
            </Grid>
        </DataTemplate>
        <ItemsPanelTemplate x:Key="ItemsPanelTemplate">
            <StackPanel Orientation="Horizontal" />
        </ItemsPanelTemplate>
    </Page.Resources>

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <SemanticZoom x:Name="semanticZoom" Margin="50,140,15,15">
            <SemanticZoom.ZoomedInView>
                <GridView x:Name="foodGrid" ItemsSource="{Binding Source={StaticResource foodDataSource}}" ItemTemplate="{StaticResource FoodTemplate}" ItemsPanel="{StaticResource ItemsPanelTemplate}">
                    <GridView.GroupStyle>
                        <GroupStyle>
                            <GroupStyle.HeaderTemplate>
                                <DataTemplate>
                                    <TextBlock FontSize="18.667" Text="{Binding CategoryName}"/>
                                </DataTemplate>
                            </GroupStyle.HeaderTemplate>
                            <GroupStyle.Panel>
                                <ItemsPanelTemplate>
                                    <VariableSizedWrapGrid Orientation="Horizontal" MaximumRowsOrColumns="3"/>
                                </ItemsPanelTemplate>
                            </GroupStyle.Panel>
                        </GroupStyle>
                    </GridView.GroupStyle>
                </GridView>
            </SemanticZoom.ZoomedInView>
            <SemanticZoom.ZoomedOutView>
                <ListView/>
            </SemanticZoom.ZoomedOutView>
        </SemanticZoom>
    </Grid>
</Page>
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
    FoodService.ServiceClient client = new FoodService.ServiceClient();

    foodDataSource.Source = await client.GetFoodsAsync();
}

Evet uygulamamizin ZoomedInView'i hazir. :) Zaten daha önceden hazirlamistik. :) Simdi sira geldi ZoomedOutView'a ki bunu sifirdan hazirliyor olacagiz. ZoomedOutView'da bir ListView kullanacagiz demistik ve bu ListView içerisinde  de kategori isimlerini gösterecektik. Bunun için ilk olarak kullanacagimiz veri kaynagini ilgili ListView kontrolünün ItemsSource'una baglamamiz gerekmekte ve bu islem için GridView kontrolünde de kullandigimiz sayfa içerisinde bulunan CollectionViewSource tipinden yararlaniyor olacagiz. Böylece ortak bir veri kaynagini kullandigimiz için de ilgili kategori ismine tiklandiginda GridView üzerindeki kategori üzerine yönlenmesi islemi de otomatik olarak gerçeklesiyor olacak.

CollectionViewSource tipinin içerisine baktigimizda ise karsimiza View isimli bir property çikmakta. Bu property aslinda CollectionViewSource tipinin içerisinde bulunan verileri disariya veya bagli oldugu kontrollere sundugu seklin birebir kopyasi. Bu nedenle View propertysi üzerinden aslinda "verilerimi bana kategorili bir biçimde ver" seklinde bir kullanim da gerçeklestirebilmekteyiz ve bu sekilde bir kullanim için de View.CollectionGroups isimli property'i kullanmaktayiz.

CollectionViewSource içerisinde bulunan View.CollectionGroups isimli propertynin tipine baktigimizda IObservableCollection<object> oldugunu görüyoruz. Peki biz yemek kategorilerinin isimlerini nasil bulacagiz da ListView içerisinde gösterecegiz. :) Isterseniz ilk olarak kategorilerimizi elimizdeki ListView'in ItemsSource'una baglayalim ve uygulamamizi çalistiralim, bakalim debug sirasinda bu property bize nasil bir deger döndürecek. :)

protected async override void OnNavigatedTo(NavigationEventArgs e)
{
    FoodService.ServiceClient client = new FoodService.ServiceClient();
    foodDataSource.Source = await client.GetFoodsAsync();
    (semanticZoom.ZoomedOutView as ListViewBase).ItemsSource = foodDataSource.View.CollectionGroups;
}

DependencyObject :) yine istedigimiz degere ulasamadik. Oldukça can sikabilecek bu durumun çözümünü su sekilde yapabiliriz. Aslinda foodDataSource.View.CollectionGroups dedigimizde bize dönen IObservableCollection<object> içerisinde bulunan her bir eleman object olmanin yani sira ayni zamanda ICollectionViewGroup :) Buradan da hareket edersek ListView içerisinde Binding islemi yaparken ICollectionViewGroup interface'i üzerinden ilerleyebiliriz. Öyleyse ICollectionViewGroup interface'inin içerisinde bulunan üyelere bir göz atalim.

public interface ICollectionViewGroup
{
    object Group { get; }
    IObservableVector<object> GroupItems { get; }
}

Simdi istedigimize ulastik gibi :) . Interface'in yapisina baktigimizda karsimiza oldukça basit bir yapi çikiyor. Group propertysi  içerisinde bagladigimiz gruplar bulurken GroupItems propertysi içinde de grup içerisindeki elemanlar bulunmakta. Uygulamamiz üzerinden ilerlersekte Group içerisinde FoodCategory bulunurken GroupItems içerisinde de Food tipini içerisinde barindiran bir IObservableVector bulunmakta. O zaman yemek kategorilerinin isimlerini göstermek için Group.CategoryName propertysini kullanabiliriz.

O zaman gelin önce ListView içerisindeki itemlari nasil görecegimizi belirlemek için bir ItemTemplate yaratalim.

<DataTemplate x:Key="CategoryTemplate">
           <Grid d:DesignWidth="205.403" d:DesignHeight="203.463">
               <Button Content="{Binding Group.CategoryName}" HorizontalAlignment="Left" VerticalAlignment="Top" Height="200" Width="200"/>
         </Grid>
</DataTemplate>

Bir de son olarak ListView içerisinde bulunacak olan Itemlarimizi yatay olarak göstermek için ListView içerisindeki ItemsPanel'de bulunan StackPanel'in Orientation'ini Vertical'dan Horizontal'a aliyoruz.

<ItemsPanelTemplate x:Key="CategoryPanelTemplate">
           <VirtualizingStackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>

Son olarak sayfamizin olusan XAML kodu ise su sekilde.

<Page
    x:Class="SemanticZoom.MainPage"
    IsTabStop="false"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:SemanticZoom"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    <Page.Resources>
        <CollectionViewSource  x:Name="foodDataSource" ItemsPath="Foods" IsSourceGrouped="True"/>
        <DataTemplate x:Key="FoodTemplate">
            <Grid>
                <Image HorizontalAlignment="Left" Height="246" VerticalAlignment="Top" Width="250" Stretch="UniformToFill" Source="{Binding ImageUrl}"/>
                <Border BorderThickness="1" HorizontalAlignment="Left" Height="22.393" Margin="0,223.607,0,0" VerticalAlignment="Top" Width="250" Background="Black" Opacity="0.4">
                    <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top" Margin="3,2,0,0" Text="{Binding FoodName}"/>
                </Border>
            </Grid>
        </DataTemplate>
        <ItemsPanelTemplate x:Key="ItemsPanelTemplate">
            <StackPanel Orientation="Horizontal" />
        </ItemsPanelTemplate>
        <ItemsPanelTemplate x:Key="CategoryPanelTemplate">
            <VirtualizingStackPanel Orientation="Horizontal" />
        </ItemsPanelTemplate>
        <DataTemplate x:Key="CategoryTemplate">
            <Grid d:DesignWidth="205.403" d:DesignHeight="203.463">
                <Button Content="{Binding Group.CategoryName}" HorizontalAlignment="Left" VerticalAlignment="Top" Height="200" Width="200"/>
            </Grid>
        </DataTemplate>
    </Page.Resources>

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <SemanticZoom x:Name="semanticZoom" Margin="50,140,15,15">
            <SemanticZoom.ZoomedInView>
                <GridView x:Name="foodGrid" ItemsSource="{Binding Source={StaticResource foodDataSource}}" ItemTemplate="{StaticResource FoodTemplate}" ItemsPanel="{StaticResource ItemsPanelTemplate}">
                    <GridView.GroupStyle>
                        <GroupStyle>
                            <GroupStyle.HeaderTemplate>
                                <DataTemplate>
                                    <TextBlock FontSize="18.667" Text="{Binding CategoryName}"/>
                                </DataTemplate>
                            </GroupStyle.HeaderTemplate>
                            <GroupStyle.Panel>
                                <ItemsPanelTemplate>
                                    <VariableSizedWrapGrid Orientation="Horizontal" MaximumRowsOrColumns="3"/>
                                </ItemsPanelTemplate>
                            </GroupStyle.Panel>
                        </GroupStyle>
                    </GridView.GroupStyle>
                </GridView>
            </SemanticZoom.ZoomedInView>
            <SemanticZoom.ZoomedOutView>
                <ListView x:Name="lstCategories" ItemsPanel="{StaticResource CategoryPanelTemplate}" ItemTemplate="{StaticResource CategoryTemplate}" Height="240">
                </ListView>
            </SemanticZoom.ZoomedOutView>
        </SemanticZoom>
    </Grid>
</Page>

Simdi uygulamamizi çalistiralim ve yaptigimiz Semantic Zoom implementasyonunu inceleyelim.

ZoomedInView

ZoomOutView

Gördügünüz gibi 1-2 trick nokta haricinde aslinda uygulamalariniza Semantic Zoom destegi eklemek oldukça basit. Semantic Zoom'un uygulamalariniza katacagi deger ise harcayacagimiz efora göre çok çok daha  yüksek :)

Hepinize kolay gelsin


Windows 8 Metro Style Uygulamalarda FlipView Kontrolü - C# & XAML

Merhaba Arkadaşlar,

Bu yazımızda da Windows 8 data kontrollerine devam ediyoruz ve yepyeni bir kontrolü inceliyoruz. :) Bu yazımızda inceleyeceğimiz kontrol FlipView kontrolü. FlipView kontrolü Windows 8 içerisinde bulunan ve daha önce diğer platformlarda da bu konseptte karşılaşmadığımız bir kontrol. Daha doğrusunu söylemek gerekirse diğer ortamlarda benzer fonksiyonaliteyi kendi yazdığımız custom kontrollerle yapabiliyorken Windows 8 üzerinde ise FlipView kontrolü ile bu fonksiyonaliteyi ve kullanıcı deneyimini hemen hızlıca implemente edebiliyoruz. FlipView kontrolü aslında Windows 8 içerisinde sıklıkla karşılaştığımız bir kontrol. Hemen ufak bir örnek vermemiz gerekirse Store içerisinde bulunan uygulamaların screenshotlarının gösterildiği kontrolün FlipView kontrolü olduğunu söyleyebiliriz..

Kontrol aslında basit olarak içerisinde bulunan itemları sırayla göstermekte. Eğer dokunmatik bir Windows 8 cihaz üzerinde çalıştırıyorsanız da resimde görmüş olduğunuz sağ ve sol ok tuşları yerine doğrudan dokunmatik olarak sağa ve sola doğru parmağınızı hareket ettirerek itemlar içerisinde gezebiliyorsunuz. Eğer siz de bu şekilde bir kullanıcı deneyimini uygulamanıza katmak istiyorsanız başvuracağınız kontrol FlipView kontrolü :)

Gerekli tanıtımı yaptıktan sonra şimdi gelelim uygulama kısmına. Hemen yeni bir Windows 8 Metro Style Application yaratıyoruz ve sahnenin ortasına bir FlipView kontrolü yerleştiriyoruz.

[sourcecode lang="xml"] <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> <FlipView x:Name="foodFlip" Margin="188,150,200,58"/> </Grid> [/sourcecode]

FlipView kontrolünün içerisinde daha önceki yazılarımızdaki örneklerimizde de kullandığımız gibi FoodService web service'i üzerinden bize dönen yemeklerin bilgilerini gösteriyor olacağız. Bu bilgiler de basit olarak yemeğin fotoğrafı ve yemeğin adı olacak. Bu şekilde bir gösterim elde etmek için önceki yazılarımızdan da hatırlayacağımız üzere FlipView kontrolüne içerisindeki itemları nasıl göstermesi gerektiğini ayrıca belirtmemiz gerekmekte. Bunu da hatırlayacağımız üzere templating yapısı ile gerçekleştirebiliyoruz.

Template yaratma kısmına geçmeden önce, eğer FlipView içerisinde bağladığınız nesnenin sadece 1 propertysini göstermek istiyorsanız yine alışkın olduğumuz DisplayMemberPath ve SelectedValuePath propertylerini kullanarak ilgili propertyleri  bu şekilde XAML üzerinden set edip ilerleyebilirsiniz. Ancak FlipView içerisinde sadece text göstermek ne derece uygun ve başarılı bir görünüm oluşturur orası artık size kalmış ;)

Evet şimdi gelelim templating kısmına. FlipView kontrolüne içerisinde bulunan nesneleri nasıl göstereceğini bildirecektik. Bunun için FlipView kontrolü içerisinde bir ItemTemplate yaratıyor olacağız. Ancak öncelikle FlipView kontrolüne bağlayacağımız Food tipimizin içerisinde bulunan alanları hatırlayalım.

[sourcecode lang="csharp"] [DataContract] public class Food { [DataMember] public string FoodName { get; set; } [DataMember] public decimal Price { get; set; } [DataMember] public string ImageUrl { get; set; } } [/sourcecode] ItemTemplate yaratma kısmında yine Blend üzerinden ilerliyor olacağız. Ancak daha önceden de bahsettiğim gibi aynı olanaklar Visual Studio 2012 içerisinde de mevcut. ;)

Yaratacağımız ItemTemplate oldukça basit olacak. Arka planda yemeğin resmi bulunacak ve resmin alt kısmında da yemeğin ismi yazıyor olacak.

[sourcecode lang="xml"] <Page.Resources> <DataTemplate x:Key="FoodTemplate"> <Grid d:DesignWidth="640.896" d:DesignHeight="381.194"> <Image Source="{Binding ImageUrl}" Stretch="UniformToFill"/> <Border BorderBrush="Black" BorderThickness="1" Margin="0" Background="Black" Opacity="0.55" VerticalAlignment="Bottom" Height="60"> <TextBlock HorizontalAlignment="Left" Margin="7.502,5.014,0,0" TextWrapping="Wrap" VerticalAlignment="Top" FontSize="26.667" Text="{Binding FoodName}" FontFamily="Segoe UI Semibold"/> </Border> </Grid> </DataTemplate> </Page.Resources> [/sourcecode]

ItemTemplate'ımızı yarattıktan sonra sıra geldi FlipView kontrolümüze içerisindeki itemları yarattığımız templatetaki gibi göstereceğini bildirme kısmına. Bunu da XAML içerisinden hızlı bir şekilde FlipView içerisinde bulunan ItemTemplate alanına yaratmış olduğumuz template'ı vererek gerçekleştirebiliriz.

[sourcecode lang="xml"] <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> <FlipView x:Name="flip" ItemTemplate="{StaticResource FoodTemplate}" Margin="188,150,200,58"/> </Grid> [/sourcecode]

Uygulamamızın UI kısmını bitirdik. Son olarak ise C# tarafından yemek listelerinin döndüğü servisi çağıracağız ve dönen listeyi FlipView kontrolünün ItemsSource propertysine vereceğiz.

[sourcecode lang="csharp"] protected async override void OnNavigatedTo(NavigationEventArgs e) { FoodService.ServiceClient client = new FoodService.ServiceClient(); flip.ItemsSource = await client.GetFoodsAsync(); } [/sourcecode]

Evet. Yapacaklarımız bu kadar. :) Aslında önceki yazılarımızı da okuduysanız yaptığımız herşey size oldukça tanıdık gelecektir. Bu da bize Windows 8 üzerindeki uygulama geliştirme deneyiminin ne denli başarılı olduğunun bir göstergesidir. Şimdi yaptığımız uygulamayı çalıştıralım ve yaptıklarımızı görelim.

Gördüğünüz gibi yemeklerimizi FlipView içerisinde belirlediğimiz template'a uygun olarak gösterebiliyoruz. Böylece kullanıcı hızlı bir şekilde yemek listesi üzerinde gezebiliyor. Bu şekilde bir kullanımı bir de dokunmatik cihaz kullanarak kullanıcıya sunarsanız elde ettiğiniz kullanıcı deneyimi ve harcadığınız efor oranının ne kadar müthiş seviyelerde olacağını tahmin edebiliyorsunuzdur ;)

Dikey FlipView :)

Yukarıdaki örneğimizde FlipView içerisindeki kontrolü içerisindeki itemları sağdan sola veya soldan sağa doğru gezebiliyorduk. Peki ya aşağıdan yukarıya yada yukarıdan aşağıya gezmek istersek ne yapmamız gerekir ? :)

Aslında yapmamız gereken şey oldukça basit. FlipView içerisinde bulunan itemları yatay olarak değil de dikey olarak dizeceğiz ;) Peki bunu nasıl yapacağız ? Gelin FlipView içerisinde bulunan templatelara bir kez daha bakalım :)

ItemsPanel bize ordan göz kırpıyor gibi :) Aslında adından da anlayacağımız gibi itemları içerisinde barındıran bir container. Hemen "Create Empty" diyerek bir örnek alalım.

Şimdi ekranda görünen kısımları sırayla inceleyelim. Öncelikle "Create Empty" tuşuna bastığımızda Blend bize bir template yarattı. Bu templatta da gördüğümüz üzere FlipView kontrolü içerisinde itemlar aslında StackPanel'in özelleşmiş bir versiyonu olan VirtualizingStackPanel içerisinde bulunuyorlarmış.

Peki StackPanel isminin başına Virtualizing kelimesi gelince StackPanel nasıl bir yetenek kazanıyor ? Virtualizing kavramı bize aslında genel olarak performans konusunda oldukça fayda sağlamakta. Çünkü virtualizing demek daha az kaynak kullanımı demek. Kaynakları gerektikçe kullanmak demek. Örneğin FlipView içerisindeki itemların belki de en sonunda bulunan itema kullanıcı hiçbir zaman ulaşmayacak. Bu nedenle bu itemin içerisinde bulunan resmi gidip indirmenin de bir anlamı yok. Bu nedenle virtualizing kavramını kullanarak aslında sadece o anda ihtiyaç duyulan kaynaklara erişebilirsiniz.

Evet ana konumuza geri dönersek sağ kısımda da göreceğiniz üzere StackPanel'in Orientation'ı default olarak Horizontal  set edilmiş. Bu da demek oluyor ki içerisinde bulunan elemanlar yan yana dizilecek. Biz demek ki bu değeri Vertical'a çekerek içerisindeki elemanların alt alta dizilmesini sağlayabiliriz. Bu işlemi de yaptıktan sonra sayfamızın XAML kodu şu şekilde olmakta.

[sourcecode lang="xml"] <Page.Resources> <DataTemplate x:Key="FoodTemplate"> <Grid d:DesignWidth="640.896" d:DesignHeight="381.194"> <Image Source="{Binding ImageUrl}" Stretch="UniformToFill"/> <Border BorderBrush="Black" BorderThickness="1" Margin="0" Background="Black" Opacity="0.55" VerticalAlignment="Bottom" Height="60"> <TextBlock HorizontalAlignment="Left" Margin="7.502,5.014,0,0" TextWrapping="Wrap" VerticalAlignment="Top" FontSize="26.667" Text="{Binding FoodName}" FontFamily="Segoe UI Semibold"/> </Border> </Grid> </DataTemplate> <ItemsPanelTemplate x:Key="ItemsPanelTemplate2"> <VirtualizingStackPanel Orientation="Vertical"/> </ItemsPanelTemplate> </Page.Resources> <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> <FlipView x:Name="flip" ItemTemplate="{StaticResource FoodTemplate}" Margin="188,150,200,58" ItemsPanel="{StaticResource ItemsPanelTemplate2}"/> </Grid> [/sourcecode]

Şimdi uygulamamızı yeniden çalıştıralım ve değişiklere bakalım :)

Gördüğünüz gibi FlipView içerisinde elemanlar aşağıdan yukarıya doğru oluştu ve FlipView kontrolü de bunu algılayıp aşağı ve yukarı oklarını kendisi otomatik olarak yerleştirdi. ;)

Bu yazımızda Windows 8 ile beraber gelen yepyeni FlipView kontrolünü inceledik. Umarım faydalı olmuştur.

Görüşmek Üzere,



Windows 8 Metro Style Uygulamalarda ListView Kontrolü - C# & XAML

Merhaba Arkadaşlar,

Bir data-driven uygulama geliştirdiğimizde en çok ihtiyaç duyacağımız kontroller, hiç şüphesiz ki listeleme kontrolleri olmakta. Geçtiğimiz yazılarda da Windows 8 içerisinde en sık kullanılan listeleme kontrollerinden olan GridView kontrolünü incelemiştik. Özellikle WPF, Windows Phone, Silverlight ile development yapıyorsanız bu platformlarda  sıklıkla kullandığımız ListBox kontrolünün Windows 8 tarafında bir karşılığı olup olmadığını merak ettiğinizi düşünüyorum :)

Windows 8 tarafında ListBox kontrolünün karşılığı aslında adından da anlayabileceğimiz gibi ListView kontrolü. ListView temel olarak içerisindeki nesneleri yatay veya dikey olarak listeleme özelliğine sahip bir kontrol. Bunun yanında kullanım olarak ta aslında mevcut WPF, Windows Phone, Silverlight eşlenikleriyle hemen hemen benzer bir kullanıma sahip.

Şimdi isterseniz basitçe bir örnek yapalım ve uygulamalı olarak ListView kontrolünün kullanımını inceleyelim.

Örnek uygulama olarak basitçe bir master - detail listeleme uygulaması yapıyor olacağız ve önceki yazılarımızda kullandığımız  FoodService servisini kullanıyor olacağız.

Şimdi ilk olarak yemek kategorilerini listeleyeceğimiz bir ListView kontrolü alalım ve sahneye yerleştirelim.

[sourcecode lang="xml"] <StackPanel Background="{StaticResource ApplicationPageBackgroundThemeBrush}" Orientation="Horizontal"> <ListView x:Name="lstCategories" HorizontalAlignment="Left" Height="710" Margin="90,48,0,0" VerticalAlignment="Top" Width="426" Background="White" Foreground="Black" FontSize="21.333"/> </StackPanel> [/sourcecode]

Yemek kategorilerini listeleyeceğimiz bu ListView kontrolünde basit olarak sadece yemek kategorisinin adını göstereceğiz. Bunun için de zaten listbox tarafından aşina olduğumuz DisplayMemberPath propertysine bağlayacağımız tip içerisindeki ilgili propertynin ismini atayacağız. Tabi öncelikle servisten bize dönen FoodCategory tipinin içeriğini bir hatırlayalım.

[sourcecode lang="csharp"] [DataContract] public class FoodCategory { [DataMember] public string CategoryName { get; set; } [DataMember] public List<Food> Foods { get; set; } } [/sourcecode]

Tipimiz içerisindeki CategoryName propertysi kategorinin ismini tuttuğundan bu propertynin ismini DisplayMemberPath'e  vereceğiz.

[sourcecode lang="xml"] <StackPanel Background="{StaticResource ApplicationPageBackgroundThemeBrush}" Orientation="Horizontal"> <ListView x:Name="lstCategories" HorizontalAlignment="Left" Height="710" Margin="90,48,0,0" VerticalAlignment="Top" Width="426" DisplayMemberPath="CategoryName" Background="White" Foreground="Black" FontSize="21.333"/> </StackPanel> [/sourcecode] Son olarak ise lstCategories isimli listView'ın ItemsSource'una web servisten dönen yemek listesini veriyoruz. [sourcecode lang="csharp"] protected async override void OnNavigatedTo(NavigationEventArgs e) { FoodService.ServiceClient client = new FoodService.ServiceClient(); ObservableCollection<FoodCategory> foodList = await client.GetFoodsAsync(); lstCategories.ItemsSource = foodList; } [/sourcecode]

Evet uygulamamızın ilk ve kolay kısmını bitirdik. Şimdi isterseniz uygulamamızı çalıştıralım ve kategorilerin nasıl listelendiğini bir görelim.

Şimdi sıra geldi kategorilerin listelendiği listboxta bir kategoriye tıklandığında başka bir listbox içerisinde o kategori içerisinde bulunan yemekleri gösterme kısmına. Bunun için öncelikle sahneye bir ListView kontrolü koyacağız ve listView kontrolünün ItemSource'una da Element Binding yöntemiyle kategori listesinden seçilen Item'ın içerisindeki Foods isimli listeyi vereceğiz. Böylece dekleratif biçimde bu bağlama işlemini hızlıca yapıp geçeceğiz. :)

[sourcecode lang="xml"] <StackPanel Background="{StaticResource ApplicationPageBackgroundThemeBrush}" Orientation="Horizontal"> <ListView x:Name="lstCategories" HorizontalAlignment="Left" Height="710" Margin="90,48,0,0" VerticalAlignment="Top" Width="426" DisplayMemberPath="CategoryName" Background="White" Foreground="Black" FontSize="21.333"/> <ListView x:Name="lstFoods" HorizontalAlignment="Left" Height="710" Margin="70,48,0,0" VerticalAlignment="Top" Width="525" Background="White" Foreground="Black" ItemsSource="{Binding SelectedItem.Foods, ElementName=lstCategories}"/> </StackPanel> [/sourcecode]

Şimdi sıra geldi listView içerisindeki yemekleri nasıl listeleyeceğimize. Bunun için daha önce GridView kontrolünde gördüğümüz gibi ve diğer platformlardan da bildiğimiz üzere ListView içerisinde bir ItemTemplate yaratacağız ve daha sonra ListView kontrolüne içerisindeki itemları yarattığımız template ile göstermesini bildireceğiz. Şimdi ilk olarak ListView içerisinde bir ItemTemplate yaratalım.

ItemTemplate'tımız ise basitçe yemeğin fotoğrafını, adını ve fiyatını içerecek.

[sourcecode lang="xml"] <DataTemplate x:Key="FoodTemplate"> <StackPanel d:DesignWidth="878" d:DesignHeight="764" Orientation="Horizontal"> <Image HorizontalAlignment="Left" Height="127" Margin="10,0,0,0" VerticalAlignment="Top" Width="155" Stretch="UniformToFill" Source="{Binding ImageUrl}"/> <StackPanel Orientation="Vertical"> <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top" FontSize="21.333" Text="{Binding FoodName}" Foreground="Black"/> <StackPanel Orientation="Horizontal"> <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top" FontSize="21.333" Text="{Binding Price}" Foreground="Black"/> <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top" FontSize="21.333" Text="TL" Margin="10,0,0,0" Foreground="Black"/> </StackPanel> </StackPanel> </StackPanel> </DataTemplate> [/sourcecode] Son olarak ise ListView kontrolüne itemları, hazırlamış olduğumuz ItemTemplate'ı kullanarak göstermesi gerektiğini bildiriyoruz. [sourcecode lang="xml"] <ListView x:Name="lstFoods" HorizontalAlignment="Left" Height="710" Margin="70,48,0,0" VerticalAlignment="Top" Width="525" Background="White" Foreground="Black" ItemTemplate="{StaticResource FoodTemplate}" ItemsSource="{Binding SelectedItem.Foods, ElementName=lstCategories}"/> [/sourcecode] Evet herşey bu kadar :) Şimdi uygulamamızı çalıştıralım ve geliştirdiğimiz uygulamayı görelim.

Gördüğünüz gibi solda bulunan kategori listesinde seçtiğimiz kategoriyi değiştirdiğimizde yapmış olduğumuz binding sayesinde otomatik olarak sağdaki listView'ın ItemsSource değeri değişiyor ve ilgili yemekler sağdaki listView kontrolünde görüntülenebiliyor. ;)

İlerleyen yazılarımızda da Windows 8 içerisindeki data kontrollerini işlemeye devam ediyor olacağız ve bir sonraki yazımızda Windows 8 ile beraber gelen yeni bir kontrolü inceliyor olacağız. ;)

Görüşmek Üzere



Windows 8 Metro Style Uygulamalarda GridView Kontrolünde Gruplama - C# & XAML

Merhaba Arkadaşlar,

Geçen yazımızda sizlerle Windows 8 Metro Style GridView kontrolünü incelemiştik ve yazımızın sonunda da GridView'ın aslında içerisindeki itemları gruplayarak gösterme gibi bir özelliği olduğundan kısaca bahsederek topu bu makaleye atmıştık. :)

Bir GridView kontrolü içerisindeki elemanları gruplu olarak göstermemiz için yapmamız gereken bazı değişiklikler bulunmakta.

Gruplanmış Data İle Çalışmak

Bu değişikliklerden ilki elimizdeki data ile ilgili. Önceki yazımızda yemek listesi Windows 8 tarafına tek bir liste olarak gelmekteydi. Ancak şimdi gruplama yapacağımız için artık yemek listesinin yemeğin kategorisine göre gruplanmış olarak gelmesi gerekmekte. Bu nedenle servise yaptığımız metot çağırısında bize dönecek olan tip içerisinde bir takım revizyonlara gideceğiz ve aşağıdaki gibi bir dönüş formatı kullanacağız.

[sourcecode lang="csharp"] [DataContract] public class FoodCategory { [DataMember] public string CategoryName { get; set; } [DataMember] public List<Food> Foods { get; set; } } [/sourcecode]

Yemekler için bu şekilde bir dış kategori sınıfı koyduktan sonra gördüğünüz gibi kategori tipi içerisinde de o kategoriye ait olan yemeklerin listesi gelecek.

[sourcecode lang="csharp"] [DataContract] public class Food { [DataMember] public string FoodName { get; set; } [DataMember] public decimal Price { get; set; } [DataMember] public string ImageUrl { get; set; } } [/sourcecode]

Web servis tarafında bu şekilde bir revizyona gittikten sonra artık GetFoods metodunun dönüş tipi de List<Food> yerine List<FoodCategory> olacak.

Evet artık elimizde gruplanmış veriler var ve web servis metodundan verileri çekip GridView kontrolüne bağlayabilir durumdayız.

Not : Her zaman datanın geleceği servislerde gruplama yapma imkanına sahip olamayabiliriz.(Örneğin RSS, veya 3.rd party servisler). Bu gibi durumlarda eğer yine gruplanmış GridView kontrolü ile çalışma gibi bir ihtiyaç olursa Windows 8 tarafında da bu gruplama işlemi yapılabilir. Tabi gelen datanın formatına göre :) Ayrıca biraz performans kaybını göze almak gerekebilir. ;)

GridView Kontrolünde Gruplama

Elimizde gruplanmış datalarımız var ve  GridView kontrolümüz de sahnede hazır. Peki hemen ItemsSource propertysine elimizdeki koleksiyonu versek bizim için gruplanmış olarak gösterir mi ? :)

Bu işlem o kadar da kolay değil. :)  Öncelikle GridView içerisindeki bazı templateları yaratmamız gerekmekte ve elimizdeki datayı da farklı bir tip üzerinden GridView kontrolüne göndermeliyiz. Neyse çok fazla işlemi karıştırmadan adım adım ilerleyelim.

Geçen yazımızda olduğu gibi sahne üzerinde bir GridView kontrolümüz bulunmakta.

[sourcecode lang="xml"] <GridView x:Name="foodGrid" Margin="50,140,15,15"/> [/sourcecode]

İlk olarak GridView kontrolüne elimizdeki gruplanmış dataları nasıl göstermesi gerektiğini bildirmemiz gerekmekte. Bunun için kontrole Visual Studio 2012'den veya Blend üzerinden sağ tıkladığımızda karşımıza şu şekilde bir seçenek çıkmakta.

Bu seçeneğe tıkladıktan sonra artık GridView kontrolünün gruplayarak gösterme templatelarını aktif hale getirmekteyiz ve aşağıda da göreceğiniz gibi "Edit GroupStyle" seçeneği artık aktif hale gelmekte ve bazı templatelar karşımıza çıkmakta.

Aslında tüm yapacağımız buradaki bazı templateları yaratarak GridView kontrolüne elimizdeki itemları nasıl göstermesi gerektiğini bildirmek. Şimdi ilk olarak kategori başlıklarının nasıl görüneceğini belirleyeceğimiz HeaderTemplate ile başlayalım.

[sourcecode lang="xml"] <GroupStyle.HeaderTemplate> <DataTemplate> <TextBlock FontSize="18.667" Text="{Binding CategoryName}"/> </DataTemplate> </GroupStyle.HeaderTemplate> [/sourcecode]

Kategori başlıklarını hallettikten sonra şimdi sıra geldi ilgili kategori içerisindeki elemanların nasıl bir düzende görüneceğine. Bunun için de GroupStyle içerisindeki ItemsPanel template'ını yaratmamız gerekmekte.

[sourcecode lang="xml"] <GroupStyle.Panel> <ItemsPanelTemplate> <VariableSizedWrapGrid Orientation="Horizontal" MaximumRowsOrColumns="3"/> </ItemsPanelTemplate> </GroupStyle.Panel> [/sourcecode]

Yukarıdaki tanımlama ile elimizdeki itemları bir VariableSizedWrapGrid içerisine alıyoruz. (VariableSizedGridView kontrolü aslında bildiğimiz WrapPanel kontrolünün biraz daha gelişmiş hali.Arasındaki farkları başka bir yazımızda inceliyor oluruz. :) ) VariableSizedWrapPanel içerisinde de itemları yatay olarak dizileceğini  ve bir satırda ve sütunda da maksimum 3 eleman olabileceğini MaximumRowsOrColumns propertysi ile belirtiyoruz.

Şimdi sıra geldi elimizde kategorileri nasıl bir layout ile göstereceğimize. Bunu da GridView kontrolü içerisindeki ItemsPanel template'ı ile gerçekleştiriyoruz.

[sourcecode lang="xml"] <ItemsPanelTemplate x:Key="ItemsPanelTemplate"> <StackPanel Orientation="Horizontal" /> </ItemsPanelTemplate> [/sourcecode]

Son olarak ise elimizdeki yemekleri nasıl göstereceğimize. Bunu da önceki yazımızdan da hatırlayacağınız üzere ItemTemplate ile gerçekleştiriyoruz.

[sourcecode lang="xml"] <DataTemplate x:Key="FoodTemplate"> <Grid> <Image HorizontalAlignment="Left" Height="246" VerticalAlignment="Top" Width="250" Stretch="UniformToFill" Source="{Binding ImageUrl}"/> <Border BorderThickness="1" HorizontalAlignment="Left" Height="22.393" Margin="0,223.607,0,0" VerticalAlignment="Top" Width="250" Background="Black" Opacity="0.4"> <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top" Margin="3,2,0,0" Text="{Binding FoodName}"/> </Border> </Grid> </DataTemplate> [/sourcecode]

GridView tarafındaki templating maceralarımızın sonuna geldik ve son olarak elimizdeki datayı GridView kontrolüne bağlama işimiz kaldı. Yazımızın başında klasik ItemsSource propertysine doğrudan elimizdeki datayı veremeyeceğimizden bahsetmiştik. Şimdi bu kısma biraz değinelim.

CollectionViewSource ile Gruplanmış Data Gösterimi

Silverlight tarafıyla daha önce uğraşanlar için CollectionViewSource tipi aslında çokta yabancı olan bir tip değil. Silverlight tarafındayken de elimizdeki verileri gruplu olarak göstermek istediğimizde CollectionViewSource kullanıp bu işlemi hızlı bir şekilde yapabiliyorduk. İşte Windows 8 Metro Style tarafında da yine CollectionViewSource tipini kullanarak bu gruplama işlemini hızlıca yapabiliyoruz. Peki burada CollectionViewSource nasıl bir işlev görüyor derseniz aslında elinizdeki gruplanmış datalar ile GridView arasında bir proxy görevi görüyor ve bizim belirlediğimiz formatta dataları alıp GridView kontrolüne gönderiyor.

CollectionViewSource tipi ile çalışmak da aslında oldukça basit. İlk olarak XAML tarafında resourcelar içerisinde bir CollectionViewSource tipinden instance tanımlıyoruz ve daha sonra GridView'ın ItemsSource propertysinin de bu tipten beslenmesi için binding işlemi yapıyoruz.

[sourcecode lang="xml"] <Page.Resources> <CollectionViewSource x:Name="foodDataSource" ItemsPath="Foods" IsSourceGrouped="True"/> </Page.Resources> [/sourcecode]

Burada IsSourceGrouped propertysine True değer vererek verdiğimiz datanın aslında gruplanmış olduğunu CollectionViewSource tipine bildiriyoruz. Ayrıca ItemsPath propertysine de Foods değerini vererek CollectionViewSource'un kategori içerisindeki yemeklerin hangi property içerisinde bulacağını da bildirmiş oluyoruz.

GridView kontorolü üzerinde yaptığımız binding işlemi ise şu şekilde.

[sourcecode lang="xml"] <GridView x:Name="foodGrid" ItemsSource="{Binding Source={StaticResource foodDataSource}}" Margin="50,140,15,15" ItemTemplate="{StaticResource FoodTemplate}" ItemsPanel="{StaticResource ItemsPanelTemplate}"/> [/sourcecode] Kod tarafına geçtiğimizde ise artık elimizdeki listeyi GridView kontrolüne vermek yerine sayfa içerisinde tanımladığımız CollectionViewSource tipinin Source'una elimizdeki listeyi veriyoruz. [sourcecode lang="csharp"] protected async override void OnNavigatedTo(NavigationEventArgs e) { FoodService.ServiceClient client = new FoodService.ServiceClient(); ObservableCollection<FoodCategory> foodList = await client.GetFoodsAsync(); foodDataSource.Source = foodList; } [/sourcecode] Uygulamamızın sonunda yaptığımız templatingler de dahil olmak üzere oluşan XAML şu şekilde. [sourcecode lang="xml"] <Page x:Class="App4.MainPage" IsTabStop="false" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:App4" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Page.Resources> <CollectionViewSource x:Name="foodDataSource" ItemsPath="Foods" IsSourceGrouped="True"/> <DataTemplate x:Key="FoodTemplate"> <Grid> <Image HorizontalAlignment="Left" Height="246" VerticalAlignment="Top" Width="250" Stretch="UniformToFill" Source="{Binding ImageUrl}"/> <Border BorderThickness="1" HorizontalAlignment="Left" Height="22.393" Margin="0,223.607,0,0" VerticalAlignment="Top" Width="250" Background="Black" Opacity="0.4"> <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top" Margin="3,2,0,0" Text="{Binding FoodName}"/> </Border> </Grid> </DataTemplate> <ItemsPanelTemplate x:Key="ItemsPanelTemplate"> <StackPanel Orientation="Horizontal" /> </ItemsPanelTemplate> </Page.Resources> <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> <GridView x:Name="foodGrid" ItemsSource="{Binding Source={StaticResource foodDataSource}}" Margin="50,140,15,15" ItemTemplate="{StaticResource FoodTemplate}" ItemsPanel="{StaticResource ItemsPanelTemplate}"> <GridView.GroupStyle> <GroupStyle> <GroupStyle.HeaderTemplate> <DataTemplate> <TextBlock FontSize="18.667" Text="{Binding CategoryName}"/> </DataTemplate> </GroupStyle.HeaderTemplate> <GroupStyle.Panel> <ItemsPanelTemplate> <VariableSizedWrapGrid Orientation="Horizontal" MaximumRowsOrColumns="3"/> </ItemsPanelTemplate> </GroupStyle.Panel> </GroupStyle> </GridView.GroupStyle> </GridView> </Grid> </Page> [/sourcecode]

Şimdi uygulamamızı çalıştıralım ve çalışmamızın sonucunda nasıl bir görünüm elde etmişiz görelim :)

Gördüğünüz gibi artık verilerimiz gruplanmış bir şekilde GridView kontrolünde görüntülenebilmekte ve mantıksal gruplar halinde kullanıcıya sunularak kısa bir development eforuyla kullanıcı deneyimi arttırılabilmekteyiz. İlk başlarda template sayısı fazla olduğundan dolayı karmaşıklık olabilir ancak tam olarak templateları anladıktan sonra hemen hızlı bir şekilde gruplamayı uygulamalarınıza entegre edebilirsiniz. ;)

Bir sonraki yazımızda görüşmek üzere.



Windows 8 Metro Style Data Uygulamaları ve GridView Kontrolü - C# & XAML

Merhaba Arkadaşlar,

Windows 8 metro style development konusuna giriş yaptığımız yazılarımızın ardından verdiğimiz kısa aradan sonra kaldığımız yerden serimize devam ediyoruz :). Ara vermemizin sebebi de aslında Windows 8 RP ve Visual Studio 2012 RC sürümlerinin çıkmasını beklememizdi. Kabul ediyorum biraz da benim tembelliğimdi :)

Bu yazımızda ise sizlerle Windows 8 Metro Style Data uygulamalarına giriş yapıyor olacağız ve bu kapsamda da GridView kontrolünü incelemeye başlayacağız. Ancak öncelikle Windows 8 tarafındaki data erişimine bir bakalım.

Wind0ws 8 Metro Style Uygulamalarında Veri Erişimi

Windows 8 tarafında bir data-driven Metro Style Uygulama geliştirmek istediğimizde aslında temelde data çekebileceğimiz 2 kaynak bulunmakta.

Bunlar,

  • Web üzerinde bulunan kaynaklar
  • Database içerisinde saklanan veriler.

Web üzerinden bulunan kaynaklardan kastımız aslında RSS gibi veya REST tabanlı doğrudan HTTP tabanlı isteklerde bulunup yanıtı alabileceğimiz kaynaklar.

Database'den kastımız da database içerisinde bulunan veriler ve bu verilerin Windows 8 Metro Style uygulamalarda kullanılması.

Web üzerinde bulunan kaynaklara erişimi ise WinRT üzerinde asenkron olarak gerçekleştirebilmekteyiz. Bunun nedeni de aslında web üzerindeki kaynağa erişim sırasında uygulamanın UI threadini bloklamamak ve kullanıcıya daha iyi bir kullanıcı deneyimi sunabilmek.

Şimdi database tarafına gelirsek. Elimizde bir WPF uygulamamız olduğunu düşünelim ve bu uygulamayı Windows 8 Metro Style uygulamaya çevirmeye çalışacağımız varsayalım. Aklımıza gelecek sorulardan ilki elimizdeki verileri Windows 8 Metro ortamına nasıl aktaracağımız olacak. Çünkü WPF tarafında code-behind tarafında SqlConnection sql = new SqlConnection(); şeklinde database'e bağlanabiliyorduk. (Bu kullanımın doğru olduğunu savunmuyorum sadece böyle yazıldığını varsayıyorum :) ) Peki Windows 8 Metro tarafında da işler böyle yürüyor mu ?

Cevap hayır :) Öyle direk hayır deme bize nedenlerini söyle diyecekseniz peki o zaman başlıyorum :)

  • Öncelikle yazdığınız uygulamanın ARM işlemcili tabletlerde dahi çalışacağını unutmayın. Bu nedenle database manipülasyonunu bu cihazlar üzerinden yapmak dönen datayı işlemek gibi işlemler sizin uygulamanızın performansını oldukça etkileyecektir. Ayrıca uygulamanız amacını da aşacaktır. Bunun yanında data cacheleme mekanizmaları da bu senaryoda olmayacaktır.
  • İkinci nedenimiz de geliştirdiğimiz uygulamada veri erişim kısmında bir değişiklik olacağı zaman bunu tabletteki uygulamayı güncelleyerek mi yapacağız. :) Sizin uygulamanız belki farklı platformlarda da kullanılıyor ve bir platformdaki istek için database de bazı güncellemeler yaptınız ve aslında bu yaptığınız değişiklik sizin uygulamanızda veriyi gösterme anlamında hiçbirşey ifade etmiyor ancak veri erişim katmanında değişiklik gerekiyor. Bu durumda Marketplace'e uygulamamızın update'ini mi göndereceğiz. Bir update süreci sertifikasyon gibi aşamaları gerektirdiği için belki 1 haftadan önce marketplace'te yer alamayacağını düşünürsek. Sanırım database'e metro style uygulamadan bağlanma hevesiniz bayağı bir azaldı. Gelelim son nedene.
  • Zaten şu anda istesenizde Windows 8 Metro Style tarafında SqlConnection sql = new SqlConnection(); yapamıyorsunuz :). Çünkü öyle bir API yok :D Zaten olsa da yapmamanız gerekir yukarıda bahsetmiş olduğum nedenlerden dolayı. ;)

Not : Yukarıda bahsettiğim nedenler uygulamanızın ana datasına erişimin nasıl yapılması ile ilgiliydi. Yani metro style uygulama ile ilgili bir takım user settinglerini localde saklayabileceğiniz yapılar zaten şu anda WinRT içerisinde mevcut.

Peki elimizde bir database var ve biz bu elimizdeki verileri nasıl dışarıya açacağız ? Cevap oldukça basit : Web Servis :) Peki web servise erişimi nasıl yapacağız ? Bunun da cevabı oldukça basit. Asenkron :) Asenkron işlemlerin yönetiminde de C# 5.0 ile beraber gelen async / await yapısını kullanıyor olacağız. Detaylı bilgi için buraya :)

Bu konsept aslında sırf Metro Style uygulamalar ile sınırlı değil. Eğer elinizde bulunan dataları çeşitli platformlarda kullanmanız gerekiyorsa araya mutlaka bir web servis katmanı alarak dış platformları data access katmanında soyutlamanız doğru bir hareket olacaktır ;)

Şimdi gelelim artık metro style uygulama geliştirme tarafına :)

GridView Kontrolü

Metro Style uygulama geliştirirken en sık kullanacağımız kontrollerden biri de GridView kontrolü. Elimizdeki verileri toplu şekilde göstermek istediğimizde içerisindeki elemanları Grid şeklinde gösterebilen bir kontrol GridView kontrolü. Evet çok fazla uzatmadan artık pratikte görmek için File=>New Project ve Blank Metro Style Application'ı seçerek boş bir uygulama yaratıyoruz.

Uygulama olarak bir restoranımız olduğunu düşünelim ve bu restoran için bir Windows 8 Metro Style uygulama geliştireceğimizi varsayalım. Restoran içerisinde satılan yiyecekler ile ilgili bilgiler ise web servis aracılığıyla geliyor olacak ve biz yemek listesini web servis içerisinde bulunan GetFoods metodu ile alacağız. Bu metot içerisinden dönen Food tipinin içeriği ise şu şekilde.

[sourcecode language="csharp"] public class Food { [DataMember] public string FoodName { get; set; } [DataMember] public decimal Price { get; set; } [DataMember] public string ImageUrl { get; set; } } [/sourcecode]

Şimdi ilk olarak bir GridView kontrolü alalım ve MainPage.xaml içerisine sahneye yerleştirelim.

[sourcecode language="xml"] <Page x:Class="App4.MainPage" IsTabStop="false" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:App4" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> <GridView x:Name="foodGrid" Margin="50,140,15,15"/> </Grid> </Page> [/sourcecode]

Şimdi sıra geldi datayı web servisten çekme kısmına. İlk olarak web servis referansını projemize ekliyoruz.

Advanced butonuna tıkladığımızda asenkron web servis erişiminin bulunduğu bölüme dikkat ;)

Şimdi sıra geldi web servis bağlantısına ve aldığımız dataları GridView kontrolüne bağlamaya. Bu işlemi sayfanın OnNavigated eventi içerisinde gerçekleştiriyor olacağız. OnNavigated metodu MainPage.xaml sayafasına navigasyon gerçekleştiğinde tetiklenmekte.

[sourcecode language="csharp"] protected async override void OnNavigatedTo(NavigationEventArgs e) { FoodService.ServiceClient client = new FoodService.ServiceClient(); ObservableCollection<Food> foodList = await client.GetFoodsAsync(); foodGrid.ItemsSource = foodList; } [/sourcecode]

Gördüğünüz gibi eğer daha önce XAML tabanlı bir platformda (Silverlight,WPF,Windows Phone vb...) geliştirme yaptıysanız kodlar sizin için oldukça tanıdık gelecektir. Windows 8 Metro Style tarafında da genel konsept aslında aynı. GridView kontrolünün ItemsSource propertysine elimizdeki listeyi veriyoruz.

Şimdi F5'e basarak uygulamamızı çalıştıralım ve uygulamamız nasıl görücek bir bakalım.

Sanki tam istediğimiz gibi olmadı :) Nesnelerimiz GridView kontrolü içerisinde göründü ancak bağladığımız Food tipinin sadece ismi ekrana yazıldı. Yani toString metodu çağrıldı.

Daha önce XAML tarafıyla uğraşanlar GridView içerisinde ItemTemplate yaratmadık diyeceklerdir. :)  Çünkü GridView şu anda içerisine verdiğimiz nesneleri nasıl göstereceği konusunda bilgi sahibi değil ;)

ItemTemplate yaratmanın 2 yöntemi var. İlki Visual Studio 2012 ile beraber templateları özelleştirme. Bir diğeri de Expression Blend içerisinden templateları özelleştirme.

Visual Studio 2012 içerisinde yapmak istediğimizde, designer görünümünde kontrole sağ tıkladığımızda tıpkı Expression Blend'de yaptığımız gibi kontrolün templatelarını özelleştirebilmekteyiz.

Bir diğer yöntem de Expression Blend kullanmak. Çünkü artık Expression Blend, Visual Studio 2012 kurulumuyla beraber bilgisayarımıza yüklenmekte ve rahatça kullanabilmekteyiz. Bunun için de değiştirmek istediğiniz sayfaya sağ tıkladığınızda "Open in Blend" 'e basarak ilgili sayfayı Expression Blend içerisinden editleyebilmekteyiz.

Ben eskiden kalma alışkanlıklarımdan dolayı tasarım tarafını daha çok Blend tarafında hallediyorum. Ancak yukarıda göstermiş olduğum gibi siz de isterseniz bu işlemleri Visual Studio 2012 içerisinden gerçekleştirebilirsiniz.

Şimdi geri dönelim konumuza :) GridView kontrolüne içerisindeki her bir nesneyi nasıl göstereceğini söyleyecektik. Bunun için de GridView içerisinde bir ItemTemplate yaratmamız gerekmekte. Biz ItemTempate olarak yemeğin resmini ve resmin altında da yemeğin adını yazıyor olacağız.

[sourcecode language="xml"] <Page x:Class="App4.MainPage" IsTabStop="false" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:App4" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Page.Resources> <DataTemplate x:Key="FoodTemplate"> <Grid> <Image HorizontalAlignment="Left" Height="246" VerticalAlignment="Top" Width="250" Stretch="UniformToFill" Source="{Binding ImageUrl}"/> <Border BorderThickness="1" HorizontalAlignment="Left" Height="22.393" Margin="0,223.607,0,0" VerticalAlignment="Top" Width="250" Background="Black" Opacity="0.4"> <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top" Margin="3,2,0,0" Text="{Binding FoodName}"/> </Border> </Grid> </DataTemplate> </Page.Resources> <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> <GridView x:Name="foodGrid" Margin="50,140,15,15" ItemTemplate="{StaticResource FoodTemplate}"/> </Grid> </Page> [/sourcecode] Şimdi uygulamamızı yeninden çalıştıralım ve neler değişti bir bakalım :)

Tamam kabul ediyorum uygulama biraz fazla akıl çelici oldu :) Ancak gördüğünüz gibi GridView içerisinde ItemTemplate'ı yaratarak istediğimiz şekilde nesneyi gösterebildik.

Data uygulamalarına giriş yaptığımız bu yazımızda sizlerle Windows 8 Metro Style uygulamalarda veri erişiminin nasıl yapılabileceğimizi ve en sık kullanılan data kontrollerinden olan GridView kontrolünü nasıl kullanabileceğimizi incelemiş olduk.

Daha önce  mevcut Windows 8 uygulamaları görenler "yahu bunun böyle gruplanmış halleri oluyor. Mesela zeytinyağlılar bir grupta, tatlılar bir grupta görünüyor" o nasıl oluyor diye sorabilirler :) Bu da diğer yazımızın konusu olsun ;)

Görüşmek Üzere,