İlkay İlknur

just a developer...

Portable Class Library mi ? Universal App Shared Projects mi ?

Microsoft'un son zamanlarda cross-platform uygulama ve kütüphane geliştirme tarafına yaptığı yatırım oldukça fazla. Gerek Xamarin desteğiyle beraber IOS ve Android tarafında olsun gerekse Windows Store ve Windows Phone tarafında yarattığı teknolojilerle olsun tek bir kod yazarak bu kodun farklı platformlarda çalışan uygulamalar arasında paylaştırılması şu anda bir şekilde sağlanmakta. Aslında bakarsanız bu yöntemlerin hiçbiri tam anlamda süper çözümler olmasa da gerektiği noktalarda doğru şekilde kullanıldığında kod paylaşımı konusunda çektiğimiz acıları oldukça azaltmakta. Peki hangisini ne zaman kullanmalıyız ?

Portable Class Libraries

Portable class libraryler aslında uzun zamandır hayatımızda bulunan ve farklı platformlar üzerinde çalışacak kod yazmak istediğimizde kullandığımız yapılardan ilk akla geleni.

PortableSelect

Portable class librarylerin kısıtlarında bir tanesi de içerisinde platform spesifik kod yazmanın mümkün olmaması. Bu yüzden de portable class librarylerde sadece seçtiğiniz platformlar içerisinde ortak olarak kullanılan kütüphanelere erişiminiz var.

 PortableIntersection

Yukarıda gördüğünüz gibi hangi platformları hedef olarak seçerseniz o platformların kesişiminde bulunan kütüphaneleri kullanabiliyorsunuz.

Eğer kütüphaneniz içerisinde platforma özel bir kod çalıştırmak isterseniz o kodun dışarıdan sizin kodunuz içerisine verilmesini sağlamak zorundasınız. Yani dependency injection vb.. yapıları kullanmak zorundasınız. Örneğin, bir ekran açarak dosya seçme işlemi yaptırmak isterseniz şu şekilde bir çözüm geliştirmeniz gerek.

public class MyLibrary
{
    public async Task Foo(IFileProvider provider)
    {
        var file = await provider.SelectFileAsync(); 
        // Dosya uzerinde islemler
    }
}
 
public interface IFileProvider
{
    Task<string> SelectFileAsync();
}
Portable class libraryi yazdıktan sonra bu kütüphaneyi kullanan Windows 8 uygulaması da portable classın belirlediği interface'te bir file provider yaratacak ve bu providerı portable class library içerisine Foo metodunu çağırırken parametre olarak geçecek.
public class WindowsFileProvider : IFileProvider
{
    public async System.Threading.Tasks.Task<string> SelectFileAsync()
    {
        FileOpenPicker picker = new FileOpenPicker();
        var file = await picker.PickSingleFileAsync();
        return file.Path;
    }
}
 
public class MyApp
{
    WindowsFileProvider fileProvider = new WindowsFileProvider();
 
    public async Task ExecuteAsync()
    {
        MyLibrary library = new MyLibrary();
        await library.Foo(fileProvider);
    }
}

Şimdi gelelim shared projects tarafına. Bakalım o tarafta işler nasıl yürüyor.

Universal App Shared Projects

Visual Studio 2013 Update 2 ile beraber gelen Universal App konsepti ve Shared projectler aslında portable class librarylerde bulunan bazı sıkıntıları çözüyorlar.

Aslında öncelikli olarak belirtmem lazım ki portable class library ile shared projectler tamamen ayrı konseptler. Shared projectler aslında universal app içerisinde bulunan ve universal app'in farklı platformlarda çalışacak uygulamaları arasında paylaştırılacak olan assetleri ve kodları bulunduran kısım.

Shared projectleri aslında biraz daha açarsak temel anlamda Visual Studio içerisinde uzun zamandan beri bulunan file link kavramına benziyorlar. Aslında daha yukarı çıkarak bakarsak file link yapısının biraz daha gelişmiş, derlenmiş toparlanmış hali. Yani siz bir dosyayı birden fazla projede de kullanılacak şekilde saklıyorsunuz. Ancak dosyanın fiziksel olarak tek bir kopyası tutuluyor.

