-
列表控件:

ComboBox控件

组合框(ComboBox)控件在很多方面类似于列表框(ListBox)控件,但占用的空间更少,因为该控件在不需要时可以隐藏项列表。该控件在Windows中使用很多,但为了确保每个人都了解它的外观和工作方式,我们将直接跳到一个简单的例子:

<Window x:Class="WpfTutorialSamples.ComboBox_control.ComboBoxSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ComboBoxSample" Height="150" Width="200">
    <StackPanel Margin="10">
        <ComboBox>
            <ComboBoxItem>ComboBox Item #1</ComboBoxItem>
            <ComboBoxItem IsSelected="True">ComboBox Item #2</ComboBoxItem>
            <ComboBoxItem>ComboBox Item #3</ComboBoxItem>
        </ComboBox>
    </StackPanel>
</Window>

在屏幕截图中,我通过单击来激活控件,从而显示项列表。 从代码中可以看出,ComboBox简单的形式让使用时很容易。 我在这里只是手动添加一些项,通过在其上设置IsSelected属性使其中一个项成为默认选中。

自定义内容

在第一个例子中,我们只显示了文本项,这对于ComboBox控件来说很常见,但由于ComboBoxItem是一个ContentControl,我们其实可以使用任何东西作为内容。 让我们尝试制作一个稍微复杂的项列表:

<Window x:Class="WpfTutorialSamples.ComboBox_control.ComboBoxCustomContentSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ComboBoxCustomContentSample" Height="150" Width="200">
    <StackPanel Margin="10">
        <ComboBox>
            <ComboBoxItem>
                <StackPanel Orientation="Horizontal">
                    <Image Source="/WpfTutorialSamples;component/Images/bullet_red.png" />
                    <TextBlock Foreground="Red">Red</TextBlock>
                </StackPanel>
            </ComboBoxItem>
            <ComboBoxItem>
                <StackPanel Orientation="Horizontal">
                    <Image Source="/WpfTutorialSamples;component/Images/bullet_green.png" />
                    <TextBlock Foreground="Green">Green</TextBlock>
                </StackPanel>
            </ComboBoxItem>
            <ComboBoxItem>
                <StackPanel Orientation="Horizontal">
                    <Image Source="/WpfTutorialSamples;component/Images/bullet_blue.png" />
                    <TextBlock Foreground="Blue">Blue</TextBlock>
                </StackPanel>
            </ComboBoxItem>
        </ComboBox>
    </StackPanel>
</Window>

对于每个ComboBoxItem,我们添加一个StackPanel,我们在里面添加一个Image和一个TextBlock。 我们可以完全控制内容和文本渲染,如截图所示,文本颜色和图像都指示颜色值。

数据绑定ComboBox

从第一个示例中可以看出,使用XAML可以很容易地手动定义ComboBox控件的项,但是很可能会遇到需要来自某种数据源的项的情况,比如数据库或者内存列表。 使用WPF数据绑定和自定义模板,我们可以轻松渲染颜色列表,包括颜色预览:

<Window x:Class="WpfTutorialSamples.ComboBox_control.ComboBoxDataBindingSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ComboBoxDataBindingSample" Height="200" Width="200">
    <StackPanel Margin="10">
        <ComboBox Name="cmbColors">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Rectangle Fill="{Binding Name}" Width="16" Height="16" Margin="0,2,5,2" />
                        <TextBlock Text="{Binding Name}" />
                    </StackPanel>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>
    </StackPanel>
</Window>
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;

namespace WpfTutorialSamples.ComboBox_control
{
	public partial class ComboBoxDataBindingSample : Window
	{
		public ComboBoxDataBindingSample()
		{
			InitializeComponent();
			cmbColors.ItemsSource = typeof(Colors).GetProperties();
		}
	}
}

它其实非常简单:在后台代码中,我使用反射Colors类的方法和获得所有颜色的列表。 我将它分配给ComboBox的ItemsSource属性,然后使用我在XAML部分中定义的模板呈现每个颜色。

ItemTemplate定义的每个项都包含一个带有Rectangle和TextBlock的StackPanel,每个项都绑定到颜色值。 这给了我们一个完整的颜色列表,只需要很少的工作量 - 它看起来很不错,对吧?

IsEditable

在第一个示例中,用户只能从我们的项列表中进行选择,但ComboBox的一个很酷的事情是它支持让用户从项列表中选择或输入自己的值。 在您希望通过为用户提供预定义选项集来帮助用户的情况下非常有用,同时仍然为他们提供手动输入所需值的选项。 这全部由IsEditable属性控制,它可以更改ComboBox的行为和外观:

<Window x:Class="WpfTutorialSamples.ComboBox_control.ComboBoxEditableSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ComboBoxEditableSample" Height="150" Width="200">
    <StackPanel Margin="10">
        <ComboBox IsEditable="True">
            <ComboBoxItem>ComboBox Item #1</ComboBoxItem>
            <ComboBoxItem>ComboBox Item #2</ComboBoxItem>
            <ComboBoxItem>ComboBox Item #3</ComboBoxItem>
        </ComboBox>
    </StackPanel>
</Window>

如您所见,我可以随意输入什么值或从列表中选择一个。 如果从列表中选中,它会覆盖ComboBox的文本。

还有自动完成功能,ComboBox将自动尝试帮助用户在输入时选择现有值,如下一个屏幕截图所示,我刚刚开始输入“Co”:

默认情况下,匹配不区分大小写,但您可以通过将IsTextSearchCaseSensitive设置为True来区分。 如果您根本不想要自动完成功能,可以通过将IsTextSearchEnabled设置为False来禁用它。

使用ComboBox选择

使用ComboBox控件的关键部分是能够读取用户选择,甚至可以使用代码控制它。 在下一个示例中,我重新使用了数据绑定的ComboBox示例,但添加了一些用于控制选择的按钮。 我还使用SelectionChanged事件来捕获所选项的变化,无论用代码还是用户,并对其进行操作。

这是例子:

<Window x:Class="WpfTutorialSamples.ComboBox_control.ComboBoxSelectionSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ComboBoxSelectionSample" Height="125" Width="250">
    <StackPanel Margin="10">
        <ComboBox Name="cmbColors" SelectionChanged="cmbColors_SelectionChanged">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Rectangle Fill="{Binding Name}" Width="16" Height="16" Margin="0,2,5,2" />
                        <TextBlock Text="{Binding Name}" />
                    </StackPanel>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>
        <WrapPanel Margin="15" HorizontalAlignment="Center">
            <Button Name="btnPrevious" Click="btnPrevious_Click" Width="55">Previous</Button>
            <Button Name="btnNext" Click="btnNext_Click" Margin="5,0" Width="55">Next</Button>
            <Button Name="btnBlue" Click="btnBlue_Click" Width="55">Blue</Button>
        </WrapPanel>
    </StackPanel>
</Window>
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Windows;
using System.Windows.Media;

namespace WpfTutorialSamples.ComboBox_control
{
	public partial class ComboBoxSelectionSample : Window
	{
		public ComboBoxSelectionSample()
		{
			InitializeComponent();
			cmbColors.ItemsSource = typeof(Colors).GetProperties();
		}

		private void btnPrevious_Click(object sender, RoutedEventArgs e)
		{
			if(cmbColors.SelectedIndex > 0)
				cmbColors.SelectedIndex = cmbColors.SelectedIndex - 1;
		}

		private void btnNext_Click(object sender, RoutedEventArgs e)
		{
			if(cmbColors.SelectedIndex < cmbColors.Items.Count-1)
				cmbColors.SelectedIndex = cmbColors.SelectedIndex + 1;
		}

		private void btnBlue_Click(object sender, RoutedEventArgs e)
		{
			cmbColors.SelectedItem = typeof(Colors).GetProperty("Blue");
		}

		private void cmbColors_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
		{
			Color selectedColor = (Color)(cmbColors.SelectedItem as PropertyInfo).GetValue(null, null);
			this.Background = new SolidColorBrush(selectedColor);
		}
	}
}

这个例子的有趣部分是三个按钮的事件处理程序,以及SelectionChanged事件处理程序。 前两个按钮中,我们通过读取SelectedIndex属性然后减去或加上一来选择上一个或下一个项。 非常简单易用。

在第三个事件处理程序中,我们使用SelectedItem根据值选择特定项。 我在这里做了一些额外的工作(使用.NET反射),因为ComboBox被绑定到一个属性列表,每个属性都是一种颜色,而不是一个简单的颜色列表,基本上就是将一个项包含的值赋予SelectedItem属性。

在第四个和最后一个事件处理程序中,我响应所选项的变化。 变化时,我会读取所选颜色(再次使用反射,如上所述),然后使用所选颜色为窗口创建新的背景画笔。 可以在屏幕截图中看到效果。

如果您使用可编辑的ComboBox(IsEditable属性设置为true),可以读取Text属性以了解用户输入或选择的值。