Caner Tosuner

Leave your code better than you found it

XAML Binding Mode OneWay, TwoWay

Binding, Binding..

Eski den WPF ile uğraşanların oldukça haşır neşir olduğu ve Windows8-WindowsPhone sonrası tamamen hayatımıza girmiş olan XAML ve onun getirdikleri. XAML ile UI geliştirenler Binding'i yakından tanırlar.

Nedir bu Binding diye soracak olursak;

"Databinding(Veri Bağlama) kısaca bir veri kaynağını (Array, Dictionary,Object), bir UI kontrolüne bağlamaya yarayan bir tekniktir."

 

 

Üstteki görselde de görüldüğü üzre Source olarak kullandığımız bir objemiz var ve bu objede ki property'ler de set edilen değerleri XAML tarafta bulunan UI kontrollerine Binding yaparak aktarıyoruz.

 

 Peki ya UI Control için Binding nasıl yapılır dersek aşağıda bulunan görsel nasıl kullanıldığını oldukça iyi özetler gibi.

Yukarıda görüldüğü üzre Source "Article" adında bir class ve içerisinde string tipinde bir "Title" property'si olsun. Bu property'yi TextBox'ın Text'ine Binding olarak set ediyoruz. Böylece şu olmuş oluyor Article objesindeki Title propery'si nin değeri değiştiğinde UI thread'i tetikleyerek Bind olduğu control'ün property'sini de güncelleyecektir.

 

Binding Modları

Binding Modları, binding işlemi sırasında source'ta bulunan verinin değiştiğinde UI'da Bind edildiği yrerin değişip değişmeyeceği veya UI da Bind edilen property'nin içeriği değiştiğinde source da bulunan verinin değişip değişmeyeceğine karar veren özellik diyebiliriz. Bu özellik Binding sınıfının “Mode” property'si ile belirlenir. Bunlar; OneWay, TwoWay, OneTime, OneWayToSource ve Default’ dur.

 

OneWay

Source yani Bind edilen property update edildiği anda UI taraftaki yani target control'de Bind edilen yer de değişir.

 public class Person : INotifyPropertyChanged 
    {
        public string Name { get; set; }
    }

Örneğin bir INotifyPropertyChanged interface'ini implemente etmiş bir Person class'ımız olsun ve bu class'ta bulunan Name alanı UI tarafta bir Textbox'ın Text alanına Bind edilmiş olsun. (INotifyPropertyChanged implementasyonun şu yazıda bulabilirsiniz.)

<TextBox Text="{Binding Name}, Mode=OneWay}"/>

Person objesinde ki Name alanı Codebehind'dan değiştirildiğinde bu değişimden TextBox'ı da haberdar edip Text property'sini de güncelleyecektir.

 

TwoWay

Source yani Bind edilen property update edildiği anda UI da Bind edilen yer de değişir. Aynı şekilde UI'da bulunan control'ün property'si kullanıcı tarafından değiştirildiğinde yani TextBox'a birisi birşeyler yazdığında codeBehind'da Bind edildiği alanıda günceller.

<TextBox Text="{Binding Name}, Mode=TwoWay}"/>

Yukarıda verdiğimiz örnekten devam edelim. Kullanıcı ilgili TextBox'a kendisi birşeyler girip Text'i değiştiğinde bu değişiklikten source'u yani Person objesinde ki Name alanını güncelleyecektir.

 

OneTime

UI tarafında ki control source'dan yani Person objesindeki Name property'sinden sadece 1 defa değerini alır ve ondan sonra ki Name property'sinin güncellenmesi UI tarafı etkilenmez. Ördeğin uygulama açıldıktan sonra Name = "Caner" dedik ve TextBox'ın Text'i de "Caner" oldu ancak bundan sonraki bütün Name="bla bla.." değişikliklerinden TextBox'ın Text'i etkilenmeyecektir.

 

OneWayToSource