Şimdi gelelim shared code içerisinde platform spesifik kod yazma kısmına. Peki biz yukarıdaki dosya açma işlemini shared code içerisinde yapmak isteseydik nasıl yapacaktık ?

Shared project içerisinde platform spesifik kod yazmak istediğimizde #if directivelerini kullanarak olarak platform spesifik kodları yazabiliyoruz. Örneğin,

public class MyLib
{
    public async Task Foo()
    {
        string filePath = String.Empty;
#if WINDOWS_APP
        FileOpenPicker picker = new FileOpenPicker();
        var file = await picker.PickSingleFileAsync();
        filePath = file.Path;
#endif
#if WINDOWS_PHONE_APP
        //Windows Phone spesfik kodlar
#endif
 
        // Dosya uzerinde ortak islemler
    }
}

Gördüğünüz gibi platform spesifik kodları if directiveleri içerisinde yazdık. Yani bizim kodumuz Windows Store App için derlendiğine #if WINDOWS_APP directive içerisinde olan kodlar kodumuzun içerisinde olacak. Aynı şekilde Windows Phone için derlediğinde de #if WINDOWS_PHONE_APP directive'i içerisinde bulunan kodlar yine source kod içerisinde olacak.

Ancak gördüğünüz gibi uygulamanız büyükdükçe #if directive 'leriniz artacak ve kodunuzun yönetimi de oldukça zorlaşacaktır. Şimdi isterseniz ortalığı toparlayalım ve bu iki çözümünde avantajlarına ve dezavantajlarına kısaca bir bakalım.

Portable Class Libraries vs Universal App Shared Projects

Portable class librarylere baktığımızda yapılarının oldukça basit olduğunu görüyoruz. Yani sadece desteklediğiniz platformlardaki kesişen kütüphaneleri kullanabiliyorsunuz ve ötesi yok. Bu kadar basit. Elinizdeki imkanlarla ilerlemek zorundasınız. Bu da aslında bir anlamda size basitlik sağlıyor. Yani kodunuz içerisinde platform spesifik kod yazmıyorsunuz. Ancak platform spesifik kod yazmak istediğinizde de abstraction yaparak dependency injection, IoC container kullanmanız gerekiyor. Bu nedenle portable class libraryler birden fazla platformu destekleyen algoritmalar veya kütüphaneler(SDK) için ideal ortam.

Shared projects tarafında ise portable class library tarafındaki platform spesifik kod yazamama sıkıntısı çözülüyor. Ancak bu çözüm de hoş bir çözüm değil. En azından bana göre :) Uygulamanız büyüdükçe platform spesifik kodlar da büyüyebilir ve karışabilir. Böylece kodunuzun bakımı da zorlaşır. Ancak bir yandan da aynı işlemleri portable class libraries ile yaptığınızda da hem abstraction vs.. derken işiniz daha da uzuyor hem de kodunuz yine karmaşıklaşıyor. Bu nedenle en basit çözüm Universal App geliştirirken shared projectlerle ilerlemek.

Ancak gördüğünüz gibi cross platform uygulama geliştirme konusunda kod paylaşımı hala  daha tam anlamıyla süper bir çözümle başarılmış değil. Şu anki çözümler sadece acımızı bir nebze hafifletiyor.

Umarım faydalı olmuştur.



Windows Runtime Componentlerinde Asenkron İşlemler - C# 5.0

Bir önceki yazimizda Windows Runtime Componentlerini inceledikten sonra simdi sira geldi WinRT Component'leri gelistirme sirasinda karsimiza siklikla çikabilecek olan bir durumu incelemeye. :) Bildigimiz gibi Windows 8 ile beraber gelen WinRT altyapisi içerisinde bulunan pek çok yapi asenkron sekilde çalismak üzere tasarlandi. Hatta bu asenkron altyapiyi kullanmayi kolaylastirmak için de C# 5.0 ile beraber gelen asenkron programlama yeniliklerini kullanmaktayiz.

