This article has been localized into Russian by the community.
Элемент управления ComboBox
Элемент управления ComboBox во многом похож на элемент управления ListBox, но занимает значительно меньше места, потому что список элементов скрыт, когда он не нужен. Элемент управления ComboBox повсеместно используется в 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 равным True.
Форматирование элементов
В первом примере мы показали список состоящий из текстовых элементов. Это довольно распространенный способ использования элемента управления 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. Это дает нам полный контроль над содержимым, а также управление отрисовкой текста, что заметно на скриншоте, где и цвет текста, и изображение указывают значение цвета.
Связывание данных (Data binding) в ComboBox
Как видно из первых примеров, задавать элементы списка ComboBox из XAML очень просто, но у вас, скорее всего, скоро возникнет ситуация когда понадобятся элементы поступающие из какого-то источника, например, базы данных или списка в памяти. Используя привязку данных (data binding) мы можем легко отобразить список цветов, с предварительным просмотром цвета:
<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();
}
}
}
Все довольно просто: В C# я получаю список всех цветов из класса Colors через рефлексию и назначаю его свойству ItemsSource ComboBox, которое затем отображает каждый цвет, используя шаблон из XAML.
Каждый элемент, определенный в ItemTemplate, состоит из StackPanel содержащей Rectangle и TextBlock, каждый из которых привязан к значению цвета. Это дает нам полный список цветов, с минимальными усилиями - выглядит неплохо, не правда ли?
Свойство 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 для обработки любого изменения ComboBox, вызванного пользователем или кодом.
Пример:
<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 для выбора определенного элемента на основе его значения. Здесь я использую рефлексию потому что ComboBox привязан к списку цветов из класса Color, и нам требуется свойству SelectedItem присвоить именно значение определенного цвета (Blue) из класса Color.
В четвертом и последнем обработчике я работаю с событием SelectionChanged которое срабатывает при изменении значения ComboBox. Когда это происходит, я через рефлексию получаю значение выбранного цвета и использую его для создания кисти которая задает фон окна. Результат можно увидеть на скриншоте.
Если вы работает с редактируемым ComboBox (свойство IsEditable установленно в True), вы можете прочитать свойство Text чтобы узнать какое значение ввел или выбрал пользователь.