DataTemplateSelector : Her item için farklı ItemTemplate!

Merhaba arkadaşlar,

Sizlere geçenlerde bir mesajlaşma uygulaması yazarken karşılaştığım bir
sorunu anlatayım. Kabaca mesajların listelendiği ListBox’ta kullanıcıya gelen
mesajların solda, kullanıcının yazdığı mesajları sağda listelemek istiyordum.
WhatsApp, Facebook, Viber ve diğer aklınıza gelecek bütün uygulamalarda bu
böyle. Gelgelelim ki gelen mesajların solda, giden mesajların sağda listelenmesini bir türlü
becerememiştim. Message sınıfına HorizontalAlignment türünde bir
property eklemeyi bile düşündüm 🙁 Ama bu çok hantal bir çözüm olacaktı. Derken 
DataTemplateSelector adlı çok kullanışlı bir sınıfla
tanıştım.

DataTemplateSelector nedir?
DataTemplateSelector,
herhangi bir listeleme kontrolündeki -bu bir ListBox olabilir- elemanları Property’lerine göre parse edip
o elemana özel bir DataTemplate sunmanızı sağlayan basit ama çok kullanışlı bir
yapıdır. DataTemplateSelector, ContentControl sınıfından türer,
abstract bir sınıftır. Yani biz her ListBox’ımız için DataTemplateSelector’den
türemiş bir başka sınıf yazmak durumundayız.

Benim bu yazıda ele alacağım örneğin sınıf diyagramı:

 Gördüğünüz gibi DataTemplateSelector sınıfı ContentControl’den türüyor. DataTemplateSelector sınıfında odaklanmamız gereken metot SelectTemplate() metodu, virtual bir metot. Parametre olarak object türünde item parametresi alıyor. Bu item parametresi, ListBox’ımızdaki her bir elemanın referansından başka birşey değil. Yazının başında bahsettiğim senaryoda item = Message objesi. Geriye ise DataTemplate döndürüyor.

Bana kalan iş ise DataTemplateSelector’dan türemiş bir sınıf yazıp, SelectTemplate metodunu ezmek.

Yazacağım yeni sınıfa ListBox’ım için kaç tane template olmasını istiyorsam o kadar DataTemplate türünden property eklemem gerekiyor.

Hatırlatmakta fayda var: DataTemplateSelector sınıfı WPF için bulunurken ben Windows Phone için bulamadım, ama Windows Phone için DLL’ini hazırladım :

 DataTemplateSelector.dll (4,5KB) / 8.0 ve üzeri için

Bu kadar bilgi yeterli sanıyorum, şimdi lafı fazla uzatmadan örnek uygulamamıza geçelim. Bu yazımda basitçe ürünlerin listelendiği bir uygulama yapacağız. Ürün sınıfının isim, fiyat, stok gibi alanları olacak. Biz bu sınıftan örnekleri listelerken stoğu 10dan küçük ürünlerin stokta az kaldığını belirten bir yazı ekleyeceğiz.

  1. Ürünler için Product isminde bir sınıf oluşturacağız
  2. Örnek veriler için UrunRepository isminde başka bir sınıf oluşturacağız. Bu sınıfı MainPage.xaml’in DataContext’i olarak kullanacağız.
  3. Daha sonra bu Product sınıfından nesneleri istediğimiz düzende listelemek için bir ProductDataTemplateSelector sınıfı yazacağız.

Product.cs

    public class Product
{
public string ID { get; set; }
public string iconUri { get; set; }
public string Name { get; set; }
public int Price { get; set; }
public int Stock { get; set; }
}

UrunRepository.cs

 public class UrunRepository
{
public ObservableCollection<Product> UrunDataSource { get; set; }
public UrunRepository()
{
this.UrunDataSource = new ObservableCollection<Product>();
this.UrunDataSource.Add(new Product { ID = "1", Name = "Windows Phone'lu cep telefonu", iconUri="Images/goodPhone.jpg", Price = 1900, Stock = 9 });
this.UrunDataSource.Add(new Product { ID = "2", Name = "Diğer cep telefonu", iconUri="Images/badPhone.jpeg", Price = 2800, Stock = 100 });
this.UrunDataSource.Add(new Product { ID = "3", Name = "Su ısıtıcı", iconUri = "Images/kettle.jpg", Price = 40, Stock = 70 });
}
}