Hal böyle olunca Windows Runtime Componentleri içerisinde de asenkron olarak çalisacak yapilar gelistirmek artik neredeyse kaçinilmaz bir hal aldi. Bu yazimizin konusu da Windows Runtime Componentleri içerisinde asenkron sekilde çalisacak yapilari nasil gelistirecegimiz ile ilgili.

.NET Framework içerisinde asenkron islem diyince artik bir çirpida aklimiza gelen tip Task tipi olmakta. Önceki yazilarimizdan da hatirlayacagimiz üzere asenkron islemlerin yönetimini Task tipi üzerinden kolaylikla yapabiliyoruz. Peki Windows Runtime Component'i gelistirme tarafina geçtigimizde Task tipi hala daha orada mi yoksa karsimiza baska seyler mi çikiyor hemen durumu bir örnek yaparak inceleyelim.

Örnek olarak basit bir sekilde bir RSS adresinden ilgili contenti asenkron olarak download eden bir metot yazacagiz.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Windows.Foundation;

namespace AsyncWinRTComponent
{
    public sealed class AsyncHelper
    {
        public async static Task<string> DownloadRSSAsync()
        {
            HttpClient client = new HttpClient();

            var result = await client.GetAsync("http://www.ilkayilknur.com/feed");

            return await result.Content.ReadAsStringAsync();
        }
    }
}
Koda baktigimizda artik alistigimiz asenkron implementasyonlardan hiç bir farki yokmus gibi görünüyor :) Öyleyse kodu derleyelim bakalim herhangi bir sorunla karsilasacak miyiz :)

Error 1 Method 'AsyncWinRTComponent.AsyncHelper.DownloadRSSAsync()' has a parameter of type 'System.Threading.Tasks.Task<System.String>' 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 'Task' in the method signature to one of the following types instead: Windows.Foundation.IAsyncAction, Windows.Foundation.IAsyncOperation, or one of the other Windows Runtime async interfaces. The standard .NET awaiter pattern also applies when consuming Windows Runtime async interfaces. Please see System.Runtime.InteropServices.WindowsRuntime.AsyncInfo for more information about converting managed task objects to Windows Runtime async interfaces. C:\Users\ilkayilknur\AppData\Local\Temporary Projects\AsyncWinRTComponent\Class1.cs 39 42 AsyncWinRTComponent

Upps :) Bu hatanin artik ne demek oldugunu biliyoruz bir önceki yazimizdan. Bu demek oluyor ki Task tipi WinRT tarafinda bulunan bir tip degil. Sadece .NET Framework tarafinda bulunuyor ve asenkron olarak gelistirdigimiz  public metotlardan Task tipini dönemiyoruz. Peki ne yapacagiz ?

IAsyncAction ve IAsyncOperation<T> Interfaceleri

Windows Runtime tarafinda asenkron islemler dedigimizde de karsimiza Task tipi yerine IAsyncAction ve IAsyncOperation<T> interfaceleri çikiyor. IAsyncAction interface'i herhangi bir deger döndürmeyen asenkron islemlerin yönetiminde kullanilirken IAsyncOperation<T> interface'i de asenkron islem sonucu bir deger dönülen metotlarda kullanilmakta. Ayni zamanda IAsyncAction interface'i içerisinde yaptiginiz asenkron çagri ile ilgili olarak progress bilgisini de almamiz mümkün degil.

Simdi yapmis oldugumuz örnegimize dönersek asenkron metodumuz içerisinde islem sonlandiktan sonra bir deger döndürdügümüz için IAsyncOperation<T> interface'ini kullanmamiz gerekmekte. Peki kullanimi nasil gerçeklestirecegiz ? Burada en önemli konu bu. Çünkü metodumuzu async modifier'i ile tanimladik. Ancak metottan Task tipi dönemiyoruz ve Windows Runtime Component'i içerisinden de metodu disari açmamiz için de Task tipi yerine IAsyncOperation<T> dönmemiz gerekmekte. Yani isler oldukça karisik. :D

Simdi ilk olarak parça parça ilerleyelim ve yazmis oldugumuz metodu public yerine private olarak tanimlayalim ve metodu Windows Runtime Component'i içerisinde çalisacak olan bir iç metot olarak düsünelim.