OneWay BindingMode'unun tam tersi gibi çalışır. TextBox'ın Text'ine kullanıcı tarafından birşeyler girildiğinde Person objesindeki Name alanını da update eder.Örnek olarak; kullanıcı uygulamada TextBox'ın Text'ine bir şeyler girdiği anda Person class'ında ki Name alanıda otomatik update olur ancak CodeBehind'dan Name alanı değiştirildiğinde bu değişiklik TextBox'ın Text'ine yansımaz.

 

Windows Phone 8.1 XAML Controls

Control

Desc

AppBar Bottom

Displays an AppBar at the bottom of the window

AutoSuggestBox

Text input with suggestions

Border

Visual border

Button

Clickable button

Canvas

Absolute positioning layout container

CaptureElement

Captures input from a camera device

CheckBox

Checkbox

ComboBox

Combobox

CommandBar
See AppBar

Handles the placement of AppBarButton elements

ContentControl

A control that has a single element of content

ContentDialog

WP8.1 'MessageBox'
See MessageDialog for Win8.1

ContentPresenter

Acts as a place-holder in a control template for the control's content

DatePicker

Date selection

DatePickerFlyout

Displays a full-screen date picker

Ellipse

Shape

FlipView

Displays a collection of items, one at a time

Flyout

Displays a non-modal window

Grid

Used to layout other controls (children) in a row/column matrix

GridView

Displays a horizontal grid of items

Hub

Displays data in horizontal sections

Hyperlink

Displays a hyperlink inside TextBlock and RichTextBlock elements

HyperlinkButton

Displays a hyperlink

Image

Displays an image

ItemsControl

A control that displays a collection of elements

ItemsPresenter

Acts as a place-holder in a control template for a list of items

Line

Shape

ListBox

Displays a list of items

ListPickerFlyout

Displays a full-screen flyout list of items

ListView

Displays a collection of items in a list that scrolls vertically

MapControl

Displays a map

MediaElement

Plays audio and video

MenuFlyout

Displays a flyout menu

Path

Shape

PasswordBox

Displays a password entry text box

PickerFlyout

Creates a custom flyout

Pivot

Manages a horizontally scrolled collection of page-like pivot items

Polygon

Shape

Polyline

Shape

Popup

Defines a custom container for other XAML elements

ProgressBar

Displays a progress bar

ProgressRing

Displays a progress ring

RadioButton

Allows the selection of a single item in a group

Rectangle

Shape

RepeatButton

A button that raises a Click event repeatedly until released

RichEditBox

Text box with rich formatting

RichTextBlock

Same as TextBlock but with rich formatting

ScrollBar

Scrollbar with thumb

ScrollViewer

Presents content in a view that may be panned and zoomed

SemanticZoom

Allows the user to zoom between two views of a collection of items

Slider

Allows the user to quickly specify a value by moving a thumb control

StackPanel

Container that layouts out other elements in a horizontal or vertical fashion

TextBlock

Displays text (non-editable)

TextBox

Allows the user to edit text

TimePicker

Time selection

TimePickerFlyout

Displays a full-screen time picker

ToggleButton

A button which can represent two states

ToggleSwitch

Displays an "on/off" switch representing a boolean value

Tooltip

Displays context help for an element

UserControl

Allows the creation of custom controls

VariableSizedWrapGrid

Display items in multiple rows and columns. See also WrapGrid

Viewbox

Container that scales content to a specific size

WebView

Displays a browser

WrapGrid

Display items in rows and columns. See also VariableSizedWrapGrid

 

 

 

 

Windows Phone, Windows 8 Converter Kullanımı

Windwos Phone yada Windows 8 app. dev.’da ItemSource ile uğraşıyorsanız emin olun muhakkak uygulamanın bir yerinde Converter’a ihtiyacınız olmuştur yada olacaktır. Peki nedir Converter, Ne işe yarar, Nasıl kullanılır ?