UrunRepository sınıfımın UrunDataSource adında, ObservableCollection<Product> türünde bir property’si var. Biz MainPage.xaml’in DataContext’i olarak bu sınıfı gösterip ListBox’ın ItemsSource’ına UrunDataSource isimli property’yi göstereceğiz. Sınıfımın constructor’ında ise gördüğünüz gibi UrunDataSource’u belleğe çıkarıp bu koleksiyona üç adet örnek Product nesnesi ekledim.

Şimdi App.xaml’e iki adet DataTemplate ekleyeceğiz. Bu template’lerden biri stoğu azalan ürünler için olacak.

   <DataTemplate x:Key="NormalUrunTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"></ColumnDefinition>
<ColumnDefinition Width="300"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="100"></RowDefinition>
<RowDefinition Height="40"></RowDefinition>
</Grid.RowDefinitions>
<Image Source="{Binding iconUri}" Width="100" Height="100" Grid.Column="0" Grid.Row="0"></Image>
<TextBlock Text="{Binding Name}" Grid.Column="1" Grid.Row="0" Foreground="#FF00FFD1"></TextBlock>
<TextBlock Text="Fiyat: " Grid.Column="1" Grid.Row="0" Margin="0,50,0,0" FontWeight="Bold">
<Run Text="{Binding Price}" FontWeight="Normal"></Run>
</TextBlock>
</Grid>
</DataTemplate>


<DataTemplate x:Key="AzKalanUrunTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"></ColumnDefinition>
<ColumnDefinition Width="300"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="100"></RowDefinition>
<RowDefinition Height="40"></RowDefinition>
</Grid.RowDefinitions>
<Image Source="{Binding iconUri}" Width="100" Height="100" Grid.Column="0" Grid.Row="0"></Image>
<TextBlock Text="{Binding Name}" Grid.Column="1" Grid.Row="0" Foreground="#FF00FFD1"></TextBlock>
<TextBlock Text="Fiyat: " Grid.Column="1" Grid.Row="0" Margin="0,50,0,0" FontWeight="Bold">
<Run Text="{Binding Price}" FontWeight="Normal"></Run>
</TextBlock>
<TextBlock Text="Son " Grid.Column="1" Grid.Row="0" Margin="0,50,0,0" HorizontalAlignment="Right" Foreground="Red" FontWeight="Bold">
<Run Text="{Binding Stock}" Foreground="Red"></Run>
<Run Text="adet!"></Run>
</TextBlock>

</Grid>
</DataTemplate>

App.xaml’e Resource olarak NormalUrunTemplate ve AzalanUrunTemplate olmak üzere iki adet DataTemplate gömdük. Bu template’leri ProductTemplateSelector sınıfında kullanacağız. Dikkat ederseniz AzalanUrunTemplate’inde ekstra olarak Son (stok) adet! değerine sahip bir TextBlock var.

İhtiyacımız olan son sınıf ProductTemplateSelector.

ProductTemplateSelector.cs

    public class ProductTemplateSelector : DataTemplateSelector
{
/*
iki adet DataTemplate türünde Property tanımlıyoruz.
*/
public DataTemplate NormalUrunTemplate { get; set; }
public DataTemplate AzKalanUrunTemplate { get; set; }

public override DataTemplate SelectTemplate(object item, System.Windows.DependencyObject container)
{
/* burada item parametresini Product'a çevirip stok kontrolü yapıyoruz. */

Product urun = item as Product;
if (urun.Stock < 10)
return AzKalanUrunTemplate;
else
return NormalUrunTemplate;
}
}

ProductTemplateSelector sınıfında öncelikle iki adet DataTemplate türünde iki adet property tanımladık.

SelectTemplate() metodunda ise parametre olarak gelen item nesnesini Product türüne çevirip stok kontrolü yaptık. Stok 10dan az ise geriye AzalanUrunTemplate’ini döndürdük.