private async static Task<string> DownloadRSSAsyncInternal()
{
    HttpClient client = new HttpClient();

    var result = await client.GetAsync("http://www.ilkayilknur.com/feed");

    return await result.Content.ReadAsStringAsync();
}

Evet simdi Windows Runtime Component'imiz basarili bir sekilde derlenebiliyor çünkü Task tipini döndügümüz metodumuzu private olarak tanimladik. (Metot isminin sonuna Internal kelimesini de yerlestirdik ki disari açtigimiz metotta yine DownloadRSSAsync ismini kullanabilelim ;) )

Simdi DownloadAsyncRSS isimli metodumuzu IAsyncOperation<T> dönecek sekilde tanimlayalim ve esas önemli kisma gelelim.

Bu yazdigimiz metot içerisinde de aslinda elimizdeki bulunan DownloadRSSAsyncInternal isimli metottan dönen Task tipini IAsyncOperation<T> interface'ine çevirebilirsek isimizi bitirebiliriz gibi görünüyor ne dersiniz ? Acaba elimizde bulunan bir Task tipini IAsyncOperation<T>'a çevirebilecek bir yapi var midir bakalim.

Iste aradigimiz tam da böyle birsey :) Windows Runtime içerisindeki yapilara baktigimizda içerisinde .NET Framework tipleri ve WinRT tipleri arasinda hizli geçisler yapabilecegimiz pek çok extension metot mevcut. Bu çerçevede elimizde bulunan Task tipinden de IAsyncOperation<T> üretmek için de AsAsyncOperation isimli bir metot WinRT içerisinde bulunmakta. Ayni sekilde elimizde bulunan Task tipinden IAsyncAction üretmemiz de mümkün. Öyleyse yazacagimiz Windows Runtime Component'in son hali su sekilde olacak.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Windows.Foundation;

namespace AsyncWinRTComponent
{
    public sealed class AsyncHelper
    {
        private async static Task<string> DownloadRSSAsyncInternal()
        {
            HttpClient client = new HttpClient();

            var result = await client.GetAsync("http://www.ilkayilknur.com/feed");

            return await result.Content.ReadAsStringAsync();
        }

        public static IAsyncOperation<string> DownloadRSSAsync()
        {
            return DownloadRSSAsyncInternal().AsAsyncOperation();
        }
    }
}

Gördügünüz gibi Windows Runtime Componentleri içerisinde asenkron metotlar yazip disari açmak da oldukça kolay. Özellikle .NET Framework ile WinRT tipleri arasindaki geçisleri yapmak gördügünüz gibi extension metotlarla oldukça kolaylasmis durumda. Bu extension metotlar sadece asenkron programlamada kullandigimiz tipler için degil ayni zamanda Streamler gibi yapilarda da islerimizi oldukça kolaylastirmakta. Tavsiyem eger WinRT tarafinda bir tipte sikisip kaldiysaniz ve bir islemi nasil yapacaginiza tam olarak emin degilseniz ve bu isi .NET Frameworkle hemen çözebileceginizi düsünüyorsaniz elinizdeki Windows Runtime tipini .NET Framework tipine çeviren bir extension metot olup olmadigini mutlaka arastirin ;)

Umarim faydali olmustur.

Hepinize kolay gelsin,

Not: Blogumu RSS veya sosyal sitelerden takip etmekte sikinti çekenler için blogumu mail ile de takip edebilirsiniz. Buradaki linke tiklayarak kaydinizi yapabilirsiniz. 



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 !



C# 5.0 - Caller Info Attributes ile Kolaylaşan INotifyPropertyChanged İmplementasyonu

Windows 8, Windows Phone 7, Silverlight ve WPF ile uygulama gelistirirken kullandigimiz ve MVVM gibi senaryolarda da siklikla basvurdugumuz INotifyPropertyChanged implementasyonu çogu zaman eger bir kod snippeti kullanmiyorsaniz biraz can sikici ve zaman kaybedici bir implemantasyon olabilmekte.

