Silverlight 2.0 ile Twitter ve TwitXR Combo Widget

0 dakikada yazıldı

5894 defa okundu

Düzenle

Bugün sizlerle yeni bir açık kaynak kodlu Silverlight 2.0 uygulamamı
paylaşacağım. Hatırlarsanız bundan aylar önce Silverlight 1.0 ile bir
Twitter
Widget

hazırlamış ve sizlerle kaynak kodlarını paylaşmıştım. Şimdi de 2.0 ile
yeni bir Widget hazırladım. Bu sefer Widget'ın
TwitXR desteği gibi ilginç özellikleri var

Bir Widget hikayesi...

Silverlight 2.0 ile geliştirme yapmanın 1.0'a kıyasla çok sayıda
avantajı var fakat unutmayalım ki artık .NET tarafındayız ve JavaScript
ile olduğu kadar low level kod yazmıyoruz. Ne demek istediğimi makale
boyunca daha net anlayacağınızdan eminim. Peki size neler anlatacağım?

Uygulamanın içindeki kodların açıklamalarını zaten kodlar içerisindeki
yorum satırlarında bulabilirsiniz. Yorum satırlarını İngilizce yazdım
çünkü uygulamayı yurt dışı ile de paylaşacağım. Önemli olan ve benim
özellikle değinmek istediğim noktalar bir Widget hazırlarken
karşılaştığım duruma özel sorunlarla ilgili. Gelin daha fazla konuşmak
yerine sorunlara el atalım.

Twitter API saçmalığı!

Twitter'ın çok güzel bir XML API yapısı var. Sorunlardan ilki bu API
için ister Flash ister Silverlight hiç fark etmez ClientAccessPolicy
dosyası konmamış, yani Cross-Domain-Request yasak! Durum böyle olunca
sunucu tarafında bir proxy oluşturarak veriyi kendi sunucunuzaalıp kendi
Widget'ınıza aktarmanız gerekiyor, ama bunu da yapamıyoruz çünkü şöyle
bir saçmalık mevcut; istemci başına bir saatte 70 request sınırı var.
Eeee? Tüm requestleri benim Web Server'ım yapacak sonuçta tüm
ziyaretçiler için, 70 kesinlikle kabul edilebilir bir sınır değil. Büyük
ihtimal ile Windows uygulamaları falan düşünülmüş.

Sonuç olarak Silverlight 1.0 Widget'da kullandığımız Remote Script
Injection
ile Cross-Domain-Reqest taktiğini Silverlight 2.0 da da
kullanmamız gerek. Dinamik olarak sayfaya bir script tagı ekleyip
twitter sitesinden JavaScript alıp sitemizde çalıştırıyorduk. Parametre
olarak da bizim istediğimiz veriler geliyordu. İşte sorular;

Silverlight 2.0 ile dinamik Script tagları sayfaya nasıl eklenir?

        'Insert our dynamic Script Tag to
get Cross Domain Data

        Dim MyDoc As HtmlDocument = HtmlPage.Document

        Dim ScriptTag =
MyDoc.CreateElement("script")

        ScriptTag.SetAttribute("type", "text/javascript")

        ScriptTag.SetAttribute("src", "http://twitter.com/statuses/user\_timeline/"
& InitParams("twitterid") & ".json?callback=TwitterIncData&count=" &
InitParams("count"))

        MyDoc.Body.AppendChild(ScriptTag)

Yukarıdaki kod ile rahatlıkla dinamik olarak bir Script tagı yaratıp
özelliklerini de ayarlayıp içerisinde bulunduğumuz sayfanın
Body'sine ekleyebiliyoruz. Böylece uzaktaki dosya çağrılacaktır.
Twitter adresinin içindeki parametrelerin konumuzla şimdilik alakası
yok. Ama bu adres üzerinden gönderdiğimiz callback parametresi
Twitter'dan data gelince sayfamızda çalıştırılacak olan JavaScript'in ta
kendisi. Peki bu durumda data gelince çağrılan JavaScript'ten bizim
Silverlight 2.0'ın nasıl haberi olacak?

JavaScript'ten Silverlight 2.0 fonksiyonları nasıl çağrılır?

Buyurun makalemi okuyun :
http://daron.yondem.com/tr/post/a1426eb0-7120-4a66-9d5c-de5027fd59ed

Şimdi veri geldi elimize ama gelen veri JSON! Bunu nasıl olacak da
anlaşılabilir bir hale çevireceğiz ve .NET nesneleri şeklinde
kullanabileceğiz?

JSON verisi Silverlight 2.0'a nasıl alınır?

Buyurun bir makale daha:
http://daron.yondem.com/tr/post/457fbb28-892e-4a37-b7d3-cb297d97020b