MainPage.xaml’deki ListBox’ı ayarlamak dışında herşey hazır.

  • Öncelikle MainPage.xaml’in DataContext’ini UrunRepository sınıfı olarak ayarlayacağız.
  • Sonrasında ise ListBox’ımızın ItemTemplate’ini ayarlayacağız.

DataContext oluşturmadan önce MainPage.xaml’e şöyle bir decleration eklememiz lazım:

    xmlns:local=”clr-namespace:PROJEISMI” 


Bu decleration’u datacontext oluşturmak ve ListBox’ımızın ItemTemplate’ine ProductTemplateSelector’ı atamak için yapıyoruz. Ekledikten sonra local bizim projemizin ana dizinini ifade ediyor olacak.

Ekledikten sonra aşağıdaki kod ile sayfamızın DataContext’ini UrunRepository olarak ayarlıyoruz.

    <phone:PhoneApplicationPage.DataContext>
<local:UrunRepository></local:UrunRepository>
</phone:PhoneApplicationPage.DataContext>

Son olarak ta ListBox’ımızın ItemSource’unu UrunDataSource yapıp ItemTemplate’ini ayarlayalım.

<ListBox ItemsSource="{Binding UrunDataSource}">
<ListBox.ItemTemplate>
<DataTemplate>
<local:ProductTemplateSelector Content="{Binding}"
NormalUrunTemplate="{StaticResource NormalUrunTemplate}"
AzKalanUrunTemplate="{StaticResource AzKalanUrunTemplate}"
HorizontalContentAlignment="Stretch" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

ItemsSource’a UrunDataSource’u bind ettik, ItemTemplate için de bir ProductTemplateSelector tanımlayıp NormalUrunTemplate ve AzalanUrunTemplate propertylerine App.xaml’deki değerleri atadık. Buradaki Content, ContentControl sınıfından gelen bir değer, bu ListBox’taki itemlerin herhangi bir şekilde ekranda görünür olması için onun Binding olması gerekiyor.

Projeyi build edip çalıştırdığımızda şöyle bir görüntüyle karşılacağız:

Gördüğünüz gibi stoğu 10dan az olan ürünümüzün yanında stok uyarısı da bulunuyor. Son derece enteresan bir mesaj vermeyi de unutmadım.

Yazının faydalı olması dileğiyle, başka bir yazıda görüşmek üzere.

DataTemplateSelectorSample.zip (267,6KB)

Fazlasını Oku

Windows Phone & W8 : Tasarım aşamasında örnek veri üretmek

Merhaba arkadaşlar,

Hepimiz uygulamalarımızı tasarlarken yaptığımız tasarıma içeriğin nasıl oturacağını visual studio veya expression blend’den görmek isteriz. Örneğin bir ListBox’ın ItemTemplate’ini düzenlediğimizde bu ListBox’ın içindeki elemanların çalışma zamanında nasıl görüneceğini tasarım aşamasında görmek isteriz.

Daha önce Visual Studio’da Windows Phone Databound App şablonunda bir proje oluşturduysanız LongListSelector’daki verilerin Design One, Design Two… şeklinde listelendiğini göreceksiniz. Uygulamayı emülatörde veya cihazınızda çalıştırınca da bu veriler Runtime One, Runtime Two… şeklinde değişiyor.

      

Bu yazımda da uygulamalarımız için tasarım zamanında nasıl örnek veri üretebileceğimize değineceğim. Aslına bakarsanız bu teknik MVVM mimarisiyle geliştirilen uygulamalarda daha anlamlı oluyor. MVVM mimarisini daha önce kullanan arkadaşlar ne demek istediğimi daha iyi anlayacaklardır.

Bugünkü senaryomuz şöyle olsun;
Bir kütüphane uygulaması yazdığımız varsayalım. Kitap isminde bir sınıfımız olsun ve bu sınıftan örnek verileri MainPage.xaml’de bir ListBox içinde özel bir ItemTemplate ile listeleyelim.

