TOC

This article has been localized into Vietnamese by the community.

Danh sách control:

ListBox control

Trong bài viết trước, chúng ta đã xem xét ItemControl, đây có lẽ là danh sách đơn giản nhất trong WPF. Điều khiển ListBox là điều khiển tiếp theo, bổ sung thêm một chút chức năng. Một trong những khác biệt chính là việc điều khiển ListBox thực sự xử lý các lựa chọn, cho phép người dùng cuối chọn một hoặc một số mục từ danh sách và tự động đưa ra phản hồi trực quan cho nó.

Đây là một ví dụ về điều khiển ListBox rất đơn giản:

<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>

Điều này đơn giản như nó nhận được: Chúng tôi khai báo một điều khiển ListBox và bên trong nó, chúng tôi khai báo ba ListBoxItem, mỗi cái có văn bản riêng. Tuy nhiên, vì ListBoxItem thực sự là một ContentControl, chúng tôi có thể xác định nội dung tùy chỉnh cho nó:

<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>

Đối với mỗi ListBoxItem, chúng tôi hiện thêm một StackPanel, trong đó chúng tôi thêm một Image và TextBlock. Điều này cho chúng tôi toàn quyền kiểm soát nội dung cũng như hiển thị văn bản, như bạn có thể thấy từ ảnh chụp màn hình, nơi các màu khác nhau đã được sử dụng cho mỗi số.

Từ ảnh chụp màn hình, bạn cũng có thể nhận thấy một sự khác biệt khác khi so sánh ItemControl với ListBox: Theo mặc định, một đường viền được hiển thị xung quanh điều khiển, làm cho nó trông giống như một điều khiển thực tế thay vì chỉ xuất ra.

Data binding the ListBox

Các mục xác định thủ công cho ListBox tạo ra một ví dụ đầu tiên tốt, nhưng hầu hết các lần, các điều khiển ListBox của bạn sẽ được lấp đầy với các mục từ nguồn dữ liệu bằng cách sử dụng liên kết dữ liệu. Theo mặc định, nếu bạn liên kết danh sách các mục với ListBox, phương thức ToString() của chúng sẽ được sử dụng để thể hiện từng mục. Điều này hiếm khi là những gì bạn muốn, nhưng may mắn thay, chúng ta có thể dễ dàng khai báo một mẫu sẽ được sử dụng để hiển thị từng mục.

Tôi đã sử dụng lại ví dụ dựa trên TODO từ bài viết ItemControl, nơi chúng tôi xây dựng một danh sách TODO thú vị bằng cách sử dụng lớp Code-behind đơn giản và trong trường hợp này là điều khiển ListBox cho biểu diễn trực quan. Đây là ví dụ:

<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; }
	}
}

Tất cả các phép thuật xảy ra trong ItemTemplate mà chúng tôi đã xác định cho ListBox. Trong đó, chúng tôi chỉ định rằng mỗi mục ListBox phải bao gồm một Lưới, được chia thành hai cột, với TextBlock hiển thị tiêu đề ở đầu tiên và một ProgressBar hiển thị trạng thái hoàn thành trong cột thứ hai. Để lấy các giá trị ra, chúng tôi sử dụng một số ràng buộc dữ liệu rất đơn giản, tất cả được giải thích trong phần ràng buộc dữ liệu của hướng dẫn này.

Trong tệp Code-behind, chúng tôi đã khai báo một lớp TodoItem rất đơn giản để chứa từng mục TODO của chúng tôi. Trong hàm tạo của cửa sổ, chúng tôi khởi tạo một danh sách, thêm ba mục TODO vào đó và sau đó gán nó cho ItemSource của ListBox. Sự kết hợp của ItemSource và ItemTemplate mà chúng tôi đã chỉ định trong phần XAML, đây là tất cả WPF cần để hiển thị tất cả các mục dưới dạng danh sách TODO.

Vui lòng lưu ý thuộc tính HorizontalContentAlignment mà tôi đặt thành Stretch trên ListBox. Căn chỉnh nội dung mặc định cho một mục ListBox là Left, có nghĩa là mỗi mục chỉ chiếm nhiều không gian ngang như nó cần. Kết quả? Chà, không hoàn toàn như những gì chúng ta muốn:

Bằng cách sử dụng căn chỉnh Stretch, mỗi mục được kéo dài để chiếm toàn bộ dung lượng có sẵn, như bạn có thể thấy từ ảnh chụp màn hình trước đó.

Working with ListBox selection

Như đã đề cập, một điểm khác biệt chính giữa ItemControl và ListBox là ListBox xử lý và hiển thị lựa chọn người dùng cho bạn. Do đó, rất nhiều câu hỏi ListBox xoay quanh việc bằng cách nào đó làm việc với lựa chọn. Để giúp với một số câu hỏi này, tôi đã tạo một ví dụ lớn hơn, cho bạn thấy một số thủ thuật liên quan đến lựa chọn:

<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; }
	}
}

Như bạn có thể thấy, tôi đã xác định một loạt các nút ở bên phải của ListBox, để lấy hoặc thao tác lựa chọn. Tôi cũng đã thay đổi SelectionMode thành Extended, để cho phép lựa chọn nhiều mục. Điều này có thể được thực hiện bằng lập trình, như tôi làm trong ví dụ hoặc bởi người dùng bằng cách giữ [Ctrl] hoặc [Shift] trong khi nhấp vào các mục.

Đối với mỗi nút, tôi đã xác định trình xử lý nhấp chuột trong Code-behind. Mỗi hành động nên tự giải thích và mã C# được sử dụng khá đơn giản, nhưng nếu bạn vẫn còn nghi ngờ, hãy thử chạy ví dụ trên máy của riêng bạn và kiểm tra các khả năng khác nhau trong ví dụ.

Tổng kết

Điều khiển ListBox giống như ItemControl và một số kỹ thuật tương tự có thể được sử dụng. ListBox cung cấp nhiều chức năng hơn một chút khi so sánh với ItemControl, đặc biệt là việc xử lý lựa chọn. Để có nhiều chức năng hơn, như tiêu đề cột, bạn nên xem điều khiển ListView, được đưa ra một mô tả rất kỹ sau này trong hướng dẫn này với một số bài viết giải thích tất cả các chức năng.

This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!