INotifyPropertyChanged interface'ini neden kullandigimizi kisaca hatirlamamiz gerekirse, elimizde bulunan tiplerin binding islemlerinde içlerinde barindirdiklari propertylerde bir degisiklik oldugu durumlarda bagli olduklari UI kontrolü üzerinde durumlarini  güncellemeleri için gerekli olan elemanlari saglamakta INotifyPropertyChanged interface'i.

INotifyPropertyChanged interface'inin içerisine baktigimizda ise çok basit bir sekilde sadece 1 event ile karsilasiyoruz.

namespace System.ComponentModel
{
    public interface INotifyPropertyChanged
    {
        event PropertyChangedEventHandler PropertyChanged;
    }
}

Evet interface implementasyonu aslinda sadece 1 eventin tetiklenmesini gerektiriyor. Bu eventi tetiklerken bir de hangi propertynin degerinin degistigini de eventi tetikleme sirasinda bildirmemiz gerekiyor ki bizim eventimizi dinleyen kontroller degisen propertynin hangisi oldugunu algilayabilsin ve buna göre de sadece degisen propertynin degerini ekranda güncellesin.

Simdi hemen basitçe Insan isminde bir tip tanimlayalim ve bu tip içerisinde Ad ve Soyad isimli property ekleyelim ve bu propertylerde de degisiklik oldugunda bind edildikleri kontrollerde de ilgili degisikliklerin yansitilmasi için bir de INotifyPropertyChanged interface'ini implemente edelim.

public class Insan : INotifyPropertyChanged
{
    private string ad;

    public string Ad
    {
        get { return ad; }
        set
        {
            ad = value;
            RaisePropertyChanged("Ad");
        }
    }

    private string soyad;

    public string Soyad
    {
        get { return soyad; }
        set
        {
            soyad = value;
            RaisePropertyChanged("Soyad");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void RaisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(thisnew PropertyChangedEventArgs(propertyName));
        }
    }
}

Evet implementasyon bu kadar basit. Farketmis oldugunuz ilk sey eminim ki auto-implemented property kullanmayisimizdir. Çünkü burada ilgili propertye deger atanma sirasinda araya girmemiz gerekmekte. Bu nedenle auto-implemented property kullanamiyoruz. Bunun haricinde ise interface içerisinde bulunan eventi gerekli parametrelerle tetiklemek için RaisePropertyChanged isimli bir de yardimci metot yazdik. Bu metotta parametre olarak içerigi degisen propertynin ismini almakta. Daha sonra ise yazmis oldugumuz bu metodu propertylerin setterlari içerisinde çagirmaktayiz.

C# 5.0 - Caller Info Attributes ile Basitlesen Implementasyon

Yukaridaki implementasyona baktigimizda aslinda bize zaman kaybettiren ve interface'in implementasyonunu zorlastiran nokta aslinda RaisePropertyChanged metodunu çagirirken sürekli olarak degisen propertynin ismini vermemiz.

Simdi C# 5.0 ile beraber CallerInfo Attributes konusunu hatirlarsak aslinda Caller Info Attributes bize yapilan bir çagrim  ile ilgili olarak bilgi vermekteydi. Yani çagrim yapilan yerin satiri, bulundugu dosya ve çagrimda bulunan üyenin adi gibi alanlari saglamaktaydi. Sanki çagrim yapan üyenin adi tam bizim ihtiyacimiz olan sey :) O zaman RaisePropertyChanged metodunu su sekilde degistirsek nasil olur bir bakalim :)

public void RaisePropertyChanged([CallerMemberName]string propertyName = null)
{
    if (PropertyChanged != null)
    {
        PropertyChanged(thisnew PropertyChangedEventArgs(propertyName));
    }
}

Gördügümüz gibi bu sekilde artik metodu çagiran üyenin adini C# 5.0 ile beraber gelen Caller Info Attributes ile alabilmekteyiz. Insan tipi içerisinde bulunan propertylerin setterlarinda da artik RaisePropertyChanged metodunu parametre vererek çagirmamiza gerek yok. Çünkü compiler bu parametreyi artik kendisi arka planda ilgili metoda opsiyonel parametre degeri olarak geçirmekte.