DesignTimeSampleData isimli bir Windows Phone projesi oluşturalım ve Kitap.cs sınıfını ekleyelim;

 

 public class Kitap
{
public string Ismi { get; set; }
public string Yazari { get; set; }
public int SayfaSayisi { get; set; }
}
  • MainPage.xaml‘e bir ListBox veya LongListSelector ekleyelim, ben listbox ekleyeceğim, bir türlü alışamadım şu LongListSelector’a 🙂

          <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">

<ListBox ItemsSource="{Binding Kitaplar1}" Grid.ColumnSpan="3">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Height="100">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80"></ColumnDefinition>
<ColumnDefinition Width="140"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>

</Grid.ColumnDefinitions>
<Image Height="80" Grid.Column="0" Source="/Assets/book.png" Margin="0,0,5,0"></Image>
<StackPanel Grid.Column="1">
<TextBlock Text="Kitap ismi:"></TextBlock>
<TextBlock Text="Yazari:"></TextBlock>
<TextBlock Text="Sayfa sayisi:"></TextBlock>

</StackPanel>
<StackPanel Grid.Column="2">
<TextBlock Text="{Binding Ismi}" Foreground="{StaticResource PhoneSubtleBrush}"></TextBlock>
<TextBlock Text="{Binding Yazari}" Foreground="{StaticResource PhoneSubtleBrush}"></TextBlock>
<TextBlock Text="{Binding SayfaSayisi}" Foreground="{StaticResource PhoneSubtleBrush}"></TextBlock>
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>

</ListBox>
</Grid>

Sadece şimdiden bir betimleme yapmak amacıyla, bizi şöyle bir görüntü bekleyecek;

  • Şimdi bir sınıf daha eklememiz gerekiyor, bu sınıf bizim DataContext’imiz olacak. Kitaplar.cs isminde bir sınıf oluşturalım ve içine List<Kitap> türünde tek bir property ekleyelim. Şunu hatırlatmakta fayda var: Bu sınıf sadece tasarım zamanı için oluşturulan örnek bir sınıf. Gerçek veri için kullanmayacağız.

 public class Kitaplar
{
private List<Kitap> kitaplar;

public List<Kitap> Kitaplar1
{
get { return kitaplar; }
set { kitaplar = value; }
}
}

Şimdi Visual Studio ile işimiz bitti, farkettiyseniz henüz DataContext veya ListBox’ın ItemSource’unu ayarlamadık.

  • Solution Explorer’da proje ismine sağ tıklayıp Open in Blend diyelim.

  • Proje Blend’de açıldıktan sonra default olarak sağ üstte yer alan Data sekmesinde yer alan Create Sample Data iconuna tıklayalım ve Create Sample Data from Class seçeneğini seçelim. Data Sekmesini görmüyorsanız sırasıyla ALT, W, D tuşlarına basın.

  • Bunu yaptıktan sonra karşımıza sınıf seçmek için bir pencere açılacak, hangi türden örnek veri üretmek istiyorsak o sınıf seçeceğiz. İşte burada sonradan oluşturduğumuz Kitaplar adındaki sınıfı seçeceğiz. ListBox’ımıza bağlayacağımız koleksiyon orada.

Gördüğünüz gibi Kitaplar sınıfını seçtim ve blend de benim için Data Source ismine ‘KitaplarSampleData’ ismini verdi. Bu adımdan sonra örnek verilerimiz hazırlanmış olacak.

Örnek verilerimiz otomatik olarak /SampleData/KitaplarSampleData.xaml‘ e çıkarıldı. Şöyle bir bakacak olursak XML verisine çok benzediğini gorecegiz.

