This article has been localized into Danish by the community.
ListBox kontrollen
I den sidste artikel kiggede vi på ItemsControl, som nok er den mest simple liste i WPF. ListBox kontrollen er den næste kontrol i rækken, og giver lidt mere funktionalitet. En af de vigtigste forskelle er, at ListBox kontrollen faktisk håndterer valg, giver brugeren mulighed for at vælge et eller flere element i listen, og automatisk giver visuel feedback på det.
Her er et eksempel på en meget simpel ListBox kontrol:
<Window x:Class="WpfTutorialSamples.ListBox_control.ListBoxSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ListBoxSample" Height="120" Width="200">
<Grid Margin="10">
<ListBox>
<ListBoxItem>ListBox Item #1</ListBoxItem>
<ListBoxItem>ListBox Item #2</ListBoxItem>
<ListBoxItem>ListBox Item #3</ListBoxItem>
</ListBox>
</Grid>
</Window>
Det er så simpelt, som det er: Vi erklærer en ListBox kontrol, og inden i den erklærer vi tre ListBoxItem's hver med sin egent tekst. Men, siden ListBoxItem faktisk er en ContentControl, kan vi definere brugerdefineret indhold til den:
<Window x:Class="WpfTutorialSamples.ListBox_control.ListBoxSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ListBoxSample" Height="120" Width="200">
<Grid Margin="10">
<ListBox>
<ListBoxItem>
<StackPanel Orientation="Horizontal">
<Image Source="/WpfTutorialSamples;component/Images/bullet_blue.png" />
<TextBlock>ListBox Item #1</TextBlock>
</StackPanel>
</ListBoxItem>
<ListBoxItem>
<StackPanel Orientation="Horizontal">
<Image Source="/WpfTutorialSamples;component/Images/bullet_green.png" />
<TextBlock>ListBox Item #2</TextBlock>
</StackPanel>
</ListBoxItem>
<ListBoxItem>
<StackPanel Orientation="Horizontal">
<Image Source="/WpfTutorialSamples;component/Images/bullet_red.png" />
<TextBlock>ListBox Item #3</TextBlock>
</StackPanel>
</ListBoxItem>
</ListBox>
</Grid>
</Window>
Til hvert ListBoxItem tilføjer vi nu et StackPanel, hvor vi tilføjer et Image og en TextBlock. Dette giver os fuld kontrol over indholdet såvel som tekstgengivelsen, som du kan se på skærmbilledet, hvor forskellige farver er brugt til hvert af tallene.
På skærmbilledet bemærker du måske også en anden forskel ved sammenligning mellem ItemsControl og ListBox: Som standard er der vist en ramme omkring kontrollen, hvilket får den til at lige en egentlig kontrol og ikke kun output.
Databinding af ListBox
Manuel definition af elementerne til ListBox er udmærket til et første eksempel, men de fleste gange vil din ListBox bliver fyldt med elementer fra en datakilde ved hjælp af databinding. Som standard, hvis du binder liste af elementer til ListBox, vil deres ToString() metode blive brugt til at repræsentere hvert element. Det er sjældendt hvad, du vil, men heldigvis kan vi nemt erklære en skabelon, som vil blive brugt til at gengive hvert element.
Jeg har genbrugt TODO eksemplet fra ItemsControl artiklen, hvor vi laver en sej TODO liste ved hjælp af en simple code-behind klasse, og i dette tilfælde, en ListBox kontrol til visuel repræsentation. Her er eksemplet:
<Window x:Class="WpfTutorialSamples.ListBox_control.ListBoxDataBindingSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ListBoxDataBindingSample" Height="150" Width="300">
<Grid Margin="10">
<ListBox Name="lbTodoList" HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="0,2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Title}" />
<ProgressBar Grid.Column="1" Minimum="0" Maximum="100" Value="{Binding Completion}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
using System;
using System.Windows;
using System.Collections.Generic;
namespace WpfTutorialSamples.ListBox_control
{
public partial class ListBoxDataBindingSample : Window
{
public ListBoxDataBindingSample()
{
InitializeComponent();
List<TodoItem> items = new List<TodoItem>();
items.Add(new TodoItem() { Title = "Complete this WPF tutorial", Completion = 45 });
items.Add(new TodoItem() { Title = "Learn C#", Completion = 80 });
items.Add(new TodoItem() { Title = "Wash the car", Completion = 0 });
lbTodoList.ItemsSource = items;
}
}
public class TodoItem
{
public string Title { get; set; }
public int Completion { get; set; }
}
}
Al magien sker i ItemTemplate, som vi har defineret til ListBox. I den angiver vi, at hvert ListBox element skal bestå af et Grid inddelt i to kolonner med en TextBlock, der viset titlen i den første, og en ProgressBar, som viser færdiggørelsesstatus i den anden kolonne. For at få værdierne ud, bruger vi lidt simpel databinding, hvilket er forklaret i databinding-delen af dette selvstudie.
I code-behind filen har vi erklæret en meget simpel TodoItem klasse til at indeholde vores TODO elementer. I vinduets kontruktør initialiserer vi en liste, tilføjer tre TODO elementer til den, og tildeler listen til ItemsSource på ListBox. Kombinationen af ItemsSource og den ItemTemplate, vi angav i XAML-delen er alt, WPF behøver for at gengive alle elementerne som en TODO liste.
Bemærk HorizontalContentAlignment egenskaben, som jeg sætter til Stretch på ListBox. Standard indholdsjustering for ListBox elementer er Left, hvilket betyder, at hvert element kun optager så meget vandret plads, som det behøver. Resultatet? Tja, ikke helt, hvad vi ønsker:
Ved at bruge Stetch justeringen, vil hvert element blive udstrakt til at udfylde al den tilgængelige plads, som du kan se i det forrige skærmbillede.
Arbejde med ListBox markeringer
Som nævnt er en væsentlig forskel mellem ItemsControl og ListBox, at ListBox håndterer og viser brugermarkeringer for dig. Derfor handler en masse ListBox spørgsmål om det at arbejde med markeringer. For at hjælpe med nogle af disse spørgsmål, har jeg lavet et større eksempel, der viser nogle tricks omkring markeringer:
<Window x:Class="WpfTutorialSamples.ListBox_control.ListBoxSelectionSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ListBoxSelectionSample" Height="250" Width="450">
<DockPanel Margin="10">
<StackPanel DockPanel.Dock="Right" Margin="10,0">
<StackPanel.Resources>
<Style TargetType="Button">
<Setter Property="Margin" Value="0,0,0,5" />
</Style>
</StackPanel.Resources>
<TextBlock FontWeight="Bold" Margin="0,0,0,10">ListBox selection</TextBlock>
<Button Name="btnShowSelectedItem" Click="btnShowSelectedItem_Click">Show selected</Button>
<Button Name="btnSelectLast" Click="btnSelectLast_Click">Select last</Button>
<Button Name="btnSelectNext" Click="btnSelectNext_Click">Select next</Button>
<Button Name="btnSelectCSharp" Click="btnSelectCSharp_Click">Select C#</Button>
<Button Name="btnSelectAll" Click="btnSelectAll_Click">Select all</Button>
</StackPanel>
<ListBox Name="lbTodoList" HorizontalContentAlignment="Stretch" SelectionMode="Extended" SelectionChanged="lbTodoList_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="0,2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Title}" />
<ProgressBar Grid.Column="1" Minimum="0" Maximum="100" Value="{Binding Completion}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
</Window>
using System;
using System.Windows;
using System.Collections.Generic;
namespace WpfTutorialSamples.ListBox_control
{
public partial class ListBoxSelectionSample : Window
{
public ListBoxSelectionSample()
{
InitializeComponent();
List<TodoItem> items = new List<TodoItem>();
items.Add(new TodoItem() { Title = "Complete this WPF tutorial", Completion = 45 });
items.Add(new TodoItem() { Title = "Learn C#", Completion = 80 });
items.Add(new TodoItem() { Title = "Wash the car", Completion = 0 });
lbTodoList.ItemsSource = items;
}
private void lbTodoList_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
if(lbTodoList.SelectedItem != null)
this.Title = (lbTodoList.SelectedItem as TodoItem).Title;
}
private void btnShowSelectedItem_Click(object sender, RoutedEventArgs e)
{
foreach(object o in lbTodoList.SelectedItems)
MessageBox.Show((o as TodoItem).Title);
}
private void btnSelectLast_Click(object sender, RoutedEventArgs e)
{
lbTodoList.SelectedIndex = lbTodoList.Items.Count - 1;
}
private void btnSelectNext_Click(object sender, RoutedEventArgs e)
{
int nextIndex = 0;
if((lbTodoList.SelectedIndex >= 0) && (lbTodoList.SelectedIndex < (lbTodoList.Items.Count - 1)))
nextIndex = lbTodoList.SelectedIndex + 1;
lbTodoList.SelectedIndex = nextIndex;
}
private void btnSelectCSharp_Click(object sender, RoutedEventArgs e)
{
foreach(object o in lbTodoList.Items)
{
if((o is TodoItem) && ((o as TodoItem).Title.Contains("C#")))
{
lbTodoList.SelectedItem = o;
break;
}
}
}
private void btnSelectAll_Click(object sender, RoutedEventArgs e)
{
foreach(object o in lbTodoList.Items)
lbTodoList.SelectedItems.Add(o);
}
}
public class TodoItem
{
public string Title { get; set; }
public int Completion { get; set; }
}
}
Som du kan se, har jeg defineret en række knapper til højre for ListBox til enten at hente eller manipulere markeringen. Jeg har også ændret SelectionMode til Extended for at tillade markering af flere elementer. Dette kan gøres enten via kode, som jeg gør i eksemplet, eller af slutbrugeren ved at holde [Ctrl] eller [Shift] nede mens, der klikkes på elementerne.
For hver af knapperne har jeg defineret en klik-handler i code-behind. Hver handling skulle være rimelig selvforklarende, og den anvendte C# kode er rimelig simpel. Men er du stadig i tvivl, så kør eksemplet på din egen maskine og prøv de forskellige muligheder i eksemplet.
Resume
ListBox kontrollen er meget som ItemsControl, og adskillige af de samme teknikker kan bruges. ListBox tilbyder lidt mere funktionalitet sammenligned med ItemsControl, specielt markeringshåndteringen. For endnu mere funktionalitet som kolonneoverskrifter, skal du have et kig på ListView kontrollen, som får en meget grundig beskrivelse senere i dette selvstudie med adskillige artikler med forklaring af al funktionaliteten.