Converter kısaca ; ItemSource olarak verilen Data’ya Binding işleminden önce müdahale etmektir şeklinde tanımlayabiliriz.

Örneğin bir sayfa var ve o sayfada WebService’den gelen bir liste var elimizde ve içerisinde Product objesi ve objeninde ProductName ProductID ve Quantity bilgileri var diyelim. Servisten gelen bu response’u alıp bir WinPhone uygulamasında Binding ile ekrana taşımak istiyoruz. Binding le uğraşan arkadaşlar biliyorlardır buraya kadar hiçbir sorun yok direk olarak Listbox yada başka bir kontrole ItemSource verip gerekli Binding’ leri verdikten sonra ekranda kolayca göreceğizdir.

Peki ya müşteriden şöyle bir istek gelirse ; “Ben Qantity bilgisi sıfır gelen ürünlerin adet satırında sıfır değilde Not Available yazsın istiyorum” derse ne yapacağız ? Gereksiz yere Database'de ilgili tabloda alan açıp o bilgiyide orada saklayacak halimiz yok. İşte Converter bu ve benzeri durumlarda devreye giriyor ve işimizi kolaylaştırıyor. Şimdi yukarıda bahsettiğimiz case'i aşağıda olduğu gibi bir adet ConverterSample adında WinPhone projesi oluşturarak inceleyelim.

 Öncelikle aşağıda olduğu gibi Producta adında bir class tanımlıyoruz.

public class Product
{
public int ProductID { get; set; }
public string ProductName { get; set; }
public int Quantity { get; set; }
}

 Sornasında geriye List<Product> dönen GetAllProducts() adında metod yazıyoruz ve örnek ürünleri store ediyoruz.

public List<Product> GetAllProducts()
{
List<Product> _allProducts = new List<Product>();
_allProducts.Add(newProduct()
{
ProductID = 111,
ProductName = "Product 111",
Quantity = 124
});
_allProducts.Add(newProduct()
{
ProductID = 112,
ProductName = "Product 112",
Quantity = 75
});
_allProducts.Add(newProduct()
{
ProductID = 113,
ProductName = "Product 113",
Quantity = 47
});
_allProducts.Add(newProduct()
{
ProductID = 114,
ProductName = "Product 114",
Quantity = 32
});
_allProducts.Add(newProduct()
{
ProductID = 115,
ProductName = "Product 115",
Quantity = 0
});
_allProducts.Add(newProduct()
{
ProductID = 116,
ProductName = "Product 116",
Quantity = 4
});
return _allProducts;
}

Code behind da en son olarak Constructor içerisinde üstte yazdığımız metoddan dönen List’i alıp Xaml tarafta oluşturacağımız ListBox’a ItemSource olarak vereceğiz.

// Constructor
public MainPage()
{
InitializeComponent();
lb_products.ItemsSource = GetAllProducts();
}

Xaml tarafında ise Grid içerisinde Row, ve  ListBox’ı oluşturup gerekli Bind işlemlerini yapıp projemizi çalıştırıyoruz ve aşağıdaki gibi bir görüntü alıyoruz.

    

<!--LayoutRoot is the root grid where all page content is placed-->
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
 
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock Text="Converter Expample" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
            <TextBlock Text="Product List" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>
 
        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <Grid.RowDefinitions>
                <RowDefinition Height="50"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="50"/>
                <ColumnDefinition Width="250"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <TextBlock
                Grid.Row="0"
                Grid.Column="0"
                Text="ID"
                FontWeight="Bold"/>
            <TextBlock
                Grid.Row="0"
                Grid.Column="1"
                Text="ProductName"
                FontWeight="Bold"/>
            <TextBlock
                Grid.Row="0"
                Grid.Column="2"
                Text="Quantity"
                FontWeight="Bold"/>
            <ListBox
                x:Name="lb_products"
                Margin="0,60,0,0"
                Width="480">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="50"/>
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="50"/>
                                <ColumnDefinition Width="250"/>
                                <ColumnDefinition Width="*"/>
                            </Grid.ColumnDefinitions>
                            <TextBlock
                                Grid.Row="0"
                                Grid.Column="0"
                                FontWeight="Bold"
                                Text="{Binding ProductID}"/>
                            <TextBlock
                                Grid.Row="0"
                                Grid.Column="1"
                                FontWeight="Bold"
                                Text="{Binding ProductName}"/>
                            <TextBlock
                                Grid.Row="0"
                                Grid.Column="2"
                                FontWeight="Bold"
                                Text="{Binding Quantity}"/>
                        </Grid>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </Grid>
    </Grid>