<DesingTimeSampleData:Kitaplar xmlns:DesingTimeSampleData="clr-namespace:DesingTimeSampleData">
<DesingTimeSampleData:Kitaplar.Kitaplar1>
<DesingTimeSampleData:Kitap Ismi="Class curabitur vestibulum cras aenean" SayfaSayisi="91" Yazari="Duis curae aliquam nunc amet"/>
<DesingTimeSampleData:Kitap Ismi="Maecenas donec" SayfaSayisi="84" Yazari="Ante nam phasellus integer"/>
<DesingTimeSampleData:Kitap Ismi="Praesent quisque" SayfaSayisi="27" Yazari="Mauris arcu"/>
<DesingTimeSampleData:Kitap Ismi="Consequat nullam sed aptent" SayfaSayisi="60" Yazari="Auctor etiam"/>
<DesingTimeSampleData:Kitap Ismi="Fusce adipiscing convallis" SayfaSayisi="16" Yazari="Dis est diam accumsan vivamus"/>
<DesingTimeSampleData:Kitap Ismi="Hac congue leo cursus" SayfaSayisi="19" Yazari="Mus parturient"/>
<DesingTimeSampleData:Kitap Ismi="Lorem vestibulum" SayfaSayisi="55" Yazari="Vestibulum nec dictum"/>
<DesingTimeSampleData:Kitap Ismi="Non dignissim elementum" SayfaSayisi="16" Yazari="Bibendum per eget sed adipiscing"/>
<DesingTimeSampleData:Kitap Ismi="Dictumst parturient facilisis" SayfaSayisi="33" Yazari="Fermentum lectus fringilla"/>
<DesingTimeSampleData:Kitap Ismi="Elit habitasse morbi eleifend" SayfaSayisi="93" Yazari="Enim erat aliquam"/>
</DesingTimeSampleData:Kitaplar.Kitaplar1>
</DesingTimeSampleData:Kitaplar>

Geriye Design DataContext ve ItemsSource ayarlamaya geldi. Design DataContext sadece tasarım zamanı için bir DataContext belirler, çalışma zamanını etkilemez.

  • DataContext ayarlamak için yine Data sekmesinde yer alan Set design-time DataContext‘e tıklayacağız.

  • Tıkladıktan sonra bize DataContext kaynağı soracak, bu pencereden biraz önce oluşturduğumuz KitapSampleData.xaml‘i seçelim.

  • Ve son olarak aşağıdaki adımları yapalım;
  1. Sağ taraftan Properties tabına gelelim
  2. ListBox’ı seçip ItemsSource özelliğinin yanındaki ufak kareye tıkalyıp Create Data Binding‘i seçelim.
  3. Açılan pencereden sonradan oluşturduğumuz Kitaplar adındaki sınıfın tek Property’si olan Kitaplar1‘i seçelim.

Ve nihayet örnek verilerimizin görüntülendiğini tasarım penceresinde göreceğiz.

  

Gördüğünüz gibi yine bir Lorem Ipsum’la karşı karşıyayız 🙂

Özet: Öncelikle bağlayacağımız verinin şablonu(Model) olan Kitap.cs sınıfını oluşturduk. Daha sonra tek property’si Kitap türünde bir koleksiyon olan Kitaplar.cs sınıfını oluşturduk. Blend’den Kitaplar sınıfı için örnek veriler ürettik ve MainPage.xaml’e Design Datacontext olarak bu verileri gösterdik. Son olarak ta ListBox’ın ItemsSource özelliğine DataContext’imiz olan Kitaplar sınıfının tek property’si olan Kitap türündeki koleksiyonu bağladık.

Bu yazıda Silverlight uygulamarında tasarım aşamasında örnek veri üretmeyi inceledik. Faydalı olması dileğiyle…

DesingTimeSampleData.zip (2,7KB)

Fazlasını Oku

ObservableCollection : Nedir, Ne işe yarar?

Merhaba arkadaşlar, bu yazımda .NET Framework’te yer alan özel bir koleksiyon sınıfı olan ‘ObservableCollection‘ hakkında bilgiler vermeye çalışacağım.

ObservableCollection Nedir?
ObservableCollection, System.Collections.ObjectModel namespace’i altında bulunan özel bir koleksiyon sınıfıdır. WPF, Windows Store ve Windows Phone uygulamalarında veri kaynağında oluşan değişiklikleri arayüze(UI) bildirme amaçlı kullanılır.

ObservableCollection’un yapısına baktığımızda Collection, INotifyPropertyChanged ve INotifyCollectionChanged sınıflarını base olarak kabul ettiğini göreceğiz.

