https://www.buraksenyurt.com/Burak Selim Şenyurt - WPF2018-11-09T13:05:29+00:00Matematik Mühendisi Bir Bilgisayar Programcısının NotlarıBurak Selim SenyurtBlogEngine.Net Syndication Generatorhttps://www.buraksenyurt.com/opml.axdBurak Selim SenyurtMatematik Mühendisi Bir Bilgisayar Programcısının Notlarıtr-TRBurak Selim Şenyurt0.0000000.000000https://www.buraksenyurt.com/post/Data-Binding-Islemlerinde-Converter-Kullanc4b1mc4b1Data Binding İşlemlerinde Converter Kullanımı2014-08-24T06:40:00+00:00bsenyurt<p><a href="https://www.buraksenyurt.com/pics/Fuel%20level.jpg"><img style="background-image: none; float: right; padding-top: 0px; padding-left: 0px; margin: 4px 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Fuel level" src="/pics/Fuel%20level_thumb.jpg" alt="Fuel level" width="220" height="241" align="right" border="0" /></a>Merhaba Arkadaşlar,</p>
<p>Daha <a href="https://www.buraksenyurt.com/post/WPF-Uzerinde-Data-Bindinge28093-Retro-Bakc4b1s-Acc4b1sc4b1" target="_blank">önceki yazılarımızdan birisinde</a><em>(Data-Binding Retro Bakış Açısı)</em> özellikle <strong>WPF</strong><em>(Windows Presentation Foundation)</em>, <strong>Windows Phone</strong>, <strong>WF</strong><em>(Workflow Foundation) </em>gibi <strong>XAML</strong> tabanlı ara birimlerin sıklıkla kullanıldığı noktalarda <strong>veri bağlama</strong><em>(Data Binding)</em> işlemlerinin temellerini kavramaya çalışmış ve çok basit bir örnek ile konuyu irdelemiştik.</p>
<p>Bu yazımızda ise, veri bağlama işlemleri sırasında dönüştürücü tiplerden<em>(Converters)</em> nasıl yararlanabileceğimizi incelemeye çalışacağız. Bu güzel kabiliyet sayesinde aslında var olan çalışma zamanı veri bağlama işlemlerine müdahale edebilmekteyiz ki bu, geliştirici açısından oldukça önem arz eden bir konudur. Öyleki, geliştiricinin standart basma kalıpların dışına çıkarak hareket edebilmesine olanak sağlamakta.</p>
<p>Standart olarak kullanılan veri bağlama tekniklerinde bilindiği üzere kontrolün bir özelliğinin, bağlanılan veri tipinin bir özelliğine eşleştirilmesi işlemi söz konusudur ve bu noktada genellikle içeriğin <strong>string</strong> tipli olarak ele alındığına şahit oluruz. Bir başka deyişle veriyi göstermek amacıyla geliştirdiğimiz senaryolarda ağırlıklı olarak <strong>Context</strong>, <strong>Text</strong> gibi nitelikler veri sunumu için kullanılmaktadır.</p>
<p>Ancak bazı senaryolarda<em>(ki edindiğim tecrübelere göre özellikle WF tarafında)</em> gelen veri tipinin string tabanlı bir kontrol niteliği yerine farklı tipten olan bir kontrol niteliğine bağlanması istenebilir. Örneğin bir kontrolün <strong>visibility</strong> niteliğinin gelen verinin durumuna göre etkinleştirilmesi veya arka plan renginin veriye göre farklılaştırılması vb. İşte bu gibi gereksinimlerde, <strong>Converter</strong> tipler devreye girerek, bağlanan veri değerinin, kontrol niteliğinin istediği asıl tipe dönüştürülmesinde rol oynamaktadır.</p>
<p>Dilerseniz konuyu biraz daha iyi kavrayabilmek adına basit bir senaryo üzerinden ilerlemeye çalışalım. <strong>WPF</strong> tabanlı olarak geliştireceğimiz örnek uygulamamızda ilk etapta aşağıdaki gibi bir <strong>POCO</strong><em>(Plain Old CLR Objects) </em>tipinin söz konusu olduğunu düşünelim.</p>
<p><a href="https://www.buraksenyurt.com/pics/dbcvrtr_1.png"><img style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 4px 0px; display: inline; padding-right: 0px; border-width: 0px;" title="dbcvrtr_1" src="/pics/dbcvrtr_1_thumb.png" alt="dbcvrtr_1" width="289" height="219" border="0" /></a></p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">namespace UsingConverters
{
public class Vehicle
{
public int VehicleId { get; set; }
public string Name { get; set; }
public int FuelLevel { get; set; }
}
}</pre>
<blockquote>
<p><em>Örnekte Converter tiplerinin kullanımını ele almak istediğimizden basitlik adına söz konusu tipe <strong>INotifyPropertyChanged</strong> arayüzü(Interface) uygulanmamıştır.</em></p>
</blockquote>
<p><strong>Vehicle</strong> sınıfı içerisinde <strong>int</strong> tipinden <strong>VehicleId</strong>, <strong>FuelLevel</strong> ve <strong>string</strong> tipinden <strong>Name</strong> özellikleri<em>(Property)</em> bulunmakta. Bu sınıfa ait nesne örneklerinden oluşan bir koleksiyona ait verilerin ise, aşağıdaki <strong>XAML</strong> içeriğine sahip <strong>WPF</strong> penceresinde gösterilmek istendiğini düşünelim.</p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><Window x:Class="UsingConverters.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="600" Loaded="Window_Loaded">
<Grid>
<ListBox x:Name="lstVehicles" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<Label
Content="{Binding Path=VehicleId}"
FontWeight="Bold" FontSize="16"/>
<Label
Content="{Binding Path=Name}"/>
<Label Height="24"
HorizontalAlignment="Left"
Background="CadetBlue"
Width="{Binding Path=FuelLevel}"
Content="{Binding Path=FuelLevel}"
/>
<Separator Width="500"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window></pre>
<p><strong>ListBox</strong> bileşeni için standart bir <strong>Data Binding</strong> işlemi gerçekleştirilmektedir. Bu nedenle <strong>ItemsSource</strong> özelliği <strong>{Binding}</strong> olarak işaretlenmiştir. <strong>DataTemplate</strong> bileşenine baktığımızda ise <strong>VehicleId</strong>, <strong>Name</strong> ve <strong>FuelLevel</strong> özellikleri için çeşitli kontrol niteliklerine<em>(Control Attribute)</em> atamalar yapıldığı görülmektedir. Örneğin aracın adı Label kontrolünün <strong>Content </strong>niteliğine bağlanmıştır. Benzer durum <strong>VehicleId</strong> ve <strong>FuelLevel</strong> özellikleri için de geçerlidir.</p>
<p><strong>FuelLevel</strong> özellik değerinin bağlanmasında ise iki niteliğe atama yapıldığı görülmektedir. Bunlardan birisi <strong>Content</strong> niteliğidir ve aslında benzin değerinin sayısal karşılığını göstermektedir. Diğer yandan <strong>Width</strong> niteliği de bu sayısal değere bağlanmış ve benzin miktarının görsel olarak boyutu değişen bir yatay bar şeklinde ifade edilmesi sağlanmıştır.</p>
<p>Örnek veriyi doldurabilmek için <strong>Window</strong> kontrolünün <strong>Loaded</strong> olay metodunda gerekli bazı düzenlemeler yapılmıştır. Bu kod içeriği aşağıdaki gibidir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System.Collections.Generic;
using System.Windows;
namespace UsingConverters
{
public partial class MainWindow
: Window
{
List<Vehicle> vehicles = null;
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
vehicles = new List<Vehicle>
{
new Vehicle{ VehicleId=1, Name="Su Todoroki", FuelLevel=75},
new Vehicle{ VehicleId=2, Name="Migel Kamino", FuelLevel=50},
new Vehicle{ VehicleId=3, Name="Francesco Bernulli", FuelLevel=45},
new Vehicle{ VehicleId=4, Name="Meytır", FuelLevel=60},
new Vehicle{ VehicleId=5, Name="Naycıl", FuelLevel=90},
new Vehicle{ VehicleId=6, Name="Şimşek", FuelLevel=23},
new Vehicle{ VehicleId=7, Name="Şolet", FuelLevel=85}
};
lstVehicles.DataContext = vehicles;
}
}
}</pre>
<p><strong>vehicles</strong> isimli <strong>List<T></strong> koleksiyonu bir kaç <strong>Vehicle </strong>nesne örneğine sahiptir ve <strong>Window_Loaded</strong> olay metodu içerisinde bu koleksiyon içeriği <strong>DataContext</strong> özelliğine set edilmektedir. Uygulamayı bu haliyle çalıştırdığımızda aşağıdak ekran görüntüsündekine benzer bir sonuç ile karşılaşırız.</p>
<p><a href="https://www.buraksenyurt.com/pics/dbcvrtr_2.png"><img style="margin: 4px 0px; display: inline;" title="dbcvrtr_2" src="/pics/dbcvrtr_2_thumb.png" alt="dbcvrtr_2" width="517" height="650" /></a></p>
<p>Aslında pek de fena bir görüntü değil? En azından benim açımdam. Yine de daha iyisi yapılabilir. Örneğin benzin seviylerini göz önüne alalım. Kutuların uzunluklarına bakıldığında araçların benzin oranlarını görsel olarak daha iyi anlayabiliyoruz. Üstelik içerisinde yazan sayısal değerlerde bize iyi bir istatistik sunmakta.</p>
<blockquote>
<p>Peki ya bu yatay bara benzer kontrollerin renklerini benzin değerlerine göre değiştirmek istesek. Söz gelimi yakıt miktarı 25 birimin altına düştüğünde rengi kırmızı olsa veya 75 ile 100 birim arasında iken elverişli anlamına gelebilecek Yeşil renkte olsa.</p>
</blockquote>
<p>Bunun için <strong>Label</strong> kontrolünün <strong>Background</strong> özelliğine uygun bir değeri vermemiz yeterli olacaktır. Ancak bu değeri verirken benzin miktarına göre uygun rengin seçilmesi ve atanması gerekmektedir. Bir başka deyişle bir aracının devreye girmesi ve sayısal olarak tutulan <strong>FuelLevel</strong> değerini, görsel kontrolün niteliğinin istediği tipe dönüştürmesi işlemi icra edilmelidir. Normal şartlar da örneğin bir <strong>Label</strong> kontrolünün arka plan rengini değiştirmek istediğimizde, kod tarafında aşağıdaki tarzda bir yaklaşımı uygularız.</p>
<p>lbl.Background = <strong>new SolidColorBrush(Colors.Red);</strong></p>
<p>Bu kod ifadesinde görüldüğü üzere <strong>Background</strong> niteliği bir <strong>SolidColorBrush</strong> ile zenginleştirilmiş ve kırmızı renkte belirlenmiştir. <strong>Converter</strong> tipi bu tarz bir yaklaşımı uygulamak durumundadır. Yani sayısal tipin aslında arka planın istediği bir <strong>Brush</strong> türevine dönüştürülmesi gerekmektedir. Şimdi aşağıdaki <strong>Converter</strong> tipini projeye ekleyereki işlemlerimize devam edelim.</p>
<p><a href="https://www.buraksenyurt.com/pics/dbcvrtr_3.png"><img style="margin: 4px 0px; display: inline;" title="dbcvrtr_3" src="/pics/dbcvrtr_3_thumb.png" alt="dbcvrtr_3" width="512" height="293" /></a></p>
<p>ve kod içeriği,</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Media;
namespace UsingConverters
{
public class FuelLevelToSolidColorConverter
:IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
int fuelLevel = (int)value;
SolidColorBrush brush = null;
if (fuelLevel <= 25)
brush = new SolidColorBrush(Colors.Red);
else if (fuelLevel > 25
&& fuelLevel <= 50)
brush = new SolidColorBrush(Colors.Orange);
else if (fuelLevel > 50
&& fuelLevel <= 75)
brush = new SolidColorBrush(Colors.LightBlue);
else if (fuelLevel > 75
&& fuelLevel <= 100)
brush = new SolidColorBrush(Colors.DarkGreen);
else
brush = new SolidColorBrush(Colors.White);
return brush;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}
}</pre>
<p><strong>IValueConverter</strong> arayüzünü implemente etmiş olduğumuz <strong>FuelLevelToSolidColorConverter</strong> sınıfı iki metodu ezmek zorundadır. Bunlardan birisi veriden kontrole doğru olan yönde devreye giren <strong>Convert</strong> fonksiyonudur. Söz konusu örnekte bu fonksiyon daha ön plandadır. Nitekim sayısal <strong>int </strong>tipinden olan <strong>FuelLevel</strong> özelliğinin çalışma zamanındaki değerinin, uygun olan bir <strong>SolidColorBrush</strong> tipine dönüştürülmesi sırasında devreye girmektedir.</p>
<blockquote>
<p><strong>.Net Framework</strong> içerisinde yer alan pek çok ve sayısız <strong>arayüz</strong><em>(Interface)</em> sayesinde, var olan davranışları değiştirmek, ortamı genişletmek ve çalışma zamanına ekstra kabiliyetler kazandırmak pekala mümkündür. <strong>IValueConverter</strong> ve <strong>IPropertyNotifyChanged</strong> gibi arayüzler bunlardan sadece ikisidir.</p>
</blockquote>
<p><strong>Convert</strong> metodu devreye girdiğinde metoda gelen değer <strong>object</strong> tipinden olan <strong>value</strong> isimli parametre ile yakalanmaktadır. Bu değer <strong>Convert</strong> metodu içerisinde ele alındıktan sonra uygun bir <strong>SolidColorBrush</strong> üretilmiş ve geriye döndürülmüştür. Convert metodunun dönüş tipi yine <strong>object’</strong> tir.</p>
<p><strong>ConvertBack</strong> metodu ise tahmin edileceği üzere tam ters yönde çalışmaktadır. Yani kontrol içerisindeki ilgili nitelik değerinin, bağlanan veri içeriğine dönüştürülmesi noktasında rol oynamaktadır. Genel olarak çok fazla başvurulan bir metod değildir ve örneğimizde de aslında bir etkinliği bulunmamaktadır. Bu sebepten metoda <strong>value</strong> ismiyle gelen kontrol değişkeni doğrudan <strong>object</strong> tipinden geriye döndürülmektedir.</p>
<blockquote>
<p>Tabi bazı kritik senaryolarda ConvertBack metodunun içeriğinin de yazılması ve kontrol içeriğinin ilgili değerinin bir dönüşüm işlemine tabi tutularak veri kaynağına gönderilmesi söz konusu olabilir. Bu, özellikle Workflow Foundation tarafında tasarlanan Custom Designer kontrolleri için söz konusudur.</p>
<p>Nitekim WF tarafında geliştirilen bu tip kontrollerde, Workflow Designer’ ın üzerinde yapılan kontrol bazlı değişikliklerin arka plandaki bazı tiplerin özelliklerine yansıtılması da gerekebilir.</p>
</blockquote>
<p>Kod tarafında gerekli düzenlemeleri yaptıktan sonra artık yeni <strong>Converter</strong> tipini arayüz tarafında kullanabiliriz. Bunun için <strong>Window</strong> <strong>XAML</strong> içeriğini aşağıdaki gibi modifiye etmemiz yeterli olacaktır.</p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><Window x:Class="UsingConverters.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="600" Loaded="Window_Loaded"
xmlns:local="clr-namespace:UsingConverters"
>
<Window.Resources>
<local:FuelLevelToSolidColorConverter x:Key="FuelLevelToSolidColor"/>
</Window.Resources>
<Grid>
<ListBox x:Name="lstVehicles" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<Label
Content="{Binding Path=VehicleId}"
FontWeight="Bold" FontSize="16"/>
<Label
Content="{Binding Path=Name}"/>
<Label Height="24"
HorizontalAlignment="Left"
Background="{Binding Path=FuelLevel, Converter={StaticResource FuelLevelToSolidColor}}"
Width="{Binding Path=FuelLevel}"
Content="{Binding Path=FuelLevel}"
/>
<Separator Width="500"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window></pre>
<p>Dikkat edilmesi gereken ilk nokta <strong>FuelLevelToSolidColorConverter</strong> tipinin <strong>XAML</strong> içeriğinde bir <strong>Resource</strong> olarak belirtilmiş olmasıdır. <strong>local</strong> ön eki ile başlayan takıya dikkat edildiğinde, bu <strong>Resource’</strong> un ilerleyen elementlerde de kullanılabilmesini sağlamak amacıyla bir de <strong>Key</strong> değeri verildiği görülmektedir. <strong>local</strong> takma adı ise <strong>Converter</strong> tipinin bulunduğu <strong>isim alanını</strong><em>(Namespace)</em> işaret etmektedir.</p>
<blockquote>
<p>Resource, Window elementine bağlandığından, Window içerisindeki her alt element tarafından kullanılabilir.</p>
</blockquote>
<p><strong>Converter</strong> tipinin devreye alındığı yer ise <strong>Label</strong> kontrolünün <strong>Background</strong> özelliğidir.</p>
<p><strong>{Binding Path=FuelLevel, Converter={StaticResource FuelLevelToSolidColor}}</strong></p>
<p>kullanılan ifadede yer alan <strong>Converter</strong> özelliğine atanan değer ile, ilgili <strong>Label</strong> kontrolünün <strong>Background</strong> özelliğine yapılan veri bağlama operasyonlarında, <strong>FuelLevelToSolidColor</strong> takma adı ile belirtilen <strong>Resource’</strong> un işaret ettiği <strong>IValueConverter</strong> türevinin devreye gireceği ifade edilmektedir.</p>
<p>Buraya kadar anlatıklarımızdan yola çıkarsak <strong>Converter</strong> tipinin ve ilgili fonksiyonlarının çalışma şekli aşağıdaki şekilde görüldüğü gibidir.</p>
<p><a href="https://www.buraksenyurt.com/pics/dbcvrtr_5_1.png"><img style="margin: 4px 0px; display: inline;" title="dbcvrtr_5" src="/pics/dbcvrtr_5_thumb_1.png" alt="dbcvrtr_5" width="575" height="274" /></a></p>
<blockquote>
<p>.Net Framework tarafında IValueConverter arayüzünü uygulayan Built-In converter tipler de bulunmaktadır. Visual Studio arabirimindeki Object Browser yardımıyla bu tipler incelenebilir.</p>
<p><a href="https://www.buraksenyurt.com/pics/dbcvrtr_6.png"><img style="margin: 4px 0px; display: inline;" title="dbcvrtr_6" src="/pics/dbcvrtr_6_thumb.png" alt="dbcvrtr_6" width="299" height="230" /></a> </p>
</blockquote>
<p>Yapılan son değişikliklere göre uygulamanın yeni çalışma zamanı çıktısına ait sonuçlar şu şekilde olacaktır.</p>
<p><a href="https://www.buraksenyurt.com/pics/dbcvrtr_4.png"><img style="margin: 4px 0px; display: inline;" title="dbcvrtr_4" src="/pics/dbcvrtr_4_thumb.png" alt="dbcvrtr_4" width="522" height="673" /></a></p>
<p>Sanırım Şimşeğin en kısa sürede pit alanına girmesi ve benzin alması grerekiyor. Gaza fena yüklenmiş belli ki.</p>
<p>Görüldüğü üzere söz konusu kontroller yakıt seviyesine göre arka plan renklerini değiştirmiş ve görsel açıdan kullanıcı deneyimi biraz daha iyi olan bir sonuç ortaya çıkmıştır. Siz de farklı senaryolarda farklı <strong>Converter</strong> tiplerini geliştirmeyi deneyerek antrenmanlar yapabilirsiniz. <strong>IValueConverter</strong> arayüzü sayesinde epey bir esnekliğimiz olduğunu fark etmişsinizdir. Böylece geldik bir yazımızın daha sonuna. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>
<p><a href="https://www.buraksenyurt.com/pics/2012%2f10%2fUsingConverters.zip">UsingConverters.zip (65,26 kb)</a></p>2014-08-24T06:40:00+00:00bsenyurtDaha önceki yazılarımızdan birisinde(Data-Binding Retro Bakış Açısı) özellikle WPF(Windows Presentation Foundation), Windows Phone, WF(Workflow Foundation) gibi XAML tabanlı ara birimlerin sıklıkla kullanıldığı noktalarda veri bağlama(Data Binding) işlemlerinin temellerini kavramaya çalışmış ve çok basit bir örnek ile konuyu irdelemiştik.https://www.buraksenyurt.com/pingback.axdhttps://www.buraksenyurt.com/post.aspx?id=586ebc1b-c899-40f4-a143-9e59079440205https://www.buraksenyurt.com/trackback.axd?id=586ebc1b-c899-40f4-a143-9e5907944020https://www.buraksenyurt.com/post/Data-Binding-Islemlerinde-Converter-Kullanc4b1mc4b1#commenthttps://www.buraksenyurt.com/syndication.axd?post=586ebc1b-c899-40f4-a143-9e5907944020https://www.buraksenyurt.com/post/WPF-Uzerinde-Data-Bindinge28093-Retro-Bakc4b1s-Acc4b1sc4b1WPF Üzerinde Data Binding– Retro Bakış Açısı2014-06-18T16:55:00+00:00bsenyurt<p><a href="https://www.buraksenyurt.com/pics/retro_car-1590.jpg"><img style="float: right; margin: 4px 0px; display: inline;" title="retro_car-1590" src="/pics/retro_car-1590_thumb.jpg" alt="retro_car-1590" width="200" height="267" align="right" /></a>Merhaba Arkadaşlar,</p>
<p>Bizim dünyamızda zaman hızla akar ve eskiler eskide kalıp, yerini yeniler almaya başlar. Her ne kadar uzun ömürlü kavramlar söz konusu olsa da genel itibariyle yazılım dünyası böyledir. Bazen durup geriye bakar, eskiden nasıl yaptığımızı hatırlar, sonra yenisine dönerek bir kıyaslama yaparız. İşte bu yazımızda yıllarca eski stilde geliştirme yapmış klasik bir .Net yazılımcısının gözünden, yenilikçi bir konuya<em>(ki çıkalı da çok çok çoook zaman olmuştur) </em>bakmaya çalışacağız. Buyrun bakalım.</p>
<p><strong>XAML</strong> doğduğundan beri gerek <strong>WPF(Windows Presentation Foundation)</strong>, gerek <strong>Silverlight</strong>, gerek <strong>Windows Phone</strong> tarafı olsun pek çok yeniliği ve farklı geliştirme bakış açılarını da beraberinde getirmiş oldu. Bu alanlardan birisi de özellikle kontrol odaklı <strong>veri bağlama(Data Binding)</strong> stratejileri üzerinedir. Bu anlamda pek çok ve farklı veri bağlama tekniğini bulmak mümkün.</p>
<p>Doğruyu söylemek gerekirse yeni nesil veri bağlama işlemleri daha kolay olmasına karşın klasik stilde programlama yapanlara biraz yabancı gelebilmektedir. İşte bu yazımızda klasik bir <strong>Windows</strong> <strong>Forms</strong> geliştiricisi olarak, anladığımız kadarı ile <strong>Data</strong> <strong>Binding</strong> kavramına giriş yapmaya çalışıyor olacağız. Olayı ilk önce klasik yaklaşım modeline göre ele almakta fayda var. Aslında klasik yaklaşım modelinden yenilikçi <strong>XAML</strong> modeline geçiş yaparak artıları görmeye çalışacağımızı ifade edebiliriz.</p>
<h1>Senaryo</h1>
<p>Senaryomuzda <strong>WPF</strong> tabanlı bir <strong>Windows</strong> uygulaması söz konusudur. <strong>Window</strong> kontrolü üzerinde yer alan <strong>TextBox</strong>, <strong>TextBlock</strong> gibi kontroller, <strong>Product</strong> tipinden bir nesne örneğinin özellikleri ile ilişkilendirileceklerdir. Product tipi ilk etapta basit bir <strong>POCO(Plain Old CLR Object)</strong> sınıfı olarak tasarlanmalıdır. Buna göre çalışma zamanında <strong>Product</strong> nesne örneklerinde veya kontrol üzerinden yapılan değişikliklerin, karşı tarafa da yansıtılması istenmektedir. Yani senkronizasyon çift taraflı olarak başarılı bir şekilde sağlanabilmelidir.</p>
<h1>İlk Tasarım</h1>
<p><strong>WPF</strong> tabanlı uygulamamızda yer alan <strong>MainWindow</strong> nesnesinin ilk hali aşağıdaki gibidir.</p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><Window x:Class="HowTo_FundementalsOfBinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="175" Width="400" Loaded="Window_Loaded_1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
</Grid.RowDefinitions>
<TextBlock Text="Product ID" Grid.Column="0" Grid.Row="0"/>
<TextBlock Text="Product Name" Grid.Column="0" Grid.Row="1"/>
<TextBlock Text="Product Price" Grid.Column="0" Grid.Row="2"/>
<TextBlock x:Name="txtProductId" Grid.Column="1" Grid.Row="0"/>
<TextBox x:Name="txtName" Grid.Column="1" Grid.Row="1" Margin="2,2,2,2"/>
<TextBox x:Name="txtListPrice" Grid.Column="1" Grid.Row="2" Margin="2,2,2,2"/>
<Button x:Name="btnChange" Grid.Column="1" Grid.Row="3" Content="Change" Width="60"
HorizontalAlignment="Right" Margin="2,2,2,2" Click="btnChange_Click_1"/>
</Grid>
</Window></pre>
<p><a href="https://www.buraksenyurt.com/pics/ub_1.png"><img style="margin: 4px 0px; display: inline;" title="ub_1" src="/pics/ub_1_thumb.png" alt="ub_1" width="419" height="191" /></a></p>
<p>Tasarıma göre pencere üzerinde yer alan kontroller görsel olarak konumlandırılmış ve özellikle kod tarafında erişilebilirlikleri için <strong>x:Name</strong> <strong>nitelikleri(attribute)</strong> ile zenginleştirilmişlerdir.</p>
<h1>Binding Olmadan Önce</h1>
<p>Eğer <strong>XAML</strong> tarafındaki zengin veri bağlama seçeneklerinin olmadığını düşünürsek, bu durumda büyük ihtimalle aşağıdaki gibi bir kodlama gerçekleştiririz.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System.Windows;
namespace HowTo_FundementalsOfBinding
{
public partial class MainWindow
: Window
{
Product computer = null;
public MainWindow()
{
InitializeComponent();
}
private void btnChange_Click_1(object sender, RoutedEventArgs e)
{
// örnek olarak computer nesne örneğinin ListPrice özelliğinin değeri arttırılır
computer.ListPrice += 10;
// computer nesne örneğinin ListPrice özelliğinin yeni değeri, yapılan değişiklik üzerine ilgili kontrolün text özelliğine YENİDEN atanır
txtListPrice.Text = computer.ListPrice.ToString();
}
private void Window_Loaded_1(object sender, RoutedEventArgs e)
{
// computer isminde Product tipine ait nesne örneklenir
computer = new Product
{
ProductId = 10934
, Name = "HP Compaq 1024X"
, ListPrice = 999
};
// örneğe ait özelliklerin değerleri Window üzerindeki kontrollerin Text özelliklerine set edilir.
txtProductId.Text = computer.ProductId.ToString();
txtName.Text = computer.Name;
txtListPrice.Text = computer.ListPrice.ToString();
}
}
}</pre>
<p>Uygulamanın çalışma zamanına ait örnek bir ekran görüntüsü aşağıdaki gibidir. Düğmeye her basışta <strong>ListPrice</strong> değeri artacak ve sonuç ilgili <strong>TextBox</strong> kontrolü içerisine yazılacaktır.</p>
<p><a><img style="margin: 4px 0px; display: inline;" title="ub_2" src="/pics/ub_2_thumb.png" alt="ub_2" width="400" height="175" /></a></p>
<p>Çalışma zamanında üretilen <strong>Product</strong> nesne örneği değerleri, kontrollerin ilgili özelliklerine kod yardımıyla basitçe atanmaktadır. Aslında ortada bir sorun yoktur. Olmayacaktır da. Bu şekilde de programlamaya devam edilebilir. Ancak <strong>XAML</strong> tarafında getirilmiş olan yeni nesil veri bağlama opsiyonlarının bazı artıları vardır. Örneğin<strong> MVVM(Model-View-ViewModel)</strong> gibi desenlere kolayca enjekte olabilirler. Peki ya diğerleri ne olabilir?</p>
<h1>En Basit Haliyle Binding</h1>
<p><strong>XAML</strong> tarafındaki veri bağlama opsiyonlarını en basit haliyle ele aldığımızda aşağıdaki yeni içeriği üretmemiz yeterlidir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false"><Window x:Class="HowTo_FundementalsOfBinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="175" Width="400" Loaded="Window_Loaded_1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
</Grid.RowDefinitions>
<TextBlock Text="Product ID" Grid.Column="0" Grid.Row="0"/>
<TextBlock Text="Product Name" Grid.Column="0" Grid.Row="1"/>
<TextBlock Text="Product Price" Grid.Column="0" Grid.Row="2"/>
<TextBlock Grid.Column="1" Grid.Row="0" Text="{Binding Path=ProductId}"/>
<TextBox Grid.Column="1" Grid.Row="1" Margin="2,2,2,2" Text="{Binding Path=Name}"/>
<TextBox Grid.Column="1" Grid.Row="2" Margin="2,2,2,2" Text="{Binding Path=ListPrice}"/>
<Button Grid.Column="1" Grid.Row="3" Content="Change" Width="60"
HorizontalAlignment="Right" Margin="2,2,2,2" Click="btnChange_Click_1"
/>
</Grid>
</Window></pre>
<p>Dikkat edileceği üzere <strong>x:Name </strong>nitelikleri kaldırılmıştır. Bu bir gereklilik değildir ama senaryomuzun bu kısmında söz konusu değerlere de ihtiyacımız yoktur. Nitekim kod tarafında bu bileşenler erişilmesine ihtiyaç <span style="text-decoration: underline;">bulunmamaktadır</span>. Önemli olan <strong>ProductId, Name, ListPrice</strong> isimli <strong>Product </strong>nesne örneğine ait özellik değerlerinin ilgili kontrollere nasıl bağlandığıdır. <strong>Syntax</strong> oldukça basittir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">Text = {Binding Path=Name}</pre>
<p>Buna göre <strong>Text </strong>özelliğine <strong>X nesne</strong> örneğinin <strong>Name</strong> özelliğinin değeri basılacaktır.</p>
<h1>X Nesne Örneğinin Kim Olduğunu Çalışma Zamanı Nasıl Bilebilir?</h1>
<p>Kod bazında bu işlemi gerçekeştirmek için üst <strong>XAML</strong> kontrollerinden birisinin <strong>DataContext</strong> özelliğine bir <strong>Product</strong> nesne örneğini<em>(computer isimli değişken)</em> atamamız yeterlidir.</p>
<blockquote>
<p>Üst kontrolün set edilen DataContext özelliğinin işaret ettiği veri kümesi, alt kontroller tarafından da erişilir niteliktedir. Buna göre Grid veya StackPanel gibi bir container kontrolünün DataContext özelliğine veri içeren bir liste bağlanması, içeride yer alan alt bileşenlerin de (ve hatta onların altındakilerin) bu veri kümesi ile çalışabilmesi anlamına gelmektedir. Ve tüm bu bağlantı işlemleri XAML tarafında dekleratif olarak yapılabilmektedir.</p>
</blockquote>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System.Windows;
namespace HowTo_FundementalsOfBinding
{
public partial class MainWindow
: Window
{
Product computer = null;
public MainWindow()
{
InitializeComponent();
}
private void btnChange_Click_1(object sender, RoutedEventArgs e)
{
// örnek olarak computer nesne örneğinin ListPrice özelliğinin değeri arttırılır
computer.ListPrice += 10;
// computer nesne örneğinin ListPrice özelliğinin yeni değeri, yapılan değişiklik üzerine ilgili kontrolün text özelliğine YENİDEN atanır
//txtListPrice.Text = computer.ListPrice.ToString();
}
private void Window_Loaded_1(object sender, RoutedEventArgs e)
{
// computer isminde Product tipine ait nesne örneklenir
computer = new Product
{
ProductId = 10934
, Name = "HP Compaq 1024X"
, ListPrice = 999
};
// Tüm Window içeriğindeki XAML kontrollerini computer isimli Product nesne örneğine bağlamış oluyoruz.
this.DataContext = computer;
// örneğe ait özelliklerin değerleri Window üzerindeki kontrollerin Text özelliklerine set edilir.
//txtProductId.Text = computer.ProductId.ToString();
//txtName.Text = computer.Name;
//txtListPrice.Text = computer.ListPrice.ToString();
}
}
}</pre>
<p>Görüldüğü üzere kontrollerin <strong>Text</strong> gibi alanlarına, <strong>computer</strong> isimli örneğe ait özellikler doğrudan kod yardımıyla <span style="text-decoration: underline;">bağlanılmamıştır</span>. Sadece nesne örneğinin oluşturulması ve <strong>this</strong> ile <strong>Window'</strong> un <strong>DataContext</strong> özelliğine <strong>set</strong> edilmesi yeterli olmuştur.</p>
<p><a href="https://www.buraksenyurt.com/pics/ub_3.png"><img style="margin: 4px 0px; display: inline;" title="ub_3" src="/pics/ub_3_thumb.png" alt="ub_3" width="400" height="175" /></a></p>
<h1>Özellik Değeri Değiştiğinde?</h1>
<p>Bir önceki ekran görüntüsüne bakıldığında <strong>XAML</strong> tabanlı yapılan veri bağlama işleminin sorunsuz çalıştığı düşünülebilir. Ancak küçük bir problem vardır. Düğmeye basarak <strong>computer</strong> isimli değişkene ait <strong>ListPrice</strong> değerini arttırdığımızda <strong>TextBox</strong> kontrolü içerisindeki verinin güncellenmediğine şait oluruz.</p>
<p><a href="https://www.buraksenyurt.com/pics/ub_4.png"><img style="margin: 4px 0px; display: inline;" title="ub_4" src="/pics/ub_4_thumb.png" alt="ub_4" width="531" height="515" /></a></p>
<p>Demek ki <strong>TextBox</strong> bileşenini gerçek anlamda <strong>Product</strong> tipinden nesne örneğine bağlayabilmiş değiliz. Çözümsel yaklaşım olarak, <strong>Product</strong> nesne örneğinin ilgili özelliklerinde olabilecek değişiklikler sonucunda, ilgili görsel kontrollerin bir şekilde uyarılması ve içeriklerinin güncellenmesi gerektiği düşünülebilir. Yine klasik stilde olaya yaklaşırsak <strong>Product</strong> tipini şu hale getirmemiz işe yarayabilir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">namespace HowTo_FundementalsOfBinding
{
public class Product
{
public int ProductId { get; set; }
private string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
txtName.Text = value;
}
}
public decimal ListPrice { get; set; }
}
}</pre>
<h1>txtName Nereden Geliyor?</h1>
<p><strong>x:Name </strong>niteliklerini kaldırmıştık hatırlayacağınız gibi. Hadi bunu geçtik diyelim. Ya <strong>Product</strong> tipi bir <strong>Class</strong> <strong>Library</strong> içerisinde ise ve aslında başka projelerde de kullanılacaksa ve o projelerde <strong>TextBox</strong> kontrolleri yoksa!? <strong>Name</strong> değerinin bir <strong>Windows</strong> <strong>Phone</strong> uygulamasında <strong>TextBlock </strong>içerisine basılması söz konusu iken başka bir <strong>XAML </strong>bazlı uygulama da farklı bir kontrolde gösterilmesi istenirse...</p>
<p>Demek ki özelliklerde olan değişiklikleri, görsel ortama bildirirken kontrolden, adından, tipinden vs tamamen bağımsız olabilmeliyiz. İşte bu, <strong>INotifyPropertyChanged</strong> isimli <strong>arayüzün<em>(Interface)</em></strong> neden var olduğunun açık bir ifadesidir. Dolayısıyla <strong>Product</strong> tipinin içeriğini şu hale getirdiğimizi düşünebiliriz.</p>
<p><a href="https://www.buraksenyurt.com/pics/ub_5.png"><img style="margin: 4px 0px; display: inline;" title="ub_5" src="/pics/ub_5_thumb.png" alt="ub_5" width="327" height="429" /></a></p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System.ComponentModel;
namespace HowTo_FundementalsOfBinding
{
public class Product
: INotifyPropertyChanged
{
private int _productId;
public int ProductId
{
get { return _productId; }
set
{
if (_productId == value)
return;
_productId = value;
// Dış dünyayı ProductId özelliğinin değerinin değiştiğine dair bilgilendir
OnPropertyChanged("ProductId");
}
}
private string _name;
public string Name
{
get { return _name; }
set
{
if (_name == value)
return;
_name = value;
// Dış dünyayı Name özelliğinin değerinin değiştiğine dair bilgilendir
OnPropertyChanged("Name");
}
}
private decimal _listPrice;
public decimal ListPrice
{
get { return _listPrice; }
set
{
if (_listPrice == value)
return;
_listPrice = value;
// Dış dünyayı ListPrice özelliğinin değerinin değiştiğine dair bilgilendir
OnPropertyChanged("ListPrice");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
// Özellik değiştiğine dair bir Event yüklendiyse bunu tetikle
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}</pre>
<p>Buna göre kod tarafında <strong>computer</strong> örneğine ait özelliklerde bir değişiklik olduğunda, <strong>Window</strong> üzerinde veriye bağlanmış olan kontrollerin ilgili içeriklerinin de değiştiği gözlemlenecektir. Diğer yandan tam tersi durumda söz konusudur. Yani kontrol üzerindeki değerlerde bir değişiklik yapıp, odağı farklı bir bileşene kaydırırsak<em>(tab tuşuna basmamız dahi bunun için yeterli olacaktır),</em> bu durumda kontrollere bağlanan nesne örneğinin özellikleri de otomatik olarak güncellenir. Aşağıdaki ekran görüntüsünde bu durum irdelenmiştir.</p>
<p><a href="https://www.buraksenyurt.com/pics/ub_6.png"><img style="margin: 4px 0px; display: inline;" title="ub_6" src="/pics/ub_6_thumb.png" alt="ub_6" width="601" height="600" /></a></p>
<h1>Biraz Revizyon</h1>
<p><strong>Product</strong> tipine ait özelliklerin <strong>set</strong> bloklarında değişikliğe neden olan özellik adlarının, <strong>OnPropertyChanged</strong> metoduna <strong>string</strong> olarak geçirildiği dikkatinizden kaçmamıştır. Aslında biraz daha güvenli bir yol tercih edilebilir. Yani <strong>string</strong> tipte özellik adlarını vermekten kurtulabiliriz. Nasıl mı? İşte aşağıdaki kod parçasında görüldüğü gibi.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.ComponentModel;
using System.Linq.Expressions;
namespace HowTo_FundementalsOfBinding
{
public class Product
: INotifyPropertyChanged
{
private int _productId;
public int ProductId
{
get { return _productId; }
set
{
if (_productId == value)
return;
_productId = value;
// Dış dünyayı ProductId özelliğinin değerinin değiştiğine dair bilgilendir
OnPropertyChanged(()=>ProductId);
}
}
private string _name;
public string Name
{
get { return _name; }
set
{
if (_name == value)
return;
_name = value;
// Dış dünyayı Name özelliğinin değerinin değiştiğine dair bilgilendir
OnPropertyChanged(()=>Name);
}
}
private decimal _listPrice;
public decimal ListPrice
{
get { return _listPrice; }
set
{
if (_listPrice == value)
return;
_listPrice = value;
// Dış dünyayı ListPrice özelliğinin değerinin değiştiğine dair bilgilendir
OnPropertyChanged(()=>ListPrice);
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
// Özellik değiştiğine dair bir Event yüklendiyse bunu tetikle
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
protected virtual void OnPropertyChanged<T>(Expression<Func<T>> propertySelector)
{
var memberExpression = propertySelector.Body as MemberExpression;
if (memberExpression != null)
{
OnPropertyChanged(memberExpression.Member.Name);
}
}
}
}</pre>
<p>Dikkat edileceği üzere özelliklerin <strong>Set</strong> bloklarında yapılan <strong>OnPropertyChanged</strong> metod çağrılarında, <strong>lambda(=>)</strong> operatörü kullanılmış ve değer olarak <strong>string</strong> yerine tipe ait özellik adları gönderilmiştir<em>(Bu noktada Development ortamında intelli-sense özelliğinin de çalıştığını ifade edebiliriz)</em></p>
<h1>Size Düşen</h1>
<p>Böylece geldik bir yazımızın daha sonuna. Bu yazımızda <strong>veri bağlama(Data Binding)</strong> operasyonlarının bir kaç temel noktasını daha iyi bir şekilde anlamaya çalıştık. Size tavsiyem <strong>XAML</strong> tarafındaki <strong>Binding</strong> ifadelerinde kullanılabilen diğer özelliklerin ne anlama geldiklerini ve hangi amaçla kullanıldıklarını öğrenmeye çalışmanız olacaktır. Söz gelimi <strong>Mode</strong> niteliğine <strong>OneWay</strong> değerinin atanması ile <strong>TwoWay</strong> verilmesi arasındaki fark nedir? Ya da <strong>OneWayToSource</strong> ne işe yaramaktadır. Hatta orada <strong>Converter’</strong> lar ile ilişkili bir durum da söz konusudur. <strong>Converter’</strong> lara neden ihtiyaç duyarız ki?</p>
<p>Bir sonraki yazımızda görüşünceye dek hepinize mutlu günler dilerim.</p>
<p>H<a href="https://www.buraksenyurt.com/pics/2012%2f10%2fHowTo_FundementalsOfBinding.zip">owTo_FundementalsOfBinding.zip (77,96 kb)</a></p>2014-06-18T16:55:00+00:00wpfwindows presentation foundationdata bindingxamlbsenyurtXAML doğduğundan beri gerek WPF(Windows Presentation Foundation), gerek Silverlight, gerek Windows Phone tarafı olsun pek çok yeniliği ve farklı geliştirme bakış açılarını da beraberinde getirmiş oldu. Bu alanlardan birisi de özellikle kontrol odaklı veri bağlama(Data Binding) stratejileri üzerinedir. Bu anlamda pek çok ve farklı veri bağlama tekniğini bulmak mümkün.https://www.buraksenyurt.com/pingback.axdhttps://www.buraksenyurt.com/post.aspx?id=9d651181-9bcb-4f1f-9fa5-7c2740d247e91https://www.buraksenyurt.com/trackback.axd?id=9d651181-9bcb-4f1f-9fa5-7c2740d247e9https://www.buraksenyurt.com/post/WPF-Uzerinde-Data-Bindinge28093-Retro-Bakc4b1s-Acc4b1sc4b1#commenthttps://www.buraksenyurt.com/syndication.axd?post=9d651181-9bcb-4f1f-9fa5-7c2740d247e9https://www.buraksenyurt.com/post/ObservableCollectione28099-c4b1-AnlamakObservableCollection’ ı Anlamak2014-05-01T13:59:00+00:00bsenyurt<p><a href="https://www.buraksenyurt.com/pics/Formspring.me.jpg"><img style="background-image: none; float: right; padding-top: 0px; padding-left: 0px; margin: 4px 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Formspring.me" src="/pics/Formspring.me_thumb.jpg" alt="Formspring.me" width="225" height="225" align="right" border="0" /></a>Merhaba Arkadaşlar,</p>
<p>31 Mart 2013 deki kapanma kararına kadar <strong>Formspring</strong> ‘in sadık kullanıcılarından birisiydim. Her ne kadar anlık bir soru-cevap ortamı olmasa da, takip edenler açısından faydalı bir sosyal ağ idi. Özellikle <strong>Facebook, Twitter</strong> gibi eklentileri de, cevapların farklı sosyal ağlara bağlanmasında önemli rol oynuyordu. Bu sayede verilen cevapların daha fazla kitleye ulaşması mümkündü. Ama maya bir şekilde tutmadı, kullanıcı sayısı git gide azaldı ve sonunda kapatılma kararı verildi<em>.(Şu anda o adrese girmek isterseniz aslında </em><a href="http://new.spring.me/" target="_blank"><em>şu adrese yönleniyor</em></a><em> ve yeni bir oluşumla karşılaşıyorsunuz)</em></p>
<p>İşte o dönemlerde <strong>WCF </strong>tarafında <strong>Interceptor</strong>' ların nasıl kullanıldığına dair bir makale talebi almıştım <strong>Formspring</strong> üzerinden. <a href="https://www.buraksenyurt.com/post/WCF-Interceptors" target="_blank">Onu geçtiğimiz zamanlarda cevaplamayı başardım</a>. Derken bunun ardından benzer bir soru daha gelmişti. <strong>Someone</strong>' dan gelen soru şöyleydi ve henüz cevaplamayı başaramamıştım…</p>
<blockquote>
<p>burak abi merhaba senden wpf de sık kullanılan observablecollection konusunu anlatmanı rica ediyorum mmalesef bu konuda derinlemesine anlatım yapan türkçe kaynak yok saygılarımla başarılar hayırlı işler</p>
</blockquote>
<p>İşte bu makalemizde söz konusu soruya cevap bulmaya çalışıyor olacağız.</p>
<p><strong>WPF<em>(Windows Presentation Foundation)</em></strong> bilindiği üzere <strong>Microsoft .Net Framework 3.0</strong> ile birlikte tanıtılmış bir alt yapı<em>(Infrastructure)</em>. <strong>Windows</strong> tabanlı masaüstü uygulamalarına<em>(ve hatta Browser tabanlı da çalışabiliyorlar) </em>yeni bir soluk getiren yapının <strong>XAML(eXtensible Application Markup Language)</strong> ile olan sıkı bir ilişkisi de bulunmakta. Dolayısıyla anlatacağımız konu aslında çok uzun zamandır var olan bir mevzu, lakin <strong>WPF</strong> tarafına yeni başlayan birisi için de epey yabancı sayılabilir. İşe ilk olarak bu koleksiyona olan ihtiyacı ortaya koyarak başlamakta yarar var.</p>
<h1>Gereksinim</h1>
<p>Günümüz yazılım ürünlerinin pek çoğu ister web tabanlı olsunlar, ister mobil cihaz üzerinde koşsunlar vb, genellikle <strong>Data-Centric</strong><em>(Veri odaklı)</em> olarak geliştirilmekteler. İçerik bir veritabanı sunucusundan<em>(hatta <strong>NoSQL </strong>tabanlı bir kaynak bile olabilir)</em> gelebileceği gibi, bellek üzerinde oluşturulmuş bir koleksiyon veya basit bir <strong>POCO</strong><em>(Plain Old CLR Object)</em> tipi dahi olabilir.</p>
<p>Bu açıdan bakıldığında veri odaklı uygulamaların ön yüzlerinin<em>(User Interface)</em> veri ile olan iletişiminde karşılıklı olarak bir bilgi transferi söz konusudur. Yani arayüzler, veride meydana gelecek en ufak bir değişiklikten haberdar olmak isterlerken, arayüzde meydana gelen değişikliklerin de veri tarafına yansıtılması gibi bir ihtiyaç ortaya çıkmış durumdadır.</p>
<blockquote>
<p>Şimdi burada durup biraz daha derin düşünmemiz gerekiyor. Tarafların birisinde meydana gelen değişiklikler sonucu başka bir tarafın/tarafların uyarılması<em>(Notify edilmesi diyelim)</em> yazılım dünyasında çok sık rastlanan bir durum olsa gerek. İşte bu sebepten zaten bir tasarım kalıbı bile ortaya çıkmış. Observer Design Pattern. Bu konuda daha önceden <a href="https://www.buraksenyurt.com/post/Tasarc4b1m-Desenleri-Observer.aspx" target="_blank">yazdığım bir makaleye şu adresten ulaşabilirsiniz</a></p>
</blockquote>
<h1>Observer Tasarım Kalıbı ile Olan İlişki</h1>
<p>Peki bu desenin konumuzla ilgisi nedir? Sadece kök kelime isim benzerliği olabilir mi? Aslında pek değil. <strong>ObservableCollection'</strong> un iç yapısına bakıldığında <strong>Observer</strong> <strong>Tasarım</strong> <strong>Kalıbını</strong> uyguladığını fark edebiliriz. Çünkü bu koleksiyonun en büyük özelliği, veri bağlı kontroller ile ilişkilendirildiğinde ekleme, çıkartma ve tazeleme gibi işlemlerde uyarı verilmesine zemin hazırlıyor olmasıdır. Bu uyarı genellikle bir arayüz kontrolünün durum değişikliğinden haberdar olması olarak algılanır. Örneğin koleksiyona bir veri eklendiğinde, bu koleksiyon ile ilişkili kontrolün ilgili öğeyi otomatik olarak göstermesi gibi.</p>
<p><strong>ObservableCollection<T> </strong>sınıfı ve çevresinde etkileşimde olduğu tiplerin genel bir fotoğrafı şekilde görüldüğü gibidir.</p>
<p><a href="https://www.buraksenyurt.com/pics/htoc_1.png"><img style="margin: 4px 0px; display: inline;" title="htoc_1" src="/pics/htoc_1_thumb.png" alt="htoc_1" width="638" height="609" /></a></p>
<p><strong>System.Collections.ObjectModel</strong> isim alanı<em>(namespace)</em> içerisinde yer alan <strong>generic</strong> <strong>ObservableCollection<T></strong> sınıf, iki arayüzü<em>(Interface)</em> implemente etmektedir. Bunlardan birisi özellik bazlı<em>(Property Based)</em> değişiklikler sonrası tetiklenecek olayı<em>(Event)</em> uygulatan <strong>INotifyPropertyChanged</strong> iken, diğeri de koleksiyon değişimleri sonrası tetiklenmesi gereken olayı uygulatan <strong>INotifyCollectionChanged</strong> arayüzüdür<em>(Interface)</em> Zaten bu iki arayüzün belirttiği olaylar <strong>ObservableCollection</strong> içerisinde uygulanırken, bağlandıkları kontrolleri uyaracak şekilde tasarlanmışlardır.</p>
<p>Öyleyse <strong>ObservableCollection<T></strong> ın temel amacı bellidir; <strong>Generic T</strong> tipi için söz konusu olan ekleme<em>(Add),</em> silme<em>(Remove) </em>veya yeniden tazeleme<em>(Refresh) </em>gibi işlemlerde bir uyarı(<em>Notify)</em> yayınlamak.</p>
<h1>Örnek</h1>
<p>Konuyu daha net anlamak adına basit bir örnek üzerinden ilerlemeye çalışalım. Öncelikli olarak aşağıdaki sınıf çizelgesinde<em>(Class Diagram)</em> görünen tipleri içeren bir <strong>WPF</strong> uygulaması oluşturduğumuzu düşünelim.</p>
<p><a href="https://www.buraksenyurt.com/pics/htoc_2.png"><img style="margin: 4px 0px; display: inline;" title="htoc_2" src="/pics/htoc_2_thumb.png" alt="htoc_2" width="235" height="309" /></a></p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">namespace HowTo_ObservableCollection
{
public class Book
{
public int BookId { get; set; }
public string Title { get; set; }
public int PageSize { get; set; }
public string Producer { get; set; }
}
}
using System.Collections.ObjectModel;
namespace HowTo_ObservableCollection
{
public class BookList
:ObservableCollection<Book>
{
public BookList()
:base()
{
Add(
new Book
{
BookId = 1
, Title = "Advanced WCF Programming"
, Producer = "Maybe Me"
, PageSize = 1280
}
);
Add(
new Book
{
BookId = 2,
Title = "SOA: from a Developer Vision",
Producer = "Maybe Me",
PageSize = 740
}
);
}
}
}</pre>
<p><strong>BookList</strong>, <strong>ObservableCollection<Book></strong> türevli olacak şekilde tanımlanmış olup içerisindeki yapıcı metod<em>(Constructor)</em> ile bir kaç <strong>Book</strong> nesne örneğinin yüklenmesini sağlamaktadır. <strong>Book</strong> tipi içerisinde çok basit bir kaç özelliğe yer verilmiştir.</p>
<p><strong>BookList</strong> bir <strong>ObservableCollection<T></strong> örneğidir. Bu nedenle veri bağlı kontroller ile ilişkilendirildiğinde ekleme, silme gibi operasyonlar sonrasında bildirimlerde bulunabilir. Bu durumu test etmek ve hangi hallerde koleksiyonun nasıl çalıştığını görmek adına geliştirmekte olduğumuz WPF uygulamasının arayüzünü aşağıdaki gibi tasarlayarak devam edelim.</p>
<p><a href="https://www.buraksenyurt.com/pics/htoc_3.png"><img style="margin: 4px 0px; display: inline;" title="htoc_3" src="/pics/htoc_3_thumb.png" alt="htoc_3" width="564" height="672" /></a></p>
<p><strong>Window</strong> seviyesinde bir <strong>Resource</strong> tanımlanmış ve <strong>BookList</strong> koleksiyonu işaret edilmiştir. <strong>BookList</strong> koleksiyonunun kendisi, <strong>ListBox</strong> kontrolüne bu <strong>static</strong> <strong>resource</strong> yardımıyla <strong>ItemsSource</strong> özelliği üzerinden bağlanmaktadır.</p>
<p><strong>Book</strong> tipine ait özelliklerin, <strong>DataTemplate</strong> içerisindeki kontrollerin <strong>Text</strong> özelliklerine nasıl bağlandığına dikkat etmekte yarar vardır. Bir başka kayda değer nokta ise şudur; <strong>Visual Studio</strong>' nun <strong>WPF Designer</strong>' ı üzerinde çalışılmakta olup, uygulama çalışmadığı halde koleksiyon içerisinde yer alan kitap bilgileri, kontrollerin <strong>Text</strong> özelliklerine bağlanmış ve içerikleri gösterilmiştir.</p>
<p>Lakin burada ayrı bir nokta daha vardır. Eğer <strong>BookList</strong> sınıfını<strong> ObservableCollection<Book></strong> yerine <strong>List<Book></strong> tipinden türetirsek de, az önce belirttiğimiz davranış sergilenecektir. Yani <strong>Visual Studio</strong> tasarım zamanı yine kitap bilgilerini bağlanan kontrollerde gösterecektir. O zaman <strong>ObservableCollection<T></strong> nin henüz kullanım amacı tam olarak tespit edilebilmiş değildir. Eğer <strong>List<T></strong> tipi de yukarıdaki senaryoda aynı davranışı gösterdiyse, neden<strong> ObservableCollection<T></strong> kullanalım ki.</p>
<h1>Neden ObservableCollection<T> Kullanırız ki?</h1>
<p>Gelin örneğimizi biraz daha değiştirelim ve aşağıdaki hale getirelim.</p>
<p><a href="https://www.buraksenyurt.com/pics/htoc_4.png"><img style="margin: 4px 0px; display: inline;" title="htoc_4" src="/pics/htoc_4_thumb.png" alt="htoc_4" width="506" height="617" /></a></p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System.Windows;
namespace HowTo_ObservableCollection
{
public partial class MainWindow
: Window
{
BookList sourceList = null;
public MainWindow()
{
InitializeComponent();
sourceList = ListBoxBooks.ItemsSource as BookList;
}
private void ButtonAdd_Click_1(object sender, RoutedEventArgs e)
{
sourceList.Add(new Book
{
BookId=94,
Title="Starwars Clone Wars",
Producer="Lucas Arts",
PageSize=180
}
);
}
private void ButtonRemove_Click_1(object sender, RoutedEventArgs e)
{
sourceList.RemoveAt(0);
}
private void ButtonChange_Click_1(object sender, RoutedEventArgs e)
{
sourceList[1].Title = "Changed...";
}
}
}</pre>
<p>İlk olarak <strong>ListBox</strong> kontrolünün çalıştığı veri kaynağını <strong>ItemsSource</strong> özelliğini <strong>BookList</strong> tipine <strong>dönüştürerek<em>(cast)</em></strong> elde etmekteyiz. Nitekim ekleme, çıkartma ve özellik değiştirme işlemlerini bu kaynak üzerinden gerçekleştireceğiz.</p>
<p>3 farklı Button kontrolümüz ile <strong>Add, Remove</strong> ve <strong>Property Change</strong> senaryolarını ele almaya çalışıyoruz<em>(Burada özellikle kodun ilgili yerlerine <strong>Breakpoint</strong>' ler koyup <strong>Debug</strong> ederek ilerlememiz de yarar var)</em></p>
<p>İlk olarak <strong>Add</strong> işlemine bakalım. <strong>BookList</strong>' e yeni bir <strong>Book</strong> nesne örneği eklendiğinde veriye bağlanmış olan kontrollerde otomatik olarak bu değişim için haberdar edilecek ve aşağıdaki çalışma zamanı durumu söz konusu olacaktır.</p>
<p><a href="https://www.buraksenyurt.com/pics/htoc_5.png"><img style="margin: 4px 0px; display: inline;" title="htoc_5" src="/pics/htoc_5_thumb.png" alt="htoc_5" width="538" height="518" /></a></p>
<p>Görüldüğü gibi 94 numaralı <strong>Book</strong> nesne örneği koleksiyona eklendikten sonra yeni içerik <strong>ListBox</strong> kontrolüne de anında yansımıştır. Eğer <strong>Remove</strong> işlemini gerçekleştirirsek de benzer bir durum ortaya çıkacak ve <strong>ListBox</strong> kontrolü güncellendiği gibi, kaynak koleksiyondan da söz konusu kitap çıkartılacaktır.</p>
<p><a href="https://www.buraksenyurt.com/pics/htoc_6.png"><img style="margin: 4px 0px; display: inline;" title="htoc_6" src="/pics/htoc_6_thumb.png" alt="htoc_6" width="582" height="184" /></a></p>
<p><strong>Add</strong> sonrası <strong>Remove</strong> işlemi icra edildiğinde ise koleksiyondaki eleman sayısının 1 eksildiği görülecektir. Ayrıca <strong>ListBox</strong> kontrolünden de ilgili Book örneği kaldırılacaktır.</p>
<p><a href="https://www.buraksenyurt.com/pics/htoc_7.png"><img style="margin: 4px 0px; display: inline;" title="htoc_7" src="/pics/htoc_7_thumb.png" alt="htoc_7" width="525" height="263" /></a></p>
<p>Peki <strong>Change</strong> işlemine gelirsek. Aslında <strong>Change</strong> vakasında, koleksiyondaki bir <strong>Book</strong> nesne örneğinin <strong>Title</strong> özelliğinde yapılan değişiklik söz konusudur. Bu durumda aşağıdaki sonuçlar ile karşılaşılır.</p>
<p><a href="https://www.buraksenyurt.com/pics/htoc_8.png"><img style="margin: 4px 0px; display: inline;" title="htoc_8" src="/pics/htoc_8_thumb.png" alt="htoc_8" width="562" height="170" /></a></p>
<p>Dikkat edileceği üzere koleksiyondaki <strong>Book</strong> örneğinin <strong>Title</strong> özelliğinin içeriği <strong>Changed</strong> olarak değişmiştir. <span style="text-decoration: underline;">Ne varki kullanıcı arayüzüne baktığımızda aynı etkinin oluşmadığı görülür</span>. <strong>Title</strong> ilk ve orjinal hali ile kalmıştır.</p>
<p><a href="https://www.buraksenyurt.com/pics/htoc_9.png"><img style="margin: 4px 0px; display: inline;" title="htoc_9" src="/pics/htoc_9_thumb.png" alt="htoc_9" width="525" height="263" /></a></p>
<p>Bu davranış doğaldır. Nitekim <strong>INotifyPropertyChanged</strong> aslında <strong>ObservableCollection<T></strong> tipi için<em>(ki örneğimizde bundan türeyen BookList)</em> için geçerlidir. Ancak yaptığımız değişiklik, aslında bir <strong>Book</strong> nesne örneğinin özelliği üzerinde meydana gelmektedir. Bir başka deyişle <strong>Book</strong> sınıfına <strong>INotifyPropertyChanged</strong> arayüzü implemente edilmediği takdirde, <strong>User Interface</strong>' in de durum değişikliğinden haberdar olması pek mümkün değildir.</p>
<p>Şimdi gelelim önemli bir noktaya; Eğer <strong>BookList</strong>' i <strong>List<Book></strong> tipinden türetirsek, <strong>Add</strong> ve <strong>Remove</strong> işlemleri sonrasında,<strong> User Interface</strong> kontrollerine ait içeriklerin güncellenmediğini görürüz. Şu anda <strong>ObservableCollection<T></strong> ile <strong>List<T></strong> arasında oluşan önemli bir davranış farkını da yakalamış bulunuyoruz.</p>
<p>Sanıyorum <strong>ObservableCollection<T> </strong>tipinin kullanım amacını ve şeklini biraz daha net anlayabilmişizdir. <strong>ObservableCollection<T></strong> bildirim yapmak için gerekli arayüz tanımlamalarını uyguladığından, özellikle veri bağlı kontrollerin söz konusu olduğu senaryolarada, hem bileşenlerin hem de kaynak koleksiyonun <strong>Add,Remove,Refresh</strong> işlemleri sonrası uyarılmasında hazır bir alt yapı sunmaktadır. Örneği test ederken Debug ederek ilerlemenizi ve özellikle <strong>BookList </strong>koleksiyonunu <strong>ListBox<Book> </strong>türevli ele alarak analiz etmenizi öneririm.</p>
<p>Tabi bakabileceğiniz/araştırabileceğiniz başka vakalar da var. Örneğin,</p>
<ul>
<li><strong>ListBox</strong> kontrolünün <strong>Items</strong> özelliği ile görsel içerik de değişiklikler yaparsak ne olur? Bundan asıl koleksiyon<em>(uygulamada <strong>BookList</strong> tipinin çalışma zamanı örneği)</em> içeriği etkilenir mi?</li>
<li>Ya da bu senaryo aslında <strong>Workflow</strong> <strong>Foundation</strong> tarafında özellikle görsel içeriğe sahip olan <strong>Custom Component</strong>’ ler de göz önüne alınabilir mi? Söz gelimi, kullanılabilir <strong>WCF</strong> servislerin listesini bir kaynaktan çekip, <strong>Workflow Component</strong>’ inin içerisinde yer alan bir <strong>ListBox </strong>bileşeninde gösterebilir miyiz? vb…</li>
</ul>
<p>Bu tip soruları da ben size sormuş olayım.</p>
<p>Böylece geldik bir yazımızın daha sonuna. Bir sonraki makalemizde görüşmek dileğiyle hepinize mutlu günler dilerim.</p>
<p><a href="https://www.buraksenyurt.com/pics/2012%2f12%2fHowTo_ObservableCollection.zip">HowTo_ObservableCollection.zip (71,13 kb)</a></p>2014-05-01T13:59:00+00:00design patternobservablecollectionwpfdesign patternsbsenyurtWPF(Windows Presentation Foundation) bilindiği üzere Microsoft .Net Framework 3.0 ile birlikte tanıtılmış bir alt yapı(Infrastructure). Windows tabanlı masaüstü uygulamalarına(ve hatta Browser tabanlı da çalışabiliyorlar) yeni bir soluk getiren yapının XAML(eXtensible Application Markup Language) ile olan sıkı bir ilişkisi de bulunmakta. Dolayısıyla anlatacağımız konu aslında çok uzun zamandır var olan bir mevzu, lakin WPF tarafına yeni başlayan birisi için de epey yabancı sayılabilir. İşe ilk olarak bu koleksiyona olan ihtiyacı ortaya koyarak başlamakta yarar var.https://www.buraksenyurt.com/pingback.axdhttps://www.buraksenyurt.com/post.aspx?id=9f8bd262-7f6b-4e06-bc3e-303772867b5a6https://www.buraksenyurt.com/trackback.axd?id=9f8bd262-7f6b-4e06-bc3e-303772867b5ahttps://www.buraksenyurt.com/post/ObservableCollectione28099-c4b1-Anlamak#commenthttps://www.buraksenyurt.com/syndication.axd?post=9f8bd262-7f6b-4e06-bc3e-303772867b5ahttps://www.buraksenyurt.com/post/Sarki-Sozleri-ve-Eglenceli-ProgramlamaŞarkı Sözleri ve Eğlenceli Programlama2014-01-16T16:36:00+00:00bsenyurt<p><a href="https://www.buraksenyurt.com/pics/scorpions-the-millenium-collection.jpg"><img style="float: right; margin: 4px 0px; display: inline;" title="scorpions-the-millenium-collection" src="/pics/scorpions-the-millenium-collection_thumb.jpg" alt="scorpions-the-millenium-collection" width="260" height="255" align="right" /></a>Merhaba Arkadaşlar,</p>
<p>Geçtiğimiz gün standart olarak <strong>Youtube</strong> üzerinden gerek 80ler, gerek 90lara ait iz bırakan sanatçıları ve şarkılarını izlemekteydim. Çok sık yaptığım şeylerden birisi de bu şarkıları sosyal ağda paylaşmak aslında. Ama bazende şarkıların melodileri dışında sözlerini de mırıldanmaktayım kendi kendime, ki pek çoğumuzun bunu sıkça yaptığından eminim <img class="wlEmoticon wlEmoticon-smile" style="border-style: none;" src="/pics/wlEmoticon-smile_43.png" alt="Smile" /></p>
<p>Fark ettim ki, pek çok şarkının sözünü unutuyorum/unutmuşum. Hatırlamak için de internet üzerinden <strong>Googlelamam</strong> gerekiyor. Gerçi bununla ilişkili belli başlı siteler de var ve onları da kullanabilirim ama elimde basit bir program arayüzü olsa çok daha etkili olabilir.</p>
<p>Mesela bir <strong>Windows Forms</strong> veya <strong>WPF(Windows Presentation Foundation)</strong> uygulaması olsa. Internete bağlanabildiği sürece istediğim sanatçının istenen albümündeki istediğim şarkının sözlerini getirse <img class="wlEmoticon wlEmoticon-winkingsmile" style="border-style: none;" src="/pics/wlEmoticon-winkingsmile_108.png" alt="Winking smile" /></p>
<p>İşte bu amaçla çıktım yola ve basit bir uygulama geliştirmek üzere oturdum bilgisayarımın başına.</p>
<h1>LyricWiki</h1>
<p><a href="http://api.wikia.com/wiki/LyricWiki_lyrics" target="_blank">LyricWiki</a> isimli şarkı sözlerine ait detaylı bir içeriğe sahip olan site, dış dünyaya da servisler aracılığıyla destek vermekte. <strong>SOAP<em>(Simple Object Access Protocol)</em></strong> bazlı servisler kullanılabileceği gibi <strong>REST<em>(Representational State Transfer)</em></strong> <strong>API</strong> tarzındaki hizmetler yardımıyla da şarkı aramaları yapılabilmekte. <strong>Lyrics Wikia</strong> dan örnek servis çağrısı kullanımı,<strong> Linkin Park</strong> gurubu için aşağıdaki gibidir.</p>
<p><a href="http://lyrics.wikia.com/api.php?func=getArtist&artist=Linkin_Park">http://lyrics.wikia.com/api.php?func=getArtist&artist=Linkin_Park</a></p>
<p><a href="https://www.buraksenyurt.com/pics/lyricapi_1.png"><img style="margin: 4px 0px; display: inline;" title="lyricapi_1" src="/pics/lyricapi_1_thumb.png" alt="lyricapi_1" width="548" height="441" /></a></p>
<p>Peki bir şarkının sözlerini nasıl alabiliriz?</p>
<p>Örneğin <strong>Linkin Park’</strong> ın <strong>1997</strong> yılı <strong>Xero</strong> albümündeki <strong>Fuse</strong> isimli şarkının sözlerini <strong>Text, HTML, XML</strong> veya <strong>JSON</strong> formatlarında almak istediğimizi düşünelim. Bu durumda <strong>URL</strong> sorgularımızın aşağıdaki gibi olması yeterlidir. Dikkat edileceği üzere <strong>fmt</strong> parametresinin değiştirilmesi, istenen formatta<em>(HTML, Text, JSON, XML)</em> bir çıktı alınması için yeterlidir.</p>
<p><strong>HTML(Hyper Text Markup Language)</strong></p>
<p><a href="http://lyrics.wikia.com/api.php?func=getSong&artist=Linkin_Park&song=Fuse&fmt=html">http://lyrics.wikia.com/api.php?func=getSong&artist=Linkin_Park&song=Fuse&fmt=html</a> için</p>
<p><a href="https://www.buraksenyurt.com/pics/lyricapi_2.png"><img style="margin: 4px 0px; display: inline;" title="lyricapi_2" src="/pics/lyricapi_2_thumb.png" alt="lyricapi_2" width="640" height="377" /></a></p>
<p><strong>Text</strong></p>
<p><a href="http://lyrics.wikia.com/api.php?func=getSong&artist=Linkin_Park&song=Fuse&fmt=text">http://lyrics.wikia.com/api.php?func=getSong&artist=Linkin_Park&song=Fuse&fmt=text</a> için</p>
<p>"Of course you know what a fuse is... It's a long piece of cord impregnated with gun powder. When you strike a match and light it It burns, fitfully, spiraling to its end At which there is, a little surprise..." From the planet of Krypton Short suit MCs you will be ripped on (ripped on) You fell off and it's my lyric sheet you slipped on Get[...]</p>
<p><strong>XML(eXtensible Markup Language)</strong></p>
<p><a href="http://lyrics.wikia.com/api.php?func=getSong&artist=Linkin_Park&song=Fuse&fmt=xml">http://lyrics.wikia.com/api.php?func=getSong&artist=Linkin_Park&song=Fuse&fmt=xml</a> için</p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><LyricsResult>
<artist>Linkin Park</artist>
<song>Fuse</song>
<lyrics>
"Of course you know what a fuse is... It's a long piece of cord impregnated with gun powder. When you strike a match and light it It burns, fitfully, spiraling to its end At which there is, a little surprise..." From the planet of Krypton Short suit MCs you will be ripped on (ripped on) You fell off and it's my lyric sheet you slipped on Get[...]
</lyrics>
<url>http://lyrics.wikia.com/Linkin_Park:Fuse</url>
<page_namespace>0</page_namespace>
<page_id>459941</page_id>
<isOnTakedownList>0</isOnTakedownList>
</LyricsResult></pre>
<p><strong>JSON(JavaScript Object Notation)</strong></p>
<p><a href="http://lyrics.wikia.com/api.php?func=getSong&artist=Linkin_Park&song=Fuse&fmt=js">http://lyrics.wikia.com/api.php?func=getSong&artist=Linkin_Park&song=Fuse&fmt=js</a> için</p>
<pre class="brush:js;auto-links:false;toolbar:false" contenteditable="false">function lyricwikiSong(){
this.artist='Linkin Park';
this.song='Fuse';
this.lyrics='"Of course you know what a fuse is...\nIt\'s a long piece of cord impregnated with gun powder.\nWhen you strike a match and light it\nIt burns, fitfully, spiraling to its end\nAt which there is, a little surprise..."\n\nFrom the planet of Krypton\nShort suit MCs you will be ripped on (ripped on)\nYou fell off and it\'s my lyric sheet you slipped on\nGet[...]';
this.url='http://lyrics.wikia.com/Linkin_Park:Fuse';
}
var song = new lyricwikiSong();</pre>
<p>şeklinde sonuçlar elde ederiz.</p>
<p>Peki bu tip bir kullanım söz konusu ise <strong>.Net</strong> tarafında ilgili içerikleri kullanarak kendimiz için eğlenceli bir program geliştirebilir miyiz acaba? <img class="wlEmoticon wlEmoticon-winkingsmile" style="border-style: none;" src="/pics/wlEmoticon-winkingsmile_108.png" alt="Winking smile" /></p>
<h1>Örnek Uygulama</h1>
<p>Söz gelimi bir <strong>WPF</strong> uygulaması yazsak ve aradığımız bir şarkı sözünü bulmak için gerekli işlevsellikleri burada sağlamaya çalışsak. Öncelikle aşağıdaki gibi bir arayüz tasarımı ile işe başlayabiliriz diye düşünüyorum.</p>
<p><a href="https://www.buraksenyurt.com/pics/lyricapi_3.png"><img style="margin: 4px 0px; display: inline;" title="lyricapi_3" src="/pics/lyricapi_3_thumb.png" alt="lyricapi_3" width="637" height="438" /></a></p>
<p><strong>WPF</strong> tabanlı uygulamamızın ana formuna ait <strong>XAML</strong> içeriği ise aşağıdaki gibi geliştirilebilir.</p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><Window x:Class="LyricsDotCom.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="600" Width="640">
<StackPanel>
<TextBlock Text="Bir Grup/Şarkıcı adı giriniz" FontWeight="Bold" Margin="2,2,2,2"/>
<TextBox x:Name="txtSinger" Text="Linkin Park" Margin="2,2,2,2" FontWeight="Bold"/>
<Button x:Name="btnFindSinger" Content="Albümlerini Getir" Margin="2,2,2,2" Width="120" HorizontalAlignment="Right" Click="btnFindSinger_Click"/>
<StackPanel Orientation="Horizontal" DataContext="{Binding}" x:Name="panelAlbums">
<ListBox x:Name="lstAlbums" Width="310" ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True" Height="200">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=Name}"/>
<TextBlock Text="{Binding Path=Year}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox x:Name="lstAlbumSongs" SelectionChanged="lstAlbumSongs_SelectionChanged" Width="310" Height="200" ItemsSource="{Binding Path=Songs}"/>
</StackPanel>
<TextBlock x:Name="txtLyric"/>
</StackPanel>
</Window></pre>
<p>Kullanıcılar<strong> text box</strong> kontrolüne bir grup veya şarkıcı adı yazarak işe başlarlar. Düğmeye basıldıktan sonra eğer söz konusu gruba ait bir albüm içeriği varsa, sol taraftaki <strong>ListBox</strong> kontrolüne otomatik olarak doldurlur. Ardından herhangibir albüm seçilir. Seçilen albüm içerisinde yer alan şarkıların listesi ise sağ tarafta yer alan <strong>ListBox</strong> kontrolü içerisinde gösterilir. Kullanıcı buradan herhangi bir şarkı seçtiğinde ise, bu şarkıya ait sözler alt tarafta yer alan <strong>TextBox</strong> bileşeni içerisine basılır.</p>
<p><strong>XAML</strong> içeriğinde görüldüğü üzere <strong>ListBox</strong> kontrolleri aslında birbirleri ile veri bağlanması açısından ilişkilidirler. Bu sebepten dolayı onları içeren <strong>StackPanel</strong> kontrolünün <strong>DataContext</strong> özelliği kullanılmıştır. <strong>lstAlbums </strong>isimli kontrol, doğrudan panele bağlanan veri içeriğini gösterecek şekilde bir <strong>DataTemplate</strong> kullanmaktadır. Buna göre albümlerin adları ve yayınlandıkları yıl bilgileri <strong>lstAlbums</strong> kontrolünde öğeler içerisinde gösterilmektedir. <strong>lstAlbumSongs</strong> ise yine <strong>StackPanel</strong> bileşeninin veri içeriğini kullanmaktadır ancak <strong>Path</strong> özelliğine dikkat edilecek olursa, bağlanan öğelerin <strong>Songs</strong> isimli koleksiyonlarını göstermektedir.</p>
<p><strong>XAML</strong> içeriğindeki veri bağlama işlemleri ile <strong>REST</strong> sorgularının gerçekleştirildiği arka plan kodları ise<em>(ki button arkası diyebilirim doğrudan)</em> aşağıda görüldüğü gibidir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Xml;
using System.Xml.Linq;
namespace LyricsDotCom
{
public partial class MainWindow
: Window
{
#region Genel değişkenler
string singerQuery = @"http://lyrics.wikia.com/api.php?func=getArtist&artist={0}&fmt=xml";
string songQuery = @"http://lyrics.wikia.com/api.php?func=getSong&artist={0}&song={1}&fmt=text";
string proxyName = ConfigurationManager.AppSettings["proxyName"];
string proxyPort = ConfigurationManager.AppSettings["proxyPort"];
string proxyUsername = ConfigurationManager.AppSettings["proxyUsername"];
string proxyPassword = ConfigurationManager.AppSettings["proxyPassword"];
List<Album> albums = null;
WebClient webClient = null;
#endregion
public MainWindow()
{
InitializeComponent();
webClient = GetWebClient();
}
private void btnFindSinger_Click(object sender, RoutedEventArgs e)
{
MemoryStream memoryStream = GetMemoryStream(string.Format(singerQuery, txtSinger.Text));
XmlTextReader reader = new XmlTextReader(memoryStream);
XDocument document = XDocument.Load(reader);
reader.Close();
memoryStream.Close();
if (document.Root.HasElements)
{
albums = new List<Album>();
foreach (var album in document.Root.Elements("albums").Elements("album"))
{
Album albm = new Album();
albm.Artist = txtSinger.Text;
albm.Name = album.Value.ToString();
albm.Year = ((XElement)album.NextNode.NextNode).Value;
albm.AmazonLink = ((XElement)album.NextNode.NextNode.NextNode.NextNode).Value;
List<string> songList = new List<string>();
XElement songs = (XElement)album.NextNode.NextNode.NextNode.NextNode.NextNode.NextNode;
foreach (var item in songs.Elements("item"))
{
songList.Add(item.Value);
}
albm.Songs = songList;
albums.Add(albm);
}
panelAlbums.DataContext = albums;
}
}
private void lstAlbumSongs_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Album selectedAlbum = lstAlbums.SelectedItem as Album;
if (lstAlbumSongs.SelectedItem != null)
{
MemoryStream memoryStream = GetMemoryStream(string.Format(songQuery, selectedAlbum.Artist, lstAlbumSongs.SelectedItem.ToString()));
StreamReader reader = new StreamReader(memoryStream);
txtLyric.Text = reader.ReadToEnd();
reader.Close();
memoryStream.Close();
}
else
txtLyric.Text = string.Empty;
}
private MemoryStream GetMemoryStream(string query)
{
MemoryStream memoryStream = new MemoryStream(webClient.DownloadData(query));
return memoryStream;
}
private WebClient GetWebClient()
{
WebProxy proxy = new WebProxy(proxyName, Convert.ToInt32(proxyPort));
proxy.Credentials = new NetworkCredential(proxyUsername, proxyPassword);
WebClient client = new WebClient();
client.Proxy = proxy;
return client;
}
}
}</pre>
<p><strong>Wikia’</strong> nın <strong>Lyrcis</strong> servisine ait <strong>REST</strong> arayüzüne atılacak sorgular için kod tarafında <strong>WebClient</strong> tipinden yararlanıldığı görülmektedir. Söz konusu sistemde bir de <strong>WebProxy</strong> kullanımı mevcuttur. Nitekim uygulamanın yazıldığı sistemde bir <strong>Proxy</strong> ile internete çıkış gerçekleştirilmektedir. <strong>WebProxy</strong> için gerekli olan <strong>Proxy adı, port numarası, kullanıcı</strong> ve <strong>şifre</strong> bilgileri ise <strong>App.config</strong> dosyasındaki <strong>appSettings</strong> bölümünden <strong>ConfigurationManager</strong> tipi yardımıyla okunmaktadır.</p>
<blockquote>
<p>ConfigurationManager sınıfının kullanılabilmesi için projeye System.Configuration assembly’ ını referans etmeyi unutmayın.</p>
</blockquote>
<p><strong>WebClient</strong> sınıfına ait nesne örneği kullanılarak albüm listesinin alınması ve bir şarkının sözlerinin getirilmesi için iki farklı <strong>REST</strong> sorgusu gönderilmektedir. Sorgu sonuçları bir <strong>MemoryStream</strong> içerisine alınmakta ve duruma bağlı olarak <strong>XmlTextReader</strong> ya da <strong>StreamReader</strong> yardımıyla okunmaktadır.</p>
<p>Uygulamanın en çok zorlayan kısımlarından birisi de, albüm listelerinin getirildiği <strong>XML</strong> içeriğinin nesnel olarak ayırştırıldığı kısmıdır<em>(Parsing)</em>. Nedense <strong>albums</strong> elementi içerisinde alt element olarak <strong>album</strong> elementlerinin olması beklenirken, <strong>albums</strong> elementi ile aynı seviyede kullanılan <strong>album</strong> elementlerinin olduğu bir <strong>XML</strong> şeması söz konusudur <img class="wlEmoticon wlEmoticon-confusedsmile" style="border-style: none;" src="/pics/wlEmoticon-confusedsmile_21.png" alt="Confused smile" /> Neden bu şekilde bir servis üretimi gerçekleştirildiğini pek bilemiyorum<em>(en azından yazının hazırlandığı tarih itibariyle)</em> açıkçası ama bana kalsaydı sanırım şemayı bu şekilde tasarlamazdım.</p>
<p>Uygulamamızda görüldüğü üzere Album isimli bir <strong>POCO(Plain Old Clr Objects)</strong> tipi kullanılmaktadır.</p>
<p><a href="https://www.buraksenyurt.com/pics/lyricapi_4.png"><img style="margin: 4px 0px; display: inline;" title="lyricapi_4" src="/pics/lyricapi_4_thumb.png" alt="lyricapi_4" width="269" height="214" /></a></p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System.Collections.Generic;
namespace LyricsDotCom
{
public class Album
{
public string Name { get; set; }
public string Year { get; set; }
public string AmazonLink { get; set; }
public List<string> Songs { get; set; }
public string Artist { get; set; }
}
}</pre>
<p>Aslında şarkılara <strong>XML, JSON</strong> gibi içerikler ile ulaşılmak istenirse bir <strong>Song</strong> tipinin de tasarlanması düşünülebilir. Özellikle şarkı sözlerinin tamamının bulunduğu web sayfası linki bu şekilde elde edilebilir.</p>
<blockquote>
<p>Lisanslama kuralları gereği bazı şarkı sözlerinin sadece 7de1 inin çekilebildiği belirtilmiştir<em>(</em><a href="http://api.wikia.com/wiki/LyricWiki_API/SOAP" target="_blank"><em>Bu adresteki</em></a><em> Cropped Lyrics başlığını okuyunuz) </em>Dolayısıyla uygulamamızda pek çok şarkı sözü eksik olarak görünmemektedir ama hatırlatıcı olması açısından bu da bir şeydir<em>(Daha iyi bir şarkı söz REST servisini aramaktayım. Siz de arayın <img class="wlEmoticon wlEmoticon-smile" style="border-style: none;" src="/pics/wlEmoticon-smile_43.png" alt="Smile" /> )</em></p>
</blockquote>
<p><strong>Album</strong> tipi içerisinde oldukça yararlı bilgiler bulunmaktadır. Söz gelimi albümün çıkış tarihi ve <strong>Amazon</strong> sitesinden doğrudan arama sorgusu gibi. Dolayısıyla istenirse hemen Amazon sepetinize ekleyebilirsiniz de. Amazon Web Servisler ile konuşan bir ara katman bile olabilir.</p>
<p><a href="https://www.buraksenyurt.com/pics/lyricapi_5.png"><img style="margin: 4px 0px; display: inline;" title="lyricapi_5" src="/pics/lyricapi_5_thumb.png" alt="lyricapi_5" width="640" height="283" /></a></p>
<p>Örneğin <strong>Debug</strong> modda yakadlığımız bir albüm için gelen amazon arama sorgusu aşağıdaki gibidir.</p>
<p><a href="http://www.amazon.com/exec/obidos/redirect?link_code=ur2&tag=wikia-20&camp=1789&creative=9325&path=external-search%3Fsearch-type=ss%26index=music%26keyword=Linkin%20Park%20Underground%204.0">http://www.amazon.com/exec/obidos/redirect?link_code=ur2&tag=wikia-20&camp=1789&creative=9325&path=external-search%3Fsearch-type=ss%26index=music%26keyword=Linkin%20Park%20Underground%204.0</a></p>
<p>Şimdi uygulamamızı test sürüşüne çıkartabiliriz. Bu amaçla <strong>Scorpions</strong> grubuna ait bir parçanın sözlerini çekmeye çalışalım. <strong>“Still loving you”</strong> mesela <img class="wlEmoticon wlEmoticon-winkingsmile" style="border-style: none;" src="/pics/wlEmoticon-winkingsmile_108.png" alt="Winking smile" /></p>
<p><a href="https://www.buraksenyurt.com/pics/lyricapi_6.png"><img style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 4px 0px; display: inline; padding-right: 0px; border-width: 0px;" title="lyricapi_6" src="/pics/lyricapi_6_thumb.png" alt="lyricapi_6" width="644" height="604" border="0" /></a></p>
<p>Tabi restriction nedeni ile sadece bir bölümünü görebildik ama sonuçta geliştirdiğimiz örnekte amacımız <strong>Developer</strong> profili açısından bakıldığında <strong>REST</strong> tabanlı bir servisi basit yöntemler ile nasıl kullanabileceğimiz ve bir <strong>WPF</strong> uygulaması içerisinde ilgili kontrollere nasıl bağlayabileceğimiz idi. Dolayısıyla istediğimiz ürün faydasını tam olarak sağlayamamış olsakta <strong>geliştirme<em>(development)</em></strong> adına bir kaç fikir sahibi olduğumuzu düşünebiliriz.</p>
<h1>Peki bundan sonrası için neler yapılabilir?</h1>
<ul>
<li>Öncelikli olarak <strong>Developer API Key </strong>ile şarkı sözlerinin tamamının çekilebilip çekilemediğine bakılmalıdır ancak pek çok şarkının lisansı henüz alınamadığı için sadece bir kısmı görünecektir.</li>
<li>Şarkılar için <strong>Song</strong> isimli bir <strong>POCO</strong> tip geliştirilip içerisine tüm içeriği gösteren web sayfasına yönlendirme yapacak bağlantının basılması sağlanabilir.</li>
<li>Uygulama bir <strong>ASP.NET</strong> <strong>Web User Control</strong> olarak da sunulabilir.</li>
<li>Var olan uygulamadaki çağrılar <strong>async</strong> ve <strong>await</strong> anahtar kelimeleri ile birlikte değerlendirilip asenkron hale de getirilebilir.
<ul>
<li>Uygulama içerisinde bir <strong>WebBrowser</strong> kontrolü de kullanılarak şarkı içeriğinin tarayıcıda açılması da sağlanabilir. Aşağıdaki gibi <img class="wlEmoticon wlEmoticon-winkingsmile" style="border-style: none;" src="/pics/wlEmoticon-winkingsmile_108.png" alt="Winking smile" /><a href="https://www.buraksenyurt.com/pics/lyric_last.png"><img style="margin: 4px 0px; display: inline;" title="lyric_last" src="/pics/lyric_last_thumb.png" alt="lyric_last" width="640" height="800" /></a></li>
</ul>
Bu kısımları ciddi anlamda düşünmenizi ve yapmaya çalışmanızı öneririm.</li>
</ul>
<h1><strong>Hoşunuza gitti mi? Öyleyse…</strong></h1>
<p>Yazımızın bu kısmına kadar yapmış olduğumuz örnekte görüldüğü gibi internet üzerinden <strong>Web API</strong>’ leri kullanarak dış dünyaya sunulan ücretsiz<em>(ve bazen de kısmen ücretsiz) </em>bilgileri alabilir ve kullanışlı hale getirebiliriz. Tabi bu tip hizmetleri sunan başka alanlarda bulunmaktadır. Örneğin bunlardan birisi <strong>IMDB<em>(InternationalMovieDataBase)</em></strong> dir <img class="wlEmoticon wlEmoticon-winkingsmile" style="border-style: none;" src="/pics/wlEmoticon-winkingsmile_108.png" alt="Winking smile" /> Aşağıdaki örnek kod parçasını yukarıdaki konu anlatımı üzerine kaymak niyetinde sürebilirsiniz. Aynı teknikleri kullanıyoruz ancak farklı bir içeriği ele alıyoruz.</p>
<p><strong>Önce WPF Windows penceresine ait XAML içeriği</strong></p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><Window x:Class="IMBDGadget.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="480">
<StackPanel>
<TextBlock Text="Movie Name" Margin="5,5,5,5" FontWeight="Bold"/>
<TextBox x:Name="txtMovieName" Margin="5,5,5,5"/>
<Button x:Name="btnFind" Content="Find" Width="120" Height="40" Margin="5,5,5,5" HorizontalAlignment="Right" Click="btnFind_Click"/>
<Grid DataContext="{Binding}" x:Name="grdMovie">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Text="IMDB ID" Grid.Row="0" Grid.Column="0" FontWeight="Bold"/>
<TextBlock x:Name="txtImdbId" Margin="1,1,1,1" Text="{Binding Path=ImdbId}" Grid.Row="0" Grid.Column="1"/>
<TextBlock Text="Url" Grid.Row="1" Grid.Column="0" FontWeight="Bold"/>
<TextBlock x:Name="txtImdbUrl" Margin="1,1,1,1" Text="{Binding Path=Url}" Grid.Row="1" Grid.Column="1"/>
<TextBlock Text="Genres" Grid.Row="2" Grid.Column="0" FontWeight="Bold"/>
<TextBlock x:Name="txtGenres" Margin="1,1,1,1" Text="{Binding Path=Genres}" Grid.Row="2" Grid.Column="1"/>
<TextBlock Text="Languages" Grid.Row="3" Grid.Column="0" FontWeight="Bold"/>
<TextBlock x:Name="txtLanguages" Margin="1,1,1,1" Text="{Binding Path=Languages}" Grid.Row="3" Grid.Column="1"/>
<TextBlock Text="Country" Grid.Row="4" Grid.Column="0" FontWeight="Bold"/>
<TextBlock x:Name="txtCountry" Margin="1,1,1,1" Text="{Binding Path=Country}" Grid.Row="4" Grid.Column="1"/>
<TextBlock Text="Votes" Grid.Row="5" Grid.Column="0" FontWeight="Bold"/>
<TextBlock x:Name="txtVotes" Margin="1,1,1,1" Text="{Binding Path=Votes}" Grid.Row="5" Grid.Column="1"/>
<TextBlock Text="Rating" Grid.Row="6" Grid.Column="0" FontWeight="Bold"/>
<TextBlock x:Name="txtRating" Margin="1,1,1,1" Text="{Binding Path=Rating}" Grid.Row="6" Grid.Column="1"/>
<TextBlock Text="Runtime" Grid.Row="7" Grid.Column="0" FontWeight="Bold"/>
<TextBlock x:Name="txtRuntime" Margin="1,1,1,1" Text="{Binding Path=Runtime}" Grid.Row="7" Grid.Column="1"/>
<TextBlock Text="Title" Grid.Row="8" Grid.Column="0" FontWeight="Bold"/>
<TextBlock x:Name="txtTitle" Margin="1,1,1,1" Text="{Binding Path=Title}" Grid.Row="8" Grid.Column="1"/>
<TextBlock Text="Year" Grid.Row="9" Grid.Column="0" FontWeight="Bold"/>
<TextBlock x:Name="txtYear" Margin="1,1,1,1" Text="{Binding Path=Year}" Grid.Row="9" Grid.Column="1"/>
</Grid>
</StackPanel>
</Window></pre>
<p>Ardından biraz kodlama,</p>
<p><strong>Movie POCO sınıfı;</strong></p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">namespace IMBDGadget
{
class Movie
{
public string ImdbId { get; set; }
public string Url { get; set; }
public string Genres { get; set; }
public string Languages { get; set; }
public string Country { get; set; }
public string Votes { get; set; }
public string Rating { get; set; }
public string Runtime { get; set; }
public string Title { get; set; }
public string Year { get; set; }
}
}</pre>
<p>ve birazcık daha kod <img class="wlEmoticon wlEmoticon-smile" style="border-style: none;" src="/pics/wlEmoticon-smile_94.png" alt="Smile" /></p>
<p><strong>Windows sınıfı</strong></p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Configuration;
using System.IO;
using System.Net;
using System.Windows;
using System.Xml;
using System.Xml.Linq;
namespace IMBDGadget
{
public partial class MainWindow : Window
{
#region Genel değişkenler
string imdbQuery = @"http://www.deanclatworthy.com/imdb/?q={0}&type=xml";
string proxyName = ConfigurationManager.AppSettings["proxyName"];
string proxyPort = ConfigurationManager.AppSettings["proxyPort"];
string proxyUsername = ConfigurationManager.AppSettings["proxyUsername"];
string proxyPassword = ConfigurationManager.AppSettings["proxyPassword"];
WebClient webClient = null;
#endregion
public MainWindow()
{
InitializeComponent();
webClient = GetWebClient();
}
private MemoryStream GetMemoryStream(string query)
{
MemoryStream memoryStream = new MemoryStream(webClient.DownloadData(query));
return memoryStream;
}
private WebClient GetWebClient()
{
WebProxy proxy = new WebProxy(proxyName, Convert.ToInt32(proxyPort));
proxy.Credentials = new NetworkCredential(proxyUsername, proxyPassword);
WebClient client = new WebClient();
client.Proxy = proxy;
return client;
}
private void btnFind_Click(object sender, RoutedEventArgs e)
{
MemoryStream memoryStream = GetMemoryStream(string.Format(imdbQuery, txtMovieName.Text));
XmlTextReader reader = new XmlTextReader(memoryStream);
XDocument document = XDocument.Load(reader);
reader.Close();
memoryStream.Close();
if (document.Root.HasElements)
{
Movie movie = new Movie();
movie.ImdbId = document.Root.Element("imdbid").Value;
movie.Url = document.Root.Element("imdburl").Value;
movie.Genres = document.Root.Element("genres").Value;
movie.Languages = document.Root.Element("languages").Value;
movie.Country = document.Root.Element("country").Value;
movie.Votes = document.Root.Element("votes").Value;
movie.Rating = document.Root.Element("rating").Value;
movie.Runtime = document.Root.Element("runtime").Value;
movie.Title = document.Root.Element("title").Value;
movie.Year = document.Root.Element("year").Value;
grdMovie.DataContext = movie;
}
}
}
}</pre>
<p>ve işte sonuç</p>
<p><a href="https://www.buraksenyurt.com/pics/lyric_imdb.png"><img style="margin: 4px 0px; display: inline;" title="lyric_imdb" src="/pics/lyric_imdb_thumb.png" alt="lyric_imdb" width="480" height="350" /></a></p>
<p>Böylece geldik bir yazımızın daha sonuna. Tekrardan görüşünceye dek hepinize mutlu günler dilerim <img class="wlEmoticon wlEmoticon-winkingsmile" style="border-style: none;" src="/pics/wlEmoticon-winkingsmile_108.png" alt="Winking smile" /></p>
<p><a href="https://www.buraksenyurt.com/pics/2013%2f3%2fLyricsDotCom.rar">LyricsDotCom.rar (75,84 kb)</a></p>2014-01-16T16:36:00+00:00c#c# temellerirestrest serviceslyrics wikiawikiawebrequestwebresponsehttpwebrequesthttpwebresponsebsenyurtMesela bir Windows Forms veya WPF(Windows Presentation Foundation) uygulaması olsa. Internete bağlanabildiği sürece istediğim sanatçının istenen albümündeki istediğim şarkının sözlerini getirse...https://www.buraksenyurt.com/pingback.axdhttps://www.buraksenyurt.com/post.aspx?id=e19d77b1-2ec8-4c16-9213-f0717cf44afe6https://www.buraksenyurt.com/trackback.axd?id=e19d77b1-2ec8-4c16-9213-f0717cf44afehttps://www.buraksenyurt.com/post/Sarki-Sozleri-ve-Eglenceli-Programlama#commenthttps://www.buraksenyurt.com/syndication.axd?post=e19d77b1-2ec8-4c16-9213-f0717cf44afehttps://www.buraksenyurt.com/post/WPF-Temeller-Layout-Kavramc4b1-bsenyurt-com-danWPF Temeller : Layout Kavramı2008-08-11T03:00:00+00:00bsenyurt<p><span style="font-size: small;"><span style="font-family: Verdana;">Değerli Okurlarım Merhabalar,</span></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Uzun süredir ara verdiğimiz makalelerimize kaldığımız yerden devam ediyoruz. Bu makalemizde çok basit seviyede <strong>Windows Presentation Foundation</strong> uygulamalarının temellerinden birisi olan <strong>Layout</strong> kavramını inceleme çalışıyor olacağız. WPF uygulamalarında kullanılan ekranlara ait element veya kontrollerin mutlaka bir <strong>Layout</strong> bileşeni içerisinde konuşlandırılmış olmaları gerekmektedir. <strong>Layout</strong> bileşenleri temelde birer <strong>Panel</strong> olarak düşünülmelidir. </span></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Bu açıdan bakıldığında klasik Windows programcılığında yer alan<em>(diğer kontrolleri üzerinden taşıyan)</em> <strong>Container</strong> bileşenlerinede benzetilebilirler. <strong>WPF</strong> uygulamalarında kullanılabilecek olan <strong>6</strong> adet temel <strong>Layout</strong> bileşeni bulunmaktadır. Herbirinin kendine özgü şekilde elementleri gösterme ve yerleştirme seçenekleri vardır. Bu bileşenlerin en önemli ortak özelliği ise <strong>Panel</strong> isimli <strong>abstract</strong> <strong>sınıftan(Class) türemiş(Inherit) </strong>olmalarıdır. Aşağıdaki <strong>sınıf şemasında(Class Diagram) </strong>söz konusu bileşenler ve Panel ile aralarında türetimsel ilişki açık bir şekilde görülebilmektedir.</span></span></p>
<blockquote>
<p><span style="font-size: small;"><span style="font-family: Verdana;"><strong>Layout</strong> bileşenlerinin tamamı, <strong>System.Windows.Controls isim alanı</strong>(<strong>namespace</strong>) altında yer almaktadır. Bu isim alanı ise, <strong>WPF</strong> <strong>Managed</strong> <strong>API</strong> katmanında yer alan <strong>PresentationFramework.dll</strong> <strong>assembly</strong>' ının bir parçasıdır. Bu <strong>assembly</strong> içerisinde <strong>Layout</strong> bileşeni dışında üst seviye kontrolleri, <strong>style</strong>' ler vb... bileşenlerde yer almaktadır. Bilindiği üzere <strong>WPF</strong> mimarisinde <strong>Managed</strong> <strong>API</strong> katmanında <strong>PresentationCore.dll</strong> ve <strong> WindowsBase.dll</strong> <strong>assembly</strong>' larıda yer almaktadır.</span></span></p>
</blockquote>
<p><span style="font-size: small;"><img src="/makale/images/mk257_1.gif" alt="" width="570" height="492" border="0" /></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;"><strong>Canvas</strong> bileşeni, üzerine bırakılan elementlerin pencerenin <strong>sol(Left), sağ(Right), üst(Top) ve alt(Bottom</strong>) eksenlerine olan uzaklıklarına göre bir yerleşim planına imkan tanımaktadır. <strong>DockPanel</strong> bileşeni, elementlerin tüm alanı kaplayacak şekilde sola, sağa, üste, alta ve geri kalan boşluklara<strong>(Fill) </strong>yanaştırılarak yerleştirilmelerine izin vermektedir. <strong>StackPanel</strong> bileşeni varsayılan olarak elementleri alt alta dizen bir yerleşim sunmaktadır. Ancak istenirse elementleri <strong>yatay eksende(Horizontal)</strong> yan yana olacak biçimde yerleştirilebilmelerine de izin vermektedir. <strong>WrapPanel</strong> bileşeni, dikey veya yatay düzlemde elemanları birbirlerine bitiştirerek sıralarken ekranın sonlanması gibi durumları otomatik hesap edip gerekli kaydırmaların yapılmasına olanak tanımaktadır(<em>Karışık gelen bu tasvir, ilerleyen kısımlardaki kodlar ile daha net bir şekilde görülebilecektir)</em>. <strong>Grid</strong> bileşeni, hücreleri, satır ve sütunları kullanarak kontrollerin yerleşimlerinin gerçekleştirilmesini sağlamaktadır. Son olarak <strong>UniformGrid</strong> kontrolü ise sabit boyuttaki hücreleri kullanarak bileşenlerin çok kolay ve hızlı bir biçimde yerleştirilebilmelerini sağlamaktadır.</span></span></p>
<blockquote>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Dikkat edileceği üzere tüm <strong>Layout</strong> bileşenleri <strong>Abstract</strong> <strong>Panel</strong> sınıfından türemektedir. Buda, geliştirici tanımlı taşıyıcı <strong>Layout</strong> kontrollerinin yazılabileceği anlamına gelmektedir. Bilindiği üzere <strong>abstract</strong> sınıflar, kendisinden türeyen tiplerin uyması ve ezmesi şart olan üye bildirimlerini içermekte olup doğrudan örneklenerek kullanılamayan tiplerdir. Ayrıca abstract sınıflar <strong>polimorfik</strong> şekilde davranış gösterebilirler. Buda Plug-In tabanlı mimarilerde önem arz eden bir konudur.</span></span></p>
</blockquote>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Bu kısa teorik bilgilerden sonra örnekler üzerinden ilerleyerek <strong>Layout</strong> bileşenlerini kavramakta yarar olacağı kanısındayım. </span></span></p>
<p><span style="font-size: small;"><strong><span style="font-family: Verdana;">WrapPanel;</span></strong></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">İlk olarak <strong>WrapPanel</strong> ile başlayalım. Örnek bir <strong>WPF</strong> uygulamasında yer alan Window sınıfına ait <strong>XAML(eXtensible Application Markup Language)</strong> içeriğini aşağıdaki gibi geliştirdiğimizi düşünelim. <em>(Makalede yer alan örnekler Visual Studio 2008 Professional üzerinde geliştirilmektedir.)</em></span></span></p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><Window x:Class="Layouts.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Layout kullanımı" Height="150" Width="250">
<WrapPanel Orientation="Horizontal">
<Button Name="Button1" Content="Giriş"/>
<Button Name="Button2" Content="Kaydet"/>
<Button Name="Button3" Content="Hesapla"/>
<Button Name="Button4" Content="Kullanıcı Değiştir"/>
<Button Name="Button5" Content="Detayları Al"/>
<Button Name="Button6" Content="Yükle"/>
<Button Name="Button7" Content="Belleği Sil"/>
</WrapPanel>
</Window></pre>
<p>Söz konusu <strong>Window1</strong> penceresinin tasarım zamanındaki ekran görüntüsü aşağıdaki gibi olacaktır.</p>
<p><span style="font-size: small;"><img src="/makale/images/mk257_2.gif" alt="" width="277" height="171" border="0" /></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Dikkat edileceği üzere <strong>WrapPanel</strong> içerisinde yer alan örnek <strong>Button</strong> kontrolleri, ekranın boyutuna göre otomatik olarak aşağıya kaydırılmaktadır. <strong>WrapPanel</strong> bileşenine ait <strong>Orientation</strong> özelliğinin varsayılan değeri <strong>Horizontal</strong>' dır. Bu sebepten açık bir şekilde belirtilmesine gerek yoktur. Ancak <strong>elementlerin(kontrollerin)</strong> dikey düzlemde kaydırılmasını istiyorsak, <strong>Orientation</strong> özelliğine <strong>Vertical</strong> değerinin verilmesi gerekir. <strong>Vertical</strong> değeri set edildikten sonra tasarım zamanında aşağıdaki sonuç elde edilir.</span></span></p>
<p><span style="font-size: small;"><img src="/makale/images/mk257_3.gif" alt="" width="277" height="181" border="0" /></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Elbetteki çalışma zamanında ekran boyutları ile oynanılması halinde düğmelerin yerleşimleride buna göre değişiklik gösterecektir. Örneğin boyut ile çalışma zamanında oynandıktan sonraki olası hal aşağıdaki ekran görüntüsüne benzer olacak şekilde elde edilebilir.</span></span></p>
<p><span style="font-size: small;"><img src="/makale/images/mk257_4.gif" alt="" width="247" height="102" border="0" /></span></p>
<p><span style="font-size: small;"><strong><span style="font-family: Verdana;">DockPanel;</span></strong></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;"><strong>Windows</strong> ile programlama yapan herkes özellikle <strong>Visual</strong> <strong>Studio</strong> ortamında kontrollerin <strong>taşıyıcılar(Container)</strong> içerisindeki yerlerini belirlemede kullanılan <strong>Dock</strong> <strong>özelliğini(Property)</strong> bilir. <strong>DockPanel</strong> bu yaklaşımı uygulacak şekilde çalışmaktadır. İşte buna örnek olacak bir <strong>XAML</strong> çıktısı.</span></span></p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><Window x:Class="Layouts.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Layout kullanımı" Height="150" Width="250">
<DockPanel>
<Button DockPanel.Dock="Top">Üst Taraf</Button>
<Button DockPanel.Dock="Left">Sol Taraf........</Button>
<Button DockPanel.Dock="Right">Sağ Taraf</Button>
<Button DockPanel.Dock="Bottom">Alt Taraf</Button>
<Button>Kalan Kısımlar</Button>
</DockPanel>
</Window></pre>
<p>Burada en önemli nokta<strong> iliştirilmiş özellik(Attached Property) </strong>kullanılarak ilgili elementin <strong>DockPanel</strong> taşıyıcısının hangi bölgesine yanaştırılacağının belirlenmesidir. Söz gelimi <strong>DockPanel.Dock</strong> özelliğine <strong>Top</strong> değeri verilmesi ile <strong>Button</strong> elementinin <strong>DockPanel</strong> bileşeninin üst tarafına yanaştırılacağı belirtilmektedir. İlginç olan noktalardan biriside son <strong>Button</strong> kontrolü için böyle bir özellik tanımlaması yapılmamış olmasıdır. Bu çok doğal olarak kalan kısmı dolduracak bir kontrol yerleşimine neden olmaktadır. <strong>Window1' </strong>in tasarım zamanındaki görüntüsü aşağıdaki gibi olacaktır.</p>
<p><span style="font-size: small;"><img src="/makale/images/mk257_5.gif" alt="" width="266" height="165" border="0" /></span></p>
<p><span style="font-size: small;"><strong><span style="font-family: Verdana;">StackPanel;</span></strong></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;"><strong>StackPanel</strong> bileşeni makalenin başındada değinildiği gibi içerisindeki elementleri eklendiği sıra ile yatay veya dikey düzlemde dizerek göstermektedir. Varsayılan olarak tüm bileşeneleri yukarıdan aşağıdaki doğru dizmektedir. Hemen aşağıdaki <strong>XAML</strong> içeriğini göz önüne alalım.</span></span></p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><Window x:Class="Layouts.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Layout kullanımı" Height="150" Width="250">
<StackPanel Background="Gold">
<Button x:Name="Button1" Content="Button1" Margin="3,5" HorizontalAlignment="Left" />
<CheckBox Content="Çalışıyor mu?" IsChecked="True"/>
<TextBlock Text="Yaşadığı Şehir" VerticalAlignment="Bottom" HorizontalAlignment="Center"/>
<ComboBox>
<ComboBoxItem Content="İstanbul" Foreground="Brown"/>
<ComboBoxItem Content="İzmir" Foreground="Red"/>
<ComboBoxItem Content="Ankara" Foreground="Blue"/>
<ComboBoxItem Content="Antalya" Foreground="Goldenrod"/>
</ComboBox>
<Button Content="BilgleriOnayla" x:Name="Button2"/>
</StackPanel>
</Window></pre>
<p>Bu içerikte dikkat edileceği üzere <strong>Button</strong>, <strong>CheckBox</strong>, <strong>TextBlock</strong>, <strong>ComboBox</strong> gibi değişik tipte bileşenler kullanılmaktadır. Normal şartlarda <strong>StackPanel</strong> içerisindeki tüm bileşenler kullanabildikleri tüm alanı kaplarlar. Bu sebepten <strong>ComboBox</strong> ve BilgileriOnayla başlıklı <strong>Button</strong> kontrolünün yatayda tüm alanı kapladıkları görülür. Ancak burada <strong>VerticalAlignment</strong>, <strong>HorizontalAlignment</strong>, <strong>Width</strong>, <strong>Height</strong>, <strong>Margin</strong> gibi özellikler ile oynanarak, kontrollerin boyutları ve <strong>StackPanel</strong> içerisinde kaplayacakları alanlar değiştirilebilir. Söz gelimi <strong>Button1</strong> isimli düğmede <strong>Margin</strong> değeri <strong>3,5 </strong>olarak verilmiştir. Yani <strong>sol üst(Left,Top)</strong> kenar uzaklıkları <strong>3</strong> ile <strong>5</strong> piksel olarak belirlenmiştir. Buna ek olarak <strong>HorizontalAlignment</strong> değerinin <strong>Left</strong> verilmesi ile <strong>Button</strong> kontrolünün sol tarafa yakın çıkması ama üst taraftan <strong>5</strong>, sol taraftan ise <strong>3</strong> piksel uzaklıkta durması sağlanmıştır. Benzer bir konumlandırma işlemide <strong>TextBlock</strong> bileşeni üzerinden <strong>VerticalAlignment</strong> ve <strong>HorizontalAlignment</strong> özelliklerine ilgili değerler atanarak gerçekleştirilmektedir. Bunlara göre tasarım zamanındaki ekran görüntüsü aşağıdaki gibi olacaktır.</p>
<p><span style="font-size: small;"><img src="/makale/images/mk257_6.gif" alt="" width="272" height="173" border="0" /></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Eğer <strong>StackPanel </strong>bileşeninin <strong>Orientation</strong> özelliğine <strong>Horizontal</strong> değeri atanırsa sonuç aşağıdaki gibi olacaktır.</span></span></p>
<p><span style="font-size: small;"><img src="/makale/images/mk257_7.gif" alt="" width="444" height="347" border="0" /></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Bu kez görüleceği üzere tüm elementler yan yana dizilmektedir. Elbetteki yerleşimler biraz tuhaflaşmıştır ve bunların ilgili özellikler yardımıyla düzenlenmesi gereklidir.</span></span></p>
<p><span style="font-size: small;"><strong><span style="font-family: Verdana;">UniformGrid;</span></strong></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Belkide <strong>Grid</strong> tipinden taşıyıcılardan en kolay kullanıma sahip olanıdır. Nitekim geliştiricinin <strong>hücreleri(Cell)</strong>, <strong>satır(Row)</strong> veya <strong>sütun(Column)</strong> özelliklerini düşünmesine gerek yoktur. <strong>UniformGrid</strong> bileşeninde içeriye eklenen elementlere göre hücrelerin boyutları, satır ve sütun sayıları sabitlenmektedir. Söz gelimi aşağıdaki <strong>XAML</strong> içeriğini göz önüne alalım.</span></span></p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><Window x:Class="Layouts.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Layout kullanımı" Height="150" Width="250">
<UniformGrid>
<Button>1</Button>
<Button>2</Button>
<Button>3</Button>
<Button>4</Button>
<Button>5</Button>
<Button>6</Button>
<Button>7</Button>
<Button>8</Button>
</UniformGrid>
</Window></pre>
<p><strong>UniformGrid</strong> bileşeni içerisine <strong>8</strong> adet <strong>Button</strong> kontrolü eklenmiştir. Bu satır ve sütun sayıları otomatik olarak belirlendiğine göre <strong>3X3</strong>' lük bir ızgara anlamına gelmektedir. Malum son hücre boş kalacaktır. İşte örnek <strong>XAML</strong> içeriğine ait tasarım zamanı görüntüsü;</p>
<p><span style="font-size: small;"><img src="/makale/images/mk257_8.gif" alt="" width="281" height="181" border="0" /></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Ancak tabikide <strong>kolon(Column)</strong> veya <strong>satır(Row) </strong>sayıları ile oynanabilir yada içerideki elementlerin hücre içerisinde bulundukları konumlar değiştirilebilir. Bu durumu daha iyi analiz etmek için aşağıdaki <strong>XAML</strong> içeriği göz önüne alınabilir.</span></span></p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><Window x:Class="Layouts.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Layout kullanımı" Height="150" Width="250">
<UniformGrid Columns="4">
<Button Margin="5">1</Button>
<Button Background="RosyBrown" Margin="10,15">2</Button>
<Button>X</Button>
<Button>4</Button>
<Button>5</Button>
<Button>6</Button>
<Button>7</Button>
<Button Foreground="Gold" Background="Black" BorderBrush="Brown" BorderThickness="2" Margin="7.5">8</Button>
</UniformGrid>
</Window></pre>
<p>Burada görüldüğü gibi <strong>UniformGrid</strong> bileşeninin, içerisindeki kontrolleri <strong>4</strong> sütundan oluşan bir ızgara içerisinde göstereceği <strong>Columns</strong> isimli özelliğe atanan değer ile belirlenmektedir. Diğer taraftan bazı <strong>Button</strong> kontrollerinin <strong>Margin</strong> özellikleri ile oynanarak hücre içerisindeki kenar boşluklarına ait miktarlarda belirlenmektedir. Söz gelimi ilk düğme hücrenin tüm kenarlarına <strong>5</strong> piksel uzaklıkta olacaktır. Diğer taraftan <strong>2</strong> yazılı <strong>Button</strong> bileşeni sol tarafa <strong>10</strong> piksel, hücrenin üst tarafına ise <strong>15</strong> piksel uzaklıkta olacak şekilde yer kaplayacaktır. Sonuç olarak tasarım zamanındaki ekran çıktısı aşağıdaki gibi olacaktır.</p>
<p><span style="font-size: small;"><img src="/makale/images/mk257_9.gif" alt="" width="273" height="173" border="0" /></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;"><strong>Grid;</strong></span></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;"><strong>Grid</strong> bileşeninde satırlar ve sütunlar geliştirici tarafından daha detaylı bir şekilde ayarlanır. Bu da söz konusu ızgara üzerinde çok daha fazla geliştirici kontrolü olacağı anlamına gelmektedir. <strong>Grid</strong> bileşeni içerisinde yer alacak elementlerin hangi hücrelere geleceğini belirlemek için yine <strong>Attached</strong> <strong>Property</strong> tekniğinden yararlanılmaktadır. Buna göre <strong>Row</strong> ve <strong>Column</strong> özelliklerine atanan değerler ile yerleşim hücresi belirlenir. Bu özelliklerin varsayılan değeri <strong>0</strong>' dır. Buna göre kontrol ilk hücreye atanır. <strong>Grid</strong> kontrolünün hücreleri üzerine Border kullanımıda gerçekleştirilebilir. <strong>Grid</strong> kontrolüne ait örnek bir kullanım aşağıdaki <strong>XAML</strong> içeriğinde olduğu gibi göz önüne alınabilir.</span></span></p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><Window x:Class="Layouts.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Layout kullanımı" Height="150" Width="250">
<Grid ShowGridLines="True">
<Grid.Background>
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStop Color="AliceBlue" Offset="0.50"/>
<GradientStop Color="Gold" Offset="1"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Grid.Background>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Background="BlueViolet" BorderThickness="2" Grid.Row="2" BorderBrush="Red" Margin="4" Grid.ColumnSpan="2"/>
<TextBlock Text="No" VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
<TextBlock Text="Ad" VerticalAlignment="Bottom" HorizontalAlignment="Right" Grid.Row="0" Grid.Column="1"/>
<TextBlock Text="Yorum" VerticalAlignment="Bottom" HorizontalAlignment="Right" Grid.Row="0" Grid.Column="2"/>
<Rectangle Fill="RosyBrown" Grid.Row="1" Grid.ColumnSpan="3" Height="3"/>
<TextBlock Text="10" VerticalAlignment="Center" HorizontalAlignment="Center" FontWeight="Bold" Foreground="White" Grid.Row="2"/>
<TextBlock Text="Burak Selim Şenyurt" TextWrapping="Wrap" VerticalAlignment="Center" HorizontalAlignment="Center" FontWeight="Bold" Foreground="White" Grid.Row="2" Grid.Column="1"/>
</Grid>
</Window></pre>
<p>İlk olarak <strong>Grid</strong> kontrolünün arka plan dolgusu(<strong>Background</strong>) <strong>LinearGradientBrush</strong> kullanılarak <strong>AliceBlue</strong> renginden <strong>Gold</strong> rengine değişecek şekilde belirlenmiştir. Grid içerisindeki satırları belirlemek için <strong>RowDefinitions(RowDefinitionCollection tipinden)</strong>, sütunları belirlemek içinse <strong>ColumnDefinitions(ColumnDefinitionCollection</strong> <strong>tipinden) </strong>koleksiyonları kullanılır. Satırlar <strong>RowDefinition</strong> elementi ile tanımlanırken, sütunlar <strong>ColumnDefinition</strong> ile tanımlanmaktadır. Satırlar için yükselik değeri <strong>Height</strong> özelliği ile, sütunlar için genişlik değeri <strong>Width</strong> özelliği ile belirlenir.</p>
<p>Dikkat çekici noktalardan biriside <strong>Auto</strong> ve <strong>*</strong> kullanımıdır. <strong>Auto</strong> ifadesine göre yükseklik veya genişlik değeri içerideki elementin boyutuna göre otomatik olarak ayarlanır. Diğer taraftan <strong>*</strong>, "kalan tüm mesafeyi kullan" anlamında düşünülebilir. Örneğin pencerenin genişliği <strong>250</strong> pikseldir. İlk sütun <strong>25</strong>, ikinci sütun ise <strong>50</strong> olarak belirlenmektedir. Geriye kalan <strong>175</strong> piksel ise üçüncü sütuna <strong>*</strong> işareti ile bırakılmaktadır. <strong>Grid</strong> içerisinde kullanılan <strong>Rectangle</strong> elementinden <strong>Grid.ColumnSpan</strong> özelliğine <strong>3</strong> değeri verilmiştir. Buna göre <strong>Rectangle</strong> elementinin bulunduğu 1nci satırdaki <strong>3</strong> hücre birleştirilmektedir. Yine <strong>VerticalAlignment</strong> ve <strong>HorizontalAlignment</strong> özelliklerine atanan değerler kullanılarak kontrolün hücre içerisindeki konumu belirlenebilir. <strong>Grid</strong> kontrolü ile ilişkili ilginç elementlerden biriside <strong>Border</strong> bileşenidir. Örnekte kullanılan <strong>Border</strong> elementi <strong>Grid</strong> bileşeninin 2nci satırıda yer alan ilk iki hücresine<strong>(Grid.ColumnSpan=2 nedeniyle)</strong> uygulanmaktadır. Sonuç itibariyle <strong>Grid</strong> bileşeninin çalışma zamanında verdiği ekran çıktısı aşağıdaki gibi olacaktır.</p>
<p><span style="font-size: small;"><img src="/makale/images/mk257_10.gif" alt="" width="325" height="208" border="0" /></span></p>
<p><span style="font-size: small;"><strong><span style="font-family: Verdana;">Canvas;</span></strong></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Son olarak <strong>Canvas</strong> bileşenine bir göz atalım. Bu kontrolde bileşenlerin konumlarını belirlemek için <strong>Top</strong>, <strong>Lef</strong>, <strong>Right</strong> veya <strong>Bottom</strong> gibi özelliklerden yararlanılmaktadır. Varsayılan olarak bu değerler belirtilmediği takdirde bileşen <strong>0,0</strong> noktasına konumlandırılmaktadır. Bir başka deyişle <strong>Canvas</strong> bileşeninin sol süt köşesine yanaştırılmaktadır. <strong>Canvas</strong> bileşeni için örnek olarak aşağıdaki <strong>XAML</strong> içeriği göz önüne alınabilir.</span></span></p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><Window x:Class="Layouts.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Layout kullanımı" Height="150" Width="250">
<Canvas Background="LightGray">
<Button x:Name="Button1" Content="Button 1"/>
<Button x:Name="Button2" Content="Button 2" Canvas.Left="100" Canvas.Top="50" />
<Button x:Name="Button3" Content="Button 3" Canvas.Right="100" Canvas.Bottom="50" />
</Canvas>
</Window></pre>
<p>Dikkat edileceği üzere <strong>Button1</strong> için herhangibir konum değeri belirtilmemiştir. <strong>Button2</strong> için ise <strong>Left</strong> ve <strong>Top</strong> özellikleri kullanılarak konumlandırma yapılmaktadır. Son <strong>Button</strong> için ise <strong>Right</strong> ve <strong>Bottom</strong> özellikleri kullanılmaktadır. Yine dikkat edilmesi gereken noktalardan birisi <strong>Attached</strong> <strong>Property</strong> kullanılmış olmasıdır. <em>(Böylece ilgili element içerisinde, dahil olduğu elemente ait özelliklere nokta notasyonu ile erişilebilmektedir.)</em> Tasarım zamanındaki ekran görüntüsü aşağıdaki gibi olacaktır.</p>
<p><span style="font-size: small;"><img src="/makale/images/mk257_11.gif" alt="" width="331" height="203" border="0" /></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Dikkat edilmesi gereken noktalardan biriside <strong>Button3</strong>' ün element sırasına göre <strong>Button2</strong>' nin üstünde çıkmış olmasıdır. Bu son derece doğaldır. Ama istenirse <strong>Button2</strong>' nin önde durmasıda sağlanabilir. Bunun için Panel sınıfının <strong>ZIndex</strong> özelliği kullanılmaktadır. Söz gelimi yukarıdaki <strong>XAML</strong> içeriği aşağıdaki gibi değiştirilebilir.</span></span></p>
<p><span style="font-size: small;"><img src="/makale/images/mk257_12.gif" alt="" width="568" height="469" border="0" /> </span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Dikkat edileceği üzere <strong>Button2</strong> için <strong>Panel.ZIndex</strong> değeri <strong>1</strong> olarak set edilmiştir. Buna göre Button2 element sırasına bakılmaksızın en öne gelmiştir.</span></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Buraya kadar geliştirilen basit örnekler ile <strong>WPF</strong> uygulamalarında kullanılabilecek temek <strong>Layout</strong> bileşenleri incelenmeye çalışılmıştır. Bu <strong>Layout</strong> bileşenlerinin ihtiyaçları karşılamaması halinde ise istenirse <strong>Panel</strong> <strong>abstract</strong> sınıfından türetme yoluna gidilerek farklı bir bileşenin üretilmesi sağlanabilir. <strong>Window</strong> bileşenleri kendi içlerinde sadece tek bir <strong>Panel</strong> taşıyabilirler. Bir başka deyişle iki <strong>Layout</strong> kontrolünü <strong>Window</strong> elementi altında aynı seviyede kullanamayız. Ancak bu kısıtlama, <strong>Layout</strong> içerisinde <strong>Layout</strong> kullanılmasını engellemez. Nitekim çoğu durumda bir <strong>Layout</strong> bileşeni içerisinde farklı bir <strong>Layout</strong> bileşeni kullanılması gerekebilir. Söz gelimi aşağıdaki örnek <strong>XAML</strong> içeriğinde bu durum gösterilmeye çalışılmaktadır.</span></span></p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><Window x:Class="Layouts.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Layout kullanımı" Height="250" Width="250" Loaded="Window_Loaded">
<Grid Background="Gold" ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="100"/>
<RowDefinition Height="*"/> <!-- İkinci satır kalan tüm kısmı kaplayacaktır-->
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75"/>
<ColumnDefinition Width="*"/> <!-- İkinci sütun kalan tüm kısmı kaplayacaktır-->
</Grid.ColumnDefinitions>
<Button Content="Gönder" Height="40" Margin="5,0,10,0"/> <!-- Sola 5, sağa 10 piksel uzaklıkta olacaktır-->
<StackPanel Grid.Row="1" Grid.ColumnSpan="2" Background="AliceBlue" Margin="5"> <!-- İkinci satırdaki iki sütun birleştirilir. StackPanel bu bölüme eklenir.-->
<TextBlock Text="Mesajınız Yazınız"/>
<TextBox Text="" Width="100" HorizontalAlignment="Right" TextWrapping="Wrap" Height="75" ScrollViewer.VerticalScrollBarVisibility="Visible" Margin="0,0,10,0"/> <!-- Sağdan 10 piksel uzaklıkta, 100 piksel genişliğinde yatay olarak sağa yaslanmış Wrap özelliği açık, 75 piksel yüksekliğinde ve dikey kaydırma çubuğu görünür olan TextBox-->
</StackPanel>
<UniformGrid Grid.Column="1" Margin="2"> <!-- Bu UniformGrid 1nci sütun içerisinde yer almaktadır.-->
<Button>1</Button>
<Button>2</Button>
<Button>3</Button>
<Button>4</Button>
<Button>5</Button>
<Button>6</Button>
<Button>7</Button>
<Button>8</Button>
<Button>9</Button>
<Button>0</Button>
</UniformGrid>
</Grid>
</Window></pre>
<p>Örnek <strong>XAML</strong> içeriğine ait tasarım zamanı ekran çıktısı aşağıdaki gibi olacaktır.</p>
<p><span style="font-size: small;"><img src="/makale/images/mk257_13.gif" alt="" width="316" height="298" border="0" /></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Elbetteki <strong>Layout</strong> bileşenlerinin dinamik olarak kod içerisinde ele alınmasıda mümkündür. Senaryonun karmaşıklığına göre <strong>Visual Studio 2008 IDE</strong>' si kullanılarak <strong> Layout</strong>' ların ve içeriklerinin tasarlanmasında çok daha iyi sonuçlar alınabilir. Hatta <strong>Expression</strong> ailesindeki ürünlerden yararlanılarak bu görsel bileşenlerin profesyonel görünümlere sahip olarak ürünsel nitelikte olmasıda daha rahat bir şekilde sağlanabilir. Ancak bunların öncesinde <strong>XAML</strong> tarafında ilgili bileşenlerin bu makalede olduğu gibi nasıl kullanılabileceğinin bilinmesinde yarar vardır. Böylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde görüşünceye dek hepinize mutlu günler dilerim.</span></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;"> <a href="https://www.buraksenyurt.com/makale/images/Layouts.rar">Örnek Uygulama için Tıklayın</a></span></span></p>2008-08-11T03:00:00+00:00wpfbsenyurtUzun süredir ara verdiğimiz makalelerimize kaldığımız yerden devam ediyoruz. Bu makalemizde çok basit seviyede Windows Presentation Foundation uygulamalarının temellerinden birisi olan Layout kavramını inceleme çalışıyor olacağız.https://www.buraksenyurt.com/pingback.axdhttps://www.buraksenyurt.com/post.aspx?id=67f34e5e-1fad-4431-8ba9-81feab4d240e1https://www.buraksenyurt.com/trackback.axd?id=67f34e5e-1fad-4431-8ba9-81feab4d240ehttps://www.buraksenyurt.com/post/WPF-Temeller-Layout-Kavramc4b1-bsenyurt-com-dan#commenthttps://www.buraksenyurt.com/syndication.axd?post=67f34e5e-1fad-4431-8ba9-81feab4d240e