</phone:PhoneApplicationPage>

 

Yujkarıda olduğu gibi listbox'ımıza Itemsource olarak ürünlerimizi verdik ve Quantity bölümündeki bilgileri uygulamamızda gösterdik. ID'si 115 olan ürünün Quantity değeride "0" olarak geldi. Buraya kadar herşey güzel ancak müşteri bizden Quantity bölümünde sıfır olan ürünler için Not Available yazılmasını söyledi ama biz ekrana Service’den gelen datayı yazdırdık.

Converter için ilk olarak Projemize bir adet QuantityConverter adında class ekliyoruz ve class’ımıza IvalueConverter interface’ini uyarlıyoruz ve IvalueConverter Convert ve ConvertBack adında sahip olduğu 2 adet metodu class’ımıza ekleniyor.Biz şimdilik Convert metodunu kullanacağız. ConvertBack’in ne işe yaradığını ilerki yazılarda bahsedeceğiz. Convert metodunun içerisini aşağıda olduğu gibi değiştiriyoruz.

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return (int)value == 0 ? "Not Available" : value.ToString();
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}

Şimdi sırada yazmış olduğumuz Converter’ı Binding işlemine entegre etmek. Bunun için xaml tarafına yazmış olduğumuz Converter’ı tanıtmalıyız. İlk olarak xmlns:Converter="clr-namespace:ConverterSample" Converter adını verdiğimiz namespace’i eklemek ve en dıştaki Grid’in üstüne aşağıda olduğu gibi Converter’ı Resource olarak yazmak.

   

 <phone:PhoneApplicationPage.Resources>
        <ResourceDictionary>
            <Converter:QuantityConverter x:Key="QuantityConverter"/>
        </ResourceDictionary>
    </phone:PhoneApplicationPage.Resources>

 

Son işlem olarak Quantity bilgisini Bind ettiğimiz yere QuantityConverter’ı yazmak,

<TextBlock
Grid.Row="0"
Grid.Column="2"
FontWeight="Bold"
           Text="{Binding Quantity,Converter={StaticResource QuantityConverter}}"/>

Visual State Nedir ? Nasıl Kullanılır ?

Visual State Kavramı blend yardımı ile xaml tarafında oluşturulan arayüzler için belirlenen state’lere göre story board aracılığı ile geçiş efektleri ve animasyonlar yapmamızı sağlayan yapıdır.

Kısaca şöyle örnekleyebiliriz; üzerinde “Aç” yazan bir butonumuz var ve kullanıcı bu butona bastığı anda ekranın üstünde bulunup o an kullanıcıya görünmeyen bir pop-up’ın yukarıdan aşağıya doğru düştüğünü ve o pop-up üzerinde bulunan “Kapat” butonuna basıldığında tekrar yukarıya doğru çıkıp sayfa üzerinden kaybolduğunu düşünelim. İçimizden “Neden bunu çok rahat bir şekilde story board kullanarak yapmayalım ki ?” diye soran arkadaşlar olacaktır ve bunun cevabını ise şu şekilde verebiliriz.

  • Story Board genel olarak uygulama içerisinde animasyonların ve değişik birbirini takip eden efektlerin olduğu yapıların hazırlanması için kullanılmalıdır.
  • Visual State ise control’ün yapacağı işlevler sınırlı olduğu durumda yani control’ün stateleri belli olup daha kısıtlayıcı efektlere ihtiyaç duyulduğunda kullanılması gereken yapıdır.

 