Ama ben yukarıdaki makalede anlatılanı yapmadım, JSON'dan çekmek
istediğim veri belli olduğu için ve twitter'ın JSON formatı basit olduğu
için doğrudan aşağıdaki kod ile gelen her JavaScript nesnesine
ScriptObject muamelesi yaptım.

        For x As Integer
= 0 To CInt(InitParams("count")) - 1

            AllData.Add(New
TwitPost(JSON.GetProperty(x).GetProperty("text").ToString,
JSON.GetProperty(x).GetProperty("created_at").ToString,
JSON.GetProperty(x).GetProperty("id").ToString))

        Next

Yukarıda JSON değişkeninin içerisinde doğrudan JavaScript tarafından
gelen JSON objesi bulunuyor. GetProperty metodu ile herhangi bir
diziden istediğimiz öğeyi ve özelliklerini tek tek alabiliyorum.

Bir sonraki sorunumuz hangi Twitter hesabından veri çekeceğimiz Widget'ı
kullananların nasıl karar verebileceği. Bunun için Silverlight 2.0'ın
sayfaya yerleştirildiği Object taglarının parametrelerini
kullanacağız.

Parametreli Silverlight 2.0 dosyaları kullanımı nasıl olur?

Buyurun size bir makale :
http://daron.yondem.com/tr/post/4834596e-b5ec-450f-8e3c-cfba929d958e

Twitter'dan data alma işleminin Widget'ın bulunduğu sayfa tamamen
yüklendikten sonra başlasın istiyoruz. Bun durum data yüklendikten sonra
DOM'a ulaşıyor olmamızdan kaynaklanıyor, eğer sayfa tam yüklenmemişse
daha DOM listeleri sabitlenmemiş olabilir.

HTML / DOM eventlarını Silverlight 2.0 ile nasıl yakalarım?

    Private Sub Page_Loaded(ByVal sender As Object,
ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        Dim MyDoc As HtmlDocument = HtmlPage.Document

        HtmlPage.Window.AttachEvent("onload", AddressOf DocLoaded)

    End Sub

 

    Private Sub DocLoaded(ByVal sender As Object,
ByVal e As EventArgs)

      

    End Sub

Yukarıdaki kod ile yaratmış olduğunuz bir event-handlerı nasıl sayfanın
eventların veya bulduğunuz herhangi bir HTML nesnesinin eventlarına
ekleyebileceğinizi görebilirsiniz. Kullanım şekli epey basit.

Bir sonraki adımda bir TextBlock içerisine farklı formatlarda yazı
eklemek istiyoruz. Bunda zor ne var? diyebilirsiniz :) Ama bir
TextBlock'un Text özelliğine baktığınızda String tipinde olduğunu
görüyorsunuz. Peki buna nasıl bir formatlama bilgisi aktarabiliriz ki?
Aktaramayız :) Aslında TextBlock'un bir de Inlines diye bir dizisi
var. Bunun içerisinde satır içi Item'lar saklanıyor. Eğer Inlines
ile ilgili bir ayarlama yapılmamışsa ve doğrudan Text özelliği set
edilmiş ise arkaplanda otomatik olarak bir Inline Item yaratılarak
bu diziye ekleniyor. Tüm bunlar programatik olarak da yapılabilir.

Bir TextBlock'un içindeki belirli bir metnin rengi programatik olarak
nasıl değiştirilir?

            Dim Span As New
Documents.Run

            Span.Text = AllText.Substring(0,
AllText.IndexOf(FoundURLs.Item(0).Value))

            Span.Foreground = CType(App.Current.Resources("PostTextForeGround"), SolidColorBrush)

            Current.Inlines.Item(0) = Span

            Span = New Documents.Run

            Span.Text = FoundURLs.Item(0).Value

            Span.Foreground = CType(App.Current.Resources("PostTextLinkForeGround"),
SolidColorBrush)

 

            Span.TextDecorations = TextDecorations.Underline

            Current.Inlines.Add(Span)

            Span = New Documents.Run

            Span.Text =
AllText.Substring(AllText.IndexOf(FoundURLs.Item(0).Value) +
FoundURLs.Item(0).Value.Length, AllText.Length -
(AllText.IndexOf(FoundURLs.Item(0).Value) +
FoundURLs.Item(0).Value.Length))

            Span.Foreground = CType(App.Current.Resources("PostTextForeGround"), SolidColorBrush)

            Current.Inlines.Add(Span)