Son olarak Insan tipinin içerigi su sekilde olmakta.

public class Insan : INotifyPropertyChanged
{
    private string ad;

    public string Ad
    {
        get { return ad; }
        set
        {
            ad = value;
            RaisePropertyChanged();
        }
    }

    private string soyad;

    public string Soyad
    {
        get { return soyad; }
        set
        {
            soyad = value;
            RaisePropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void RaisePropertyChanged([CallerMemberName]string propertyName = null)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(thisnew PropertyChangedEventArgs(propertyName));
        }
    }
}

Baktigimizda aslinda programalama dili tarafinda gelen bir yenilik bambaska bir tarafta belki de hiç aklimiza gelmeyecek bir noktada gördügünüz gibi isimizi kolaylastiriyor. Iste programlama dillerinin de en güzel yani bu :)

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,



Windows 8 Application Manifest Kavramı ve Package.appxManifest Dosyası

Merhaba Arkadaşlar,

Bir Windows 8 uygulaması geliştirmesi sırasında adını sıklıkla duyacağımız kavramlardan biri de "Application Manifest" kavramı. Geçen yazımızda hatırlarsanız bir Windows 8 Solution'ı içerisindeki itemlardan bahsederken Package.appxManifest isimli bir dosyadan sözetmiştik ve kısaca "geliştirmiş olduğumuz uygulama ile ilgili metadatayı içerisinde barındıran dosyadır" demiştik. Bu yazımızda ise metadata kavramını biraz daha açarak bu dosya içerisindeki kavramları inceliyor olacağız. Çünkü ileriki yazılarımızda kullanacağımız yapılar manifest dosyasında bir takım tanımlamaları yapmamızı gerektiriyor olacak. ;)

Windows 8 Uygulama Metadatası Nedir ?

Öncelikle metadata kavramına yabancı olanlar için metadata ne demektir diye baktığımızda "data about data" tanımıyla karşılaşmaktayız. Biraz akıl karıştırıcı bir tanım olsa da aslında en doğru ve en güzel açıklayan tanımlardan biri olduğunu söyleyebiliriz, yani tuttuğumuz verinin sahip olduğu özellikler. Örneğin database tarafında tuttuğunuz verilerin tipleri(varchar vs..) aslında o verinin metadatasıdır.

Evet bu kadar metadata felsefesi yeterli. :) Windows 8 uygulamasının metadatası da aslında geliştirdiğimiz uygulamanın bir takım özellikleri, tanımlamalarıdır ve Package.appxmanifest isimli dosyada tutulmaktadır. Aslında Windows Phone 7 uygulaması geliştiriyorsanız WMAppManifest.xml dosyasının Windows 8 tarafındaki eşleniğidir Package.appxManifest dosyası.

Bir Windows 8 Application solutionı yarattığımızda Visual Studio'nun üretmiş olduğu Package.appxManifest dosyasına tıkladığımızda aslında bu dosyanın içeriği Xml olmasına rağmen Visual Studio bu dosyanın kolayca editlenebilmesi için bize özel bir arayüz sağlamakta ve tıklandığında bu arayüzü default olarak açmakta.

Manifest dosyasını hızlı bir şekilde editlememizi sağlayan bu ekrana baktığımızda 4 ana bölüme ayrılmış olduğunu görüyoruz. Bunlar,

  • ApplicationUI
  • Capabilities
  • Declerations
  • Packaging

ApplicationUI

ApplicationUI tarafına baktığımızda uygulamamızın daha çok UI taraflı settinglerini belirtmek için kullanabileceğimizi görmekteyiz.

ApplicationUI tabının ilk bölümünde uygulamamızın isimlendirmesi, açıklaması ve uygumanın ilk başlangıcının hangi tip üzerinden yapılacağı belirtilmekte. Yukarıda gördüğümüz gibi uygulama App tipi üzerinden ayağa kaldırılmakta.

Not: Entry Point olarak verilecek olan tiplerin Windows.UI.Xaml.Application tipinden türetilmesi gerekmekte.

