WPF Listbox İçerisine ListBoxItem Ekleme

  • 3
  • (1)
  • (5)
  • 12 Eki 2021

ListBox İçine String Ekleme

WPF penceresine aşağıdaki gibi bir ListBox ekleyin.


<Window x:Class="WpfAppTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfAppTest"
        mc:Ignorable="d"
        Title="Ürün Listesi" Height="320" Width="640">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="24" />
            <ColumnDefinition Width="120" />
            <ColumnDefinition Width="200" />
            <ColumnDefinition Width="1*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="32" />
            <RowDefinition Height="32" />
            <RowDefinition Height="144" />
        </Grid.RowDefinitions>
        <TextBlock Text="Ürün: " Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" TextAlignment="Right" />
        <TextBox Grid.Row="0" Grid.Column="2" VerticalAlignment="Center" x:Name="tbProduct" />
        <Button Content="Ekle" Grid.Row="1" Grid.Column="2" VerticalAlignment="Center" HorizontalAlignment="Left" Width="64" Click="AddButton_Click" />
        <ListBox Grid.Row="2" Grid.Column="2" x:Name="lbProducts"></ListBox>
    </Grid>
</Window>

wpf listbox

Textbox nesnesine yazılan her ürün adı birer birer ListBox içerisine eklenecek.

Click="AddButton_Click" üzerinde AddButton_Click yazan yere imleci getirerek F12 tuşuna basın ve arka planda ilgili metodu otomatik olarak oluşturun.


public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void AddButton_Click(object sender, RoutedEventArgs e)
    {
        // Buraya ürün ekleme işlemlerini yazacağız
    }
}

Her ürün adı sadece bir kere olabilsin. Ürün adı uzunluğu en az 4 karakter ve en fazla 32 karakter olabilsin. Ürün eklendikten sonra ise TextBox nesnesi temizlensin. Enter kısayol tuşuna basılınca da ekleme işlemi gerçekleşsin.

Ürün Ekleme

En salt hali ile ürün ekleme aşağıdaki gibi gerçekleştirilir.


private void AddButton_Click(object sender, RoutedEventArgs e)
{
    lbProducts.Items.Add(tbProduct.Text);
    tbProduct.Text = ""; // Ürün eklenince TextBox içerisi boşaltılır
}

wpf listbox

Ürün Karakter Uzunluğu Belirleme

Ürün adının alındığı TextBox.Text değerinin uzunluğunun geçerliliğini bool türünde geri döndüren bir metot tanımlanabilir.


private void AddButton_Click(object sender, RoutedEventArgs e)
{
    string productName = tbProduct.Text;
    bool isValid = CheckProductName_IsValid(productName);
    if (!isValid)
    {
        MessageBox.Show("Ürün adı en az 4 karakter ve en fazla 32 karakter olabilir.");
        return;
    }
    lbProducts.Items.Add(productName);
    tbProduct.Text = ""; // Ürün eklenince TextBox içerisi boşaltılır
}

private bool CheckProductName_IsValid(string productName)
{
    return productName.Length >= 4 && productName.Length <= 32;
}

Eğer ürün adının uzunluğu 4 karaktere eşit veya büyükse ve 32 karaktere eşit veya küçükse CheckProductName_IsValid metodu true değeri olarak dönecektir. Aksi halde false olarak dönecek, ürün ekleme butonuna tıklanan metot içerisinde !isValid koşulu true olacağı için mesaj kutusunda uyarı gelip işlem gerçekleşmeden return ile sonlanacaktır.

wpf listbox

Ürün Adı Mevcut ise Eklemeyi Engelleme

Ürün adının uzunluğunu denetleyen metot gibi mevcut olup olmadığını belirleyen ayrı bir metot daha tanımlanabilir.


private void AddButton_Click(object sender, RoutedEventArgs e)
{
    string productName = tbProduct.Text;
    bool isValid = CheckProductName_IsValid(productName);
    if (!isValid)
    {
        MessageBox.Show("Ürün adı en az 4 karakter ve en fazla 32 karakter olabilir.");
        return;
    }
    bool isExist = CheckProductName_IsExist(productName);
    if (isExist)
    {
        MessageBox.Show("Ürün adı zaten mevcut.");
        return;
    }
    lbProducts.Items.Add(productName);
    tbProduct.Text = ""; // Ürün eklenince TextBox içerisi boşaltılır
}

private bool CheckProductName_IsValid(string productName)
{
    return productName.Length >= 4 && productName.Length <= 32;
}

private bool CheckProductName_IsExist(string productName)
{
    foreach (string listItem in lbProducts.Items)
    {
        if (listItem == productName) return true;
    }
    return false;
}