Yukarıdaki kod içerisinde Current değişkeni aslında bir TextBlock.
Bu TextBlock içerisinde URL'i alıp URL'den öncesini ayrı bir Run
olarak, URL'i ayrı bir Run olarak, kalanı da ayrı bir Run olarak
TextBlock'un Inlines dizisine ekliyoruz. Böylece her bir Run
için görsel olarak farklı ayarlar yapabiliyoruz.

Yazımın en başında TwitXR desteği derken ne demek istediğimi biraz
anlatıyım. Twitter ile TwitXR beraber çalışan sitelerdir aslında. TwitXR
üzerine yolladığınız bir resim ve yazı otomatik olarak Twitter'a da
aktarılır. Bizim Widget Twitter'dan Post'ları alırken kontrol edecek
eğer o Post TwitXR'dan gelmişse uygun fotoğrafı da bularak gösterecek.
Tüm bu hikayede benim istediğim nokta TwitXR'dan alınan resim istemciye
yüklenirken yüklemenin durumundan haberdar olmaktı. Yani resmi istedim
ama tam olarak yüklendi mi yoksa indiriliyor mu?

Remote Image yüklerken Progress göstermek!

Başından beridir Remote-Request'e izin verilmiyor ve Policy dosyaları
yok diyoruz! Bu durumda benim normal bir WebClient sınıfı ile resmi
indirmem ve sonra gelen Stream'i Image nesnesine bağlayıp sahneye koyma
şansım yok. Mecburen Image'ı doğrudan Image nesnesine bağlamak
zorundayım, ancak bu şekilde remote resim alabiliyorum. Ama bunu
yaparken de zaten Imaging.BitmapImage sınıfını kullanmak zorundayım
ve bu sınıfın kendine özel bir DownloadProgress'i var :)

 WithEvents PhotoDownload As New
Imaging.BitmapImage

 

    'The Photo for the PhotoFrame has been
downloaded.

    Private Sub PhotoDownload_DownloadProgress(ByVal sender As Object,
ByVal e As
System.Windows.Media.Imaging.DownloadProgressEventArgs) Handles PhotoDownload.DownloadProgress

        If e.Progress = 100 Then

            GetBig(MousePos.Y)

        End If

    End Sub

 

    'Play the anim when the mouse is
on

    Private Sub Clickable_MouseEnter(ByVal sender As System.Object, ByVal e As
System.Windows.Input.MouseEventArgs)

            PhotoDownload.UriSource = New Uri(MyPhoto, UriKind.Absolute)

            Photo.Source = PhotoDownload

    End Sub

Yukarıdaki kod içerisinde PhotoDownload adındaki BitmapImage'e
fotoğrafın URL'ini veriyorum ve sonra da Photo adında Image
UIElement nesneme Source olarak veriyorum. Böylece Silverlight
resmi BitmapImage ile indirerek Image nesnesine bağlayıp göstermeye
çalışıyor. Bu esnada BitmapImage'ın DownloadProgress'i
çalışıyor. İlginç bir şekilde bu Progress event'ı içerisindeki Progress
özelliği 1 ile 0 arasında olması gerekirken ya 0 ya da 100 döndürüyor.
Normalde 0 = indirilemedi ve 1 = indirildi anlamına gelmeliydi. Sanırım
bu bir BUG :) Her neyse bir işimizi şimdilik halletik. Unutmayın
buradaki Progress WebClient'taki biri Double değil, Integer. Yani
aslında bir Progress değil de Status değeri veriyor.

Şeffaf uygulama ve Overlay Sorunu

Aslında uygulama fonunu şeffaf yapmak çok kolay. Buyurun makalesi :
http://daron.yondem.com/tr/post/b334e195-feb7-4411-a77d-b6f07d482068

