İ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 !



Yorum Gönder


Yorumlar

  • profile

    Enis CIFTCI

    • 15
    • 4
    • 2013

    Emeğinize sağlık. Çok güzel. Makalelerinizi dikkatle takip ediyorum..

  • profile

    Vahit

    • 5
    • 4
    • 2013

    Ellerinize sağlık...

  • profile

    Erhan

    • 11
    • 1
    • 2013

    Eline sağlık gayet iyi bir makale olmuş.