Ürün adını eklemek için butona tıklandığında önce ürün adının uzunluğu denetlenir. Bu denetlemeden geçildiği taktirde CheckProductName_IsExist metodu ile ürün adı listede mevcut mu değil mi denetlenir. foreach döngüsü ile lbProducts isimli ListBox nesnesinin her bir öğesi string türünden alınır. Eğer bu değerlerden biri girilmek istenen ürün adına eşitse metot true değeri olarak dönecektir. Ürün ekleme butonuna tıklanıldığında çalışacak olan AddButton_Click metodu içerisindeki isExist koşulu da true olacağı için mesaj kutusu ile uyarı verilip metot return ile sonlanacaktır.

wpf listbox

ListBox İçine Daha Karmaşık Veri Modeli Ekleme

ListBoxItem nesnesini daha karmaşık bir veri modeli ile tasarlamamız mümkündür. Veri modeli aşağıdaki gibi olsun.


public class ProductModel
{
    public string Name { get; set; }
    public double Price { get; set; }
    public int Stock { get; set; }
    public bool InStock { get { return Stock > 0; } }

    public ProductModel(string name, double price, int stock)
    {
        Name = name; Price = price; Stock = stock;
    }
}

ListBoxItem nesnesinden başka bir nesne üretebilirsiniz.


public class ProductListBoxItem : ListBoxItem
{
    public StackPanel sp { get; set; }
    public TextBlock tbName { get; set; }
    public TextBlock tbPrice { get; set; }

    public ProductListBoxItem(ProductModel product)
    {
        this.Background = product.InStock ? Brushes.LightGreen : Brushes.LightPink;
        sp = new StackPanel();
        this.Content = sp;
        tbName = new TextBlock() { Text = product.Name, FontSize = 12.0 };
        tbPrice = new TextBlock() { Text = product.Price.ToString("₺ 0.00"), FontSize = 10.0 };
        sp.Children.Add(tbName);
        sp.Children.Add(tbPrice);
    }
}

Her bir öğe StackPanel içerisinde iki adet TextBlock ile doldurulacak. Eğer stokta varsa öğenin arka rengi açık yeşil, yoksa açık pembe olacak.

Ekleme butonuna doğrudan aşağıdaki gibi hazır verileri ekletip sonucu görebiliriz. İsterseniz form üzerinden okunan değerleri tek tek de ekletebilirsiniz.


private void AddButton_Click(object sender, RoutedEventArgs e)
{
    lbProducts.Items.Add(new ProductListBoxItem(new ProductModel("Geniş Paça Kot Pantolon", 92.0, 54)));
    lbProducts.Items.Add(new ProductListBoxItem(new ProductModel("XL Beyaz Gömlek", 42.0, 0)));
    lbProducts.Items.Add(new ProductListBoxItem(new ProductModel("Blazer Ceket", 160.0, 22)));
    lbProducts.Items.Add(new ProductListBoxItem(new ProductModel("Siyah Kumaş Pantolon", 200.0, 16)));
}

wpf listbox

ListBox İçini Veri Modeli Bağlayarak Doldurmak (Binding)

XAML tasarımı üzerinde Binding özelliğini kullanarak bir veri modelini arayüze doğrudan bağlayabiliriz. Bunun için veri modelini INotifyPropertyChanged arayüzü ile tanımlamalıyız.

Bu interface özelliklerini kullanabilmek için cs dosyasına using System.ComponentModel; satırı ile ilgili kütüphaneyi eklemelisiniz.


public class ProductModel : INotifyPropertyChanged
{
    private string _name;
    private double _price;
    private int _stock;
    public string Name { get { return _name; } set { _name = value; OnPropertyChanged(); } }
    public double Price { get { return _price; } set { _price = value; OnPropertyChanged(); } }
    public int Stock { get { return _stock; } set { _stock = value; OnPropertyChanged(); OnPropertyChanged("InStock"); } }
    public bool InStock { get { return _stock > 0; } }