ApplicationUI'ın ikinci bölümünde ise karşımıza ilk olarak uygulamamızın destekleyeceği rotationlar sorulmakta. Bu noktada eğer uygulamanızda sadece belirli rotationları destekleyecekseniz buradan ilgili seçimleri yapabilirsiniz. Aksi takdirde tüm rotationların desteklendiği kabul edilmekte.

Bir alt bölüme geçtiğimizde ise uygulamamızın temel olarak kullanılacak olan görsellerinin belirlenebildiği görmekteyiz. Bu görseller, uygulamamızın listelemelerde ve kullanıcının seçimine göre start menüsünde kullanılacak olan small logo, yine start menüsünde kullanılabilecek olan wide logo ve standart logo olmakta. Bunun yanında tilelar üzerinde isim gösterilip gösterilmeyeceği gibi gösterilecekse ne gösterilecek gibi settingler de bu bölümde bulunmakta. Son olarak ise uygulamanızda default olarak kullanılacak olan background ve foreground renkleri de buradan belirlenebilmekte.

ApplicationUI ekranındaki üçüncü ve son kısımda ise Notification ve Splash Screen ile ilgili ayarlar bulunmakta. Burada uygulamanızda Toast ve Lock Screen Notificationlarının desteklenip desteklenmediğini belirtebilir ve notificationlarda kullanılacak badge logoyu da buradan ekleyebilirsiniz.

En son kısımda ise uygulamanız ilk açıldığı sırada gösterilen Splash Screen görselini özelleştirebilirsiniz ve kendi görsellerinizi yerleştirebilirsiniz.

Capabilities

Capabilities tabına geçtiğimizde bu kısımda uygulamamızın içerisinde ihtiyaç duyacağı özellikleri-yetenekleri belirtebileceğimizi görüyoruz. Peki yetenekler derken neleri kastediyoruz ?  Örneğin diyelim ki uygulamanız içerisinde kullanıcı webcam'ini açmak istiyorsunuz. Bunu yapmak için öncelikle manifest dosyasında bu kaynağa ihtiyaç duyacağınızı belirtmeniz gerekiyor. Aksi takdirde istediğiniz kadar implementasyon yapın webcami açamıyorsunuz !  Bu bölüm aynı zamanda Store tarafında kullanıcıya uygulamayı yükletmeden önce "this application requiress webcam access..." şeklinde mesajların verilmesi sırasında da kullanılıyor olacaktır ve kullanıcıdan da bu kaynakları kullanmak üzere onayı alıyor olacaksınız.  Bu nedenle uygulamanız içerisinde implemente ettiğiniz özellikler buradan enable etmeyi unutmayın ;)

Declerations

Declaration tabı ise bizim uygulamamızın dışarıya açılan genişletme noktasıdır. Örneğin uygulamanızın search menüsünde görünüp kullanıcıların sizin uygulamanız içerisinde search yapmasını istiyorsanız buradan ilgili item'ı seçip manifest dosyasına eklemeniz gerekir. Ya da uygulamanızı bir share target olarak belirtip kullanıcıların bazı içerikleri sizin uygulamanızı kullanarak paylaşmasını sağlayabilirsiniz.

Packaging

Manifest dosyamızdaki son tab ise Packaging bölümü. Bu kısımda ise artık uygulamamızı bitirip deployment safhasına geldiğimizde kullanacağımız Package ile ilgili settingleri bu alandan belirleyebiliyoruz. Package'ın görünen isminin ne olacağı, store logosu ve developer sertifikası ile ilgili bilgileri buradan değiştirebilmekteyiz. Package Name ise paketin unique numarası olmakta ve Guid kullanılmakta.

Evet arkadaşlar gördüğünüz gibi bir Windows 8 uygulaması solution'ı içerisindeki en önemli kavramlardan birinin de Application Manifest kavramı olduğunu bu yazımızla beraber görmüş bulunmaktayız. Şimdi artık uygulama geliştirmeye hazırız ve bir sonraki yazımızda artık daha eğlenceli kısımlara geçiyor olacağız. ;)

Görüşmek Üzere,