Esas sorun ben şeffaf olan yerlerin sadece şeffaf gözükmesini değil aynı
anda o şeffaflığın arkasındaki HTML'in de kullanılabilir olmasını
istiyorum. İşte bu olmuyor! Hedefim Widget içerisinde herhangi bir
Post'un fare ile üzerine gelince yana doğru sayfanın üzerine taşacak
şekilde uygulamanın genişlemesi ve orada da postun fotosunun gözükmesi.
Tabi tüm uygulama gelişmeyecek sadece fotoğrafın gözükeceği bir kısım
açılacak. Şeffaf fon kullanıldığında görsel olarak bir sorun yok gibi
gözükse de bir bakıyorsunuz ki şeffaf olmasına rağmen uygulama alanınız
fotoğrafın gösterileceği yerleri de kapsadığı yani sayfaya taştığı için
o kısımlardaki HTML kontrolleri çalışmıyor. Bu konu maalesef Flash'ta
daha iyi çözülmüş durumda, Flash'ta şeffaf olan yerler gerçekten şeffaf
:(

Peki nasıl çözeriz, dinamik olarak Silverlight uygulamasının sayfadaki
kapladığı alanı yine kodlarımız ile düzenlememiz gerek. Silverlight'ın
OBJECT taglarına bir ID değeri vererek bunun üzerinden OBJECT'in
genişliğini değiştirebiliriz.

        HtmlPage.Document.GetElementById("TwitterSLWidget").SetAttribute("width", "360px")

Bu kod ile kullandığımız OBJECT tagları aşağıdaki gibi.

                <object style="position:absolute; z-index: 2;" id="TwitterSLWidget" data="data:application/x-silverlight-2,"

                    type="application/x-silverlight-2">

                    <param name="source" value="ClientBin/TwitterWidget.xap" />

                    <param name="initParams" value="twitterid=daronyondem,count=10,twitxrid=daronyondem"
/>

                    <param name="onerror" value="onSilverlightError" />

                    <param name="background" value="Transparent" />

                    <param name="pluginbackground" value="Transparent" />

                    <param name="windowless" value="true" />

                    <param name="background" value="white" />

                    <param name="minRuntimeVersion" value="2.0.31005.0" />

                    <param name="autoUpgrade" value="true" />

                    <a href="http://go.microsoft.com/fwlink/?LinkID=124807"
style="text-decoration: none;">

                        <img src="http://go.microsoft.com/fwlink/?LinkId=108181"
alt="Get
Microsoft Silverlight"

                            style="border-style: none" />

                    </a>

                </object>

Widget'ı nasıl kullanırız?

Birazdan kaynak kodları ile beraber Widget'ı sizinle paylaşacağım. Ama
onun öncesinde hemen Widget'ı nasıl kullanırız ona bakalım.

            <div id="TwitterSLWidgetHost">

                <object style="position:absolute; z-index: 2;" id="TwitterSLWidget" data="data:application/x-silverlight-2,"

                    type="application/x-silverlight-2">

                    <param name="source" value="ClientBin/TwitterWidget.xap" />

                    <param name="initParams" value="twitterid=daronyondem,count=10,twitxrid=daronyondem"
/>

                    <param name="onerror" value="onSilverlightError" />

                    <param name="background" value="Transparent" />

                    <param name="pluginbackground" value="Transparent" />

                    <param name="windowless" value="true" />

                    <param name="background" value="white" />

                    <param name="minRuntimeVersion" value="2.0.31005.0" />

                    <param name="autoUpgrade" value="true" />

                    <a href="http://go.microsoft.com/fwlink/?LinkID=124807"
style="text-decoration: none;">

                        <img src="http://go.microsoft.com/fwlink/?LinkId=108181"
alt="Get
Microsoft Silverlight"

                            style="border-style: none" />

                    </a>

                </object></div>

Yukarıdaki HTML kodunu sayfanıza yerleştirmeniz gerekiyor. Özellikle
koyu olan yerlere dikkat. daronyondem yerine kendi Twitter ve
TwitXT hesaplarınızın adlarını yazmanız gerek. count kısmına da
koç Post gözüksün istiyorsanız onu yazabilirsiniz. OBJECT ve DIV
taglarının ID'leri çok önemli. Bu ID'ler kodlarda kullanılıyor, eğer
değiştirirseniz kodları da tekrar düzenleyip XAP dosyasını Compile
etmeniz gerekecektir.

       function TwitterIncData(object)

        {

        document.getElementById("TwitterSLWidget").Content.Page.IncData(object);

        }

Son olarak yukarıdaki kodu da sayfanızda uygun bir JavaScript dosyasına
veya tagları arasında koymanız ve XAP dosyasını sunucuya kopyalamanız
yeterli olacaktır.

Kaynak Kodlar

Tüm projenin kaynak kodlarını aşağıdaki adresten indirebilirsiniz. Proje
epey karışık oldu, özellikle Remote Script Injection kullandığımız için
Cross-Browser uyumluluğu konusunda sıkıntılar var. Diğer yandan Overlay
konusunda da farklı tarayıcılarda sorunlar var. O nedenle şimdilik ben
ancak IE 7 desteği sunabiliyorum, uğraşacak pek zaman olmadı. Eğer siz
uygulamayı diğer tarayıcıları da destekleyecek şekilde modifiye
ederseniz beni haberdar etmeniz yeterli. Böylece mini bir açık kaynak
projesi olmuş olur.

Makaledeki tüm kodlar VB :) çünkü uygulamadan kesip yapıştırdım.
Uygulamayı da malum VB ile yazdım :) C#'cılara selamlar :)

Silverlight 2.0 Twitter / TwitXR Widget
Kaynak Kodlar ve Proje - 15102008_1.rar (558,89
KB)

Hepinize kolay gelsin.