Üstte verdiğimiz örneği düşündüğümüzde bizim 2 adet state’imiz bulunmaktadır.

               1-Pop-up’ın açılması,

               2-Pop-up’ın kapatılması.

Yani ihtiyacımız olan şey  Visual State ‘dir.

 Gelin şimdi 1 adet windows phone app oluşturarak o örneği yapalım

 Xaml kodları ve ekran görüntüsü aşağıdaki gibi olan bir arayüz oluşturduk,

  

<Grid
        x:Name="ContentPanel"
        HorizontalAlignment="Stretch">
        <StackPanel
            Margin="0,-200,0,0"
            x:Name="stackPanel"
            VerticalAlignment="Top"
            Background="#f0f0f0"
            Orientation="Vertical">
            <TextBlock
                Margin="20,40,0,0"
                Text="Visual State"
                FontSize="30"
                FontWeight="SemiBold"
                Foreground="#373938"/>
            <Button
                Width="210"
                Margin="0,0,0,0"
                BorderBrush="#F26B28"
                HorizontalAlignment="Center"
                Content="kapat"
                FontWeight="Bold"
                Foreground="#F26B28"/>
        </StackPanel>
        <Button
            Width="210"
            Height="100"
            Margin="0,-0,0,0"
            BorderBrush="#F26B28"
            HorizontalAlignment="Center"
            Content="Aç"
            FontWeight="Bold"
            Background="White"
            Foreground="#F26B28"/>
    </Grid>

 

 Şimdi ise sırada Visual State’leri oluşturma var. Bunun için SolutionExplorar’dan MainPage.xaml’e sağ tıklayıp “Open in Blend” diyoruz ve sayfamızı Blend Exp.’da açıyoruz.

 Açılan sayfada sol menüden pop-up’ımız olduğu StackPanel kontolünü seçip bir üstte bulunan State sekmesinden Add state group’a tıklayıp bir adet VisualState Group oluşturmuş oluyoruz. Gereken “Aç” ve “Kapat” statelerini ise bu gorup içerisinde tanımlayacağız

İlk olarak VisualStateGroup yazan yerin sağ tarafında bulunan Add State’e tıklayarak “Kapat” state 2imizi belirliyoruz. Aynı şekilde bir adet daha state ekleyerek onun adınada “Ac” ismini veriyoruz. 

Kapat ve Ac statelerini sağ taraflarında bulunan Add Transition’a tıklayarak Kapalı durumdan açık duruma gelirken ne gibi bir geçiş olacak onu belirliyoruz ve aynı şeyi Açık durumdan kapalı duruma geçerkende yapıyoruz. Gerekli margin ve transition değerlerini verdikten sonra iki state’in arasındaki geçişi yapacak olan story board’a geçiş süresini belirtiyoruz ve Blend’de bulunan uygulamamızı kaydedip kapatıyoruz ve Visual Studio’ya geri dönüyoruz.

 

Şimdi ise sırada oluşturmuş olduğumuz state’leri gerekli durumlarda çağırma işlemi var.Sayfanın xaml tarafına baktığımızda Visual State kodlarımızın geldiğini göreceksinizdir.

//Aç butonunun click event’ine
VisualStateManager.GoToState(this, "Ac", true);

//Pop-up üzerinde bulunan Kapat butonuna ise
VisualStateManager.GoToState(this, "Kapat", true);

 Kodlarını yazdığımızda oluştumuş olduğumuz stateleri çağırıp gerekli transitionları yapacaktır.

 

 >> catch {Foot in Mouth} 'e düşmemeniz dileğiyle.. Smile <<