ObservableCollection, generic veri tipini destekleyen bir koleksiyon olduğundan sadece tek bir tip veri barındırabilir.(ObservableCollection<T>)

 

Neden ObservableCollection?
Veri listelediğimiz herhangi bir sayfada veri kaynağında değişme olduğunda bir refresh ihtiyacı olmadan bu değişiklikleri ListBox, LongListSelector gibi kontrollere bildirir ve değişiklikler gerçekleşir. ListBox veya LongListSelector’ı yenilemek için kod yazma ihtiyacı ortadan kalkar.

Veri kaynağında gerçekleşen değişiklikler UI’a bildirilir.

 

1

Örnek Uygulama

Şimdi veri listelemeye, sonradan veri eklemeye dayanan basit bir örnek yapalım. Bu yazımda WPF üzerinden örnek vereceğim.

public class Person
    {
        public int personID { get; set; }
        public string Name { get; set; }
        public string Title { get; set; }

        public static IEnumerable<Person> getPeople()
        {
            ObservableCollection<Person> People = new ObservableCollection<Person>();
            People.Add(new Person { personID = 1, Name = "Fatih Dumanlı", Title = "Jr. Software Developer" });
            People.Add(new Person { personID = 2, Name = "Hasan Hasan", Title = "Specialist" });
            People.Add(new Person { personID = 3, Name = "Ahmet Mehmet", Title = "Senior Software Developer" });

            return People;
        }
    }

Yukarda yapısını verdiğim sınıftan verileri bir listbox’ta görüntüleyelim.

Tasarım için de ben böyle birşey hazırladım :

3

 

<Window x:Class="ObservableCollectionOrnek.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <DataTemplate x:Key="lstPeopleTemplate">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="20"></RowDefinition>
                    <RowDefinition Height="20"></RowDefinition>
                    <RowDefinition Height="20"></RowDefinition>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="50"></ColumnDefinition>
                    <ColumnDefinition Width="*"></ColumnDefinition>
                </Grid.ColumnDefinitions>
                <TextBlock Text="ID:" FontWeight="Bold" Grid.Row="0" Grid.Column="0"></TextBlock>
                <TextBlock Text="Name:" FontWeight="Bold" Grid.Row="1" Grid.Column="0"></TextBlock>
                <TextBlock Text="Title:" FontWeight="Bold" Grid.Row="2" Grid.Column="0"></TextBlock>
                <TextBlock Text="{Binding personID}" Grid.Row="0" Grid.Column="1"></TextBlock>
                <TextBlock Text="{Binding Name}" Grid.Row="1" Grid.Column="1"></TextBlock>
                <TextBlock Text="{Binding Title}" Grid.Row="2" Grid.Column="1"></TextBlock>
            </Grid>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <ListBox ItemsSource="{Binding PeopleDataSource}" HorizontalAlignment="Left" Height="309" VerticalAlignment="Top" Width="305" Margin="212,0,0,0" ItemTemplate="{DynamicResource lstPeopleTemplate}">
            <ListBox.BorderBrush>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="Black" Offset="0"/>
                    <GradientStop Color="White" Offset="1"/>
                </LinearGradientBrush>
            </ListBox.BorderBrush>
        </ListBox>
        <TextBox x:Name="txtName" HorizontalAlignment="Left" Height="23" Margin="77,5,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
        <TextBox x:Name="txtTitle" HorizontalAlignment="Left" Height="23" Margin="77,33,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
        <TextBlock x:Name="tbName" HorizontalAlignment="Left" Margin="10,10,0,0" TextWrapping="Wrap" Text="Name" VerticalAlignment="Top"/>
        <TextBlock HorizontalAlignment="Left" Margin="10,34,0,0" TextWrapping="Wrap" Text="Title" VerticalAlignment="Top"/>
        <Button x:Name="btnAddPerson" Content="Add to List" HorizontalAlignment="Left" Margin="10,61,0,0" VerticalAlignment="Top" Width="187"/>
    </Grid>
</Window>

 

MainWindow.xaml.cs:

