WPF Listbox İçerisine ListBoxItem Ekleme
- 401
- (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>
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
}
Ü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.
Ü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.
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)));
}
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.
İ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.
İlişkili İçerikler
C# ile ekran görüntüsü alan bir uygulama nasıl yazılır öğrenmek için bu içeriğe bakabilirsiniz. Ekran görüntülerini ListBox üzerinde gösteren bir WPF uygulaması.