    public ProductModel(string name, double price, int stock)
    {
        _name = name; _price = price; _stock = stock;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

}

CallerMemberName isim attribute sayesinde OnPropertyChanged metodu hangi property (Name, Price veya Stock) içerisinden çağrılıyorsa, propertName isimli parametre o özelliğin(property) adını alacaktır. Bu sayede o özelliğin değiştiği XAML arayüzüne bildirilecektir. Yani eş zamanlı değişiklikler programın arayüzüne doğrudan yansıyacaktır.

Binding işleminin gerçekleşmesi için XAML arayüzünün aşağıdaki gibi olması gerekiyor.


<Window x:Class="WpfAppTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfAppTest"
        mc:Ignorable="d"
        Title="Ürün Listesi" Height="320" Width="640">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="24" />
            <ColumnDefinition Width="120" />
            <ColumnDefinition Width="200" />
            <ColumnDefinition Width="1*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="32" />
            <RowDefinition Height="32" />
            <RowDefinition Height="144" />
        </Grid.RowDefinitions>
        <TextBlock Text="Ürün: " Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" TextAlignment="Right" />
        <TextBox Grid.Row="0" Grid.Column="2" VerticalAlignment="Center" x:Name="tbProduct" />
        <Button Content="Ekle" Grid.Row="1" Grid.Column="2" VerticalAlignment="Center" HorizontalAlignment="Left" Width="64" Click="AddButton_Click" />
        <ListBox Grid.Row="2" Grid.Column="2" x:Name="lbProducts" ItemsSource="{Binding}">
            <ListBox.ItemContainerStyle>
                <Style TargetType="ListBoxItem">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding InStock}" Value="True">
                            <Setter Property="Background" Value="LightGreen"></Setter>
                        </DataTrigger>
                        <DataTrigger Binding="{Binding InStock}" Value="False">
                            <Setter Property="Background" Value="LightPink"></Setter>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </ListBox.ItemContainerStyle>
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel>
                        <TextBlock Text="{Binding Name}" FontSize="12"></TextBlock>
                        <TextBlock Text="{Binding Price, StringFormat='₺ 0.00'}" FontSize="10"></TextBlock>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

ListBox nesnesinin ItemTemplate özelliğine DataTemplate tanımlanır. DataTemplate içerisinde bir önceki örnekte kodlanan arayüz modeli XAML olarak tanımlanır ve ilgili özelliklere değişkenler Binding ile bağlanır.


public partial class MainWindow : Window
{
    private ObservableCollection<ProductModel> products;
    public MainWindow()
    {
        InitializeComponent();
        products = new ObservableCollection<ProductModel>();
        lbProducts.DataContext = products;
    }

    private void AddButton_Click(object sender, RoutedEventArgs e)
    {
        products.Add(new ProductModel("Geniş Paça Kot Pantolon", 92.0, 54));
        products.Add(new ProductModel("XL Beyaz Gömlek", 42.0, 0));
        products.Add(new ProductModel("Blazer Ceket", 160.0, 22));
        products.Add(new ProductModel("Siyah Kumaş Pantolon", 200.0, 16));
    }
}

Ekle butonuna tıklandığında lbProducts isimli ListBox nesnesinin DataContext özelliğine atanan veri değiştirildiğinde arayüze otomatik yansıyacaktır. Bu veriyi List olarak tanımlarsanız veri değiştiği zaman arayüze yansıması için her değişiklikten sonra lbProducts.DataContext = products; işlemini kullanmanız gerekir. Ancak ObservableCollection kullanıldığında bu işlemi başlangıçta tanımlamış olmanız yeterli olacaktır. Çünkü INotifyPropertyChanged arayüzü(interface) tanımladığımız veri modelinde mevcut olsa da, List veri türünün kendisi için böyle bir durum söz konusu değildir. Ancak ObservableCollection üzerine gelip F12 tuşuna basarsanız metadata olarak gelen cs dosyasında INotifyCollectionChanged, INotifyPropertyChanged isimli iki adet interface ile tanımlandığını fark edeceksiniz.

wpf listbox

İsterseniz bu verileri başlangıçta ekleyip butona tıklayınca her birine % 10 fiyat zammı ekleyerek interaktif değişikliği görebilirsiniz.


public partial class MainWindow : Window
{
    private ObservableCollection<ProductModel> products;
    public MainWindow()
    {
        InitializeComponent();
        products = new ObservableCollection<ProductModel>();
        products.Add(new ProductModel("Geniş Paça Kot Pantolon", 92.0, 54));
        products.Add(new ProductModel("XL Beyaz Gömlek", 42.0, 0));
        products.Add(new ProductModel("Blazer Ceket", 160.0, 22));
        products.Add(new ProductModel("Siyah Kumaş Pantolon", 200.0, 16));
        lbProducts.DataContext = products;
    }

    private void AddButton_Click(object sender, RoutedEventArgs e)
    {
        foreach (var product in products)
        {
            product.Price += product.Price * 0.1;
        }
    }
}

Ekle butonuna tıklandığında sonuç şu şekilde olacaktır.

wpf listbox
İlişkili İçerikler

Masaüstü uygulama geliştirmek için Windows Forms türüne alternatif olarak WPF türü uygulamalar geliştirebilirsiniz.

WPF uygulaması içerisinde TextBox nesnesinin kullanım şekillerini bu içerikle öğrenebilir ve uygulayabilirsiniz.

Paylaşın
Etiket Bulutu