namespace ObservableCollectionOrnek
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public static ObservableCollection<Person> PeopleDataSource { get; set; }

        public MainWindow()
        {
            InitializeComponent();
            PeopleDataSource = new ObservableCollection<Person>(Person.getPeople());
            this.DataContext = this;
        }
    }
}

 

Uygulamayı bu haliyle çalıştırdığımızda sağ taraftaki ListBox’ta daha önceden hazırladığımız örnek verilerin listelendiğini göreceğiz.

4

 

Amacımız kişi bilgilerini girip add to list butonuna bastığımızda yeni kişinin sağdaki ListBox’a eklenmesi. Fakat burada dikkat edilmesi gereken nokta şudur ki : Person türündeki veriyi doğrudan ListBox’ın Items özelliğine değil ListBox’ın source’una yani PeopleDataSource adlı ObservableCollection‘a ekleyeceğiz.

O zaman Add To List butonu için bir click event handler oluşturup içini kodlayalım.

private void btnAddPerson_Click(object sender, RoutedEventArgs e)
{
    PeopleDataSource.Add(new Person { personID = PeopleDataSource.Count+1, Name = txtName.Text, Title = txtTitle.Text });
}

Şimdi Add To List butonuna basıldığında Person türündeki nesnenin ListBox’a eklendiğini göreceğiz.

5

 

Bu yazıda basitçe ObservableCollection’un ne işe yaradığına değindik ve basit bir uygulama yaptık. Faydalı olması dileğiyle…

Özet: Data bound sayfalarda Data Source’ta oluşan değişiklikleri standart generic
koleksiyonlar UI’a bildiremez. Data Source’ta oluşan değişiklikleri UI’a
bildirmek için ObservableCollection<T> kullanılır.Veri bağlarken kontrolün ObservableCollection‘a bind edilmesiyle kontrolü refresh etmek için ekstradan bir kod yazma ihtiyacı ortadan kalkar.

 

ObservableCollectionOrnek.rar (63KB)

Fazlasını Oku

XAML Binding Converters(Dönüştürücüler)

Merhaba arkadaşlar,

Bu yazımda Windows Store, WPF ve Windows Phone platformlarında uygulama geliştirirken kullanabileceğiniz Converter’lara değineceğim.

Converter nedir
Converter adı üstünde dönüştürme işlemi yapan nesnelerdir.

Converter’lar System.Windows.Data namespace’i altında bulunan IValueConverter arayüzünden türerler.
IValueConverter‘in imza yapısı;

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture);
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture);

Converterlar neden kullanılır
Sınıfların Propertylerini UI’da kendi istediğimiz formatta görüntülemek için Converter kullanırız. Bir nevi ToString() metodunu ezmek gibi düşünebiliriz.

Üç adımda converter kullanımı:

  1. IValueConver arayüzünden türemiş bir sınıf oluşturulur ve metodlar gerektiği şekilde düzenlenir.
class OrnekConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            //gerekli dönüştürmeler ve return
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException(); //ConvertBack metodu çevrilen değeri eski haline getirmek içindir.
        }
    }

 

2. Oluşturulan converter sınıfını xaml sayfada kullanmak için XAML sayfasına Converter sınıfı StaticResource olarak gömülür.

 xmlns:local="clr-namespace:ProjeIsmi"
 
 <phone:PhoneApplicationPage.Resources>
        <local:OrnekConverter x:Key="ornekConverter1"></local:OrnekConverter>
 </phone:PhoneApplicationPage.Resources>

 

3. UI’da Propertyler görüntülenirken {Binding PropertyIsmi, Converter=ConverterIsmi} şeklinde bind edilir.

<TextBlock Text="{Binding OrnekProperty, Converter={StaticResource ornekConverter1}}"/>

Örnek Uygulama
Bir alışveriş uygulaması geliştirdiğinizi varsayalım. Ürünleri UI’da listelerken ürün ismi, kategorisi ve fiyat bilgileriyle listelediğimizi varsayalım. Ürünleri listelerken doğrudan Fiyat isimli Property’ye bind ettiğimizde
sadece TL cinsinden değeri yazacaktır. Ama sonunda TL ibaresi
olmayacaktır ki bu kesinlikle istemediğimiz bir durum.

İşte bu gibi durumlarda Converter’lar devreye giriyor. Hemen örneğimize başlayalım.

  • Visual Studio’da BindingConverters isimli bir Windows Phone, WPF veya Windows Store projesi oluşturalım
  • Projeye sağ tıklayıp Add -> New Class adımından bir sınıf ekleyelim ve ismine Urun.cs verelim.
  • Kullanacağim Urun.cs sınıfı:
public class Urun
    {
        public string Isim { get; set; }
        public string Kategori { get; set; }
        public int Fiyat { get; set; }

        public static List<Urun> urunGetir()
        {
            List<Urun> urunler = new List<Urun>();
            urunler.Add(new Urun { Isim = "Notebook", Kategori = "Elektronik", Fiyat = 1300 });
            urunler.Add(new Urun { Isim = "Tost Makinesi", Kategori = "Ev eşyaları", Fiyat = 220 });
            urunler.Add(new Urun { Isim = "Parfüm", Kategori = "Kozmetik", Fiyat = 80 });

            return urunler;
        }
    }

Örnek veri kullanmak için urunGetir() isimli bir statik metot tanımladım.

  • Converter sınıfımızı oluşturalım. Projeye sağ tıklayıp Add -> New Class diyelim ve sınıfa FiyatConverter ismini verelim.

FiyatConverter.cs : 

 public class FiyatConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return value.ToString() + " ₺";
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

 

Fiyat isimli Property value parametresiyle geliyor biz de onu string’e çevirip sonuna ₺ ekleyip döndürüyoruz.

  • MainPage.xaml’in üstünde şöyle bir decleration eklememiz gerekecek,

 xmlns:local=”clr-namespace:BindingConverters”

local isimli ön etiket bizim projemizin ana dizinini ifade ediyor. Converter sınıfımızı da ana dizine ekleyeceğiz.

MainPage.xaml:

<phone:PhoneApplicationPage.Resources>
        <local:FiyatConverter x:Key="fConverter"></local:FiyatConverter>
</phone:PhoneApplicationPage.Resources>
 
  <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <ListBox x:Name="lstUrunler" ItemsSource="{Binding UrunDataSource}">
                <ListBox.ItemContainerStyle>
                    <Style TargetType="ListBoxItem">
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="ListBoxItem">
                                    <Grid x:Name="grid" Background="#FF07B063" Height="100" Margin="0,0,0,2">
                                        <Grid.RowDefinitions>
                                            <RowDefinition Height="60"></RowDefinition>
                                            <RowDefinition Height="*"></RowDefinition>
                                        </Grid.RowDefinitions>
                                        <TextBlock Grid.Row="0" Text="{Binding Isim}" Margin="12,0,0,0"></TextBlock>
                                        <TextBlock Grid.Row="0" Text="{Binding Fiyat, Converter={StaticResource fConverter}}" HorizontalAlignment="Right"></TextBlock>
                                        <TextBlock Grid.Row="1" Text="{Binding Kategori}" HorizontalAlignment="Right" FontStyle="Italic" Foreground="Black"></TextBlock>
                                    </Grid>
                                </ControlTemplate>
                            </Setter.Value>                            
                        </Setter>
                    </Style>
                </ListBox.ItemContainerStyle>
            </ListBox>
        </Grid>

 

 

  • Örnek verimizi ListBox’a bağlamak için de MainPage.xaml.cs‘i de şöyle yapalım.
 public partial class MainPage : PhoneApplicationPage
    {
        public static List<Urun> UrunDataSource = new List<Urun>(Urun.urunGetir());
        public MainPage()
        {
            InitializeComponent();
            this.DataContext = this;
        }
    }

 

Ve nihayet uygulamayı test ediyoruz.

1

Gördüğünüz gibi Urun sınıfımızın Fiyat propertyleri yalın bir şekilde değil de sonundaki ₺ sembolü ile birlikte görüntüleniyor.

Umarım faydalı olmuştur, bir sonraki yazıda görüşmek üzere.
   Örnek Proje Dosyası (BindingConverters.zip, 181 KB)

Fazlasını Oku