В ходе обучения разработке приложений WPF
экспериментально установил, что функция автозаполнения в ComboBox
работает только когда внутри - цельный TextBlock
(поправьте, если это не так). Пример:
<ComboBox Name="People" IsEditable="True">
<TextBlock>Andrew Invanov</TextBlock>
<TextBlock>Sergey Petrov</TextBlock>
<TextBlock>Valadimir Sidorov</TextBlock>
<TextBlock>Nikolay Kuznetsow</TextBlock>
</ComboBox>
Теперь предположим, что мы хотим включить в список не только имя и фамилию, но и какой-нибудь ID, при этом хотим, чтобы автозаполнение работало как при вводе первых цифер ID, так и при вводе первых букв имени. Можно ли это реализовать, и если да, то как? Только программно?
ID и имя разнесены в разные TextBlock
затем, чтобы к ID и имени можно было применить разные стили.
<ComboBox Name="People" Height="30" VerticalAlignment="Top" IsEditable="True">
<ComboBoxItem>
<StackPanel Orientation="Horizontal">
<TextBlock Padding="0 0 10 0">3845</TextBlock>
<TextBlock>Andrew Invanov</TextBlock>
</StackPanel>
</ComboBoxItem>
<ComboBoxItem>
<StackPanel Orientation="Horizontal">
<TextBlock Padding="0 0 10 0">3845</TextBlock>
<TextBlock>Sergey Petrov</TextBlock>
</StackPanel>
</ComboBoxItem>
<ComboBoxItem>
<StackPanel Orientation="Horizontal">
<TextBlock Padding="0 0 10 0">3845</TextBlock>
<TextBlock>Valadimir Sidorov</TextBlock>
</StackPanel>
</ComboBoxItem>
<ComboBoxItem>
<StackPanel Orientation="Horizontal">
<TextBlock Padding="0 0 10 0">3845</TextBlock>
<TextBlock>Nikolay Kuznetsow</TextBlock>
</StackPanel>
</ComboBoxItem>
</ComboBox>
Если для ответа на данный вопрос Вам нужно поэкспериментировать с кодом, то в целях экономии Вашего времени я подготовил проект для Visual Studio с начальной разметкой ComboBox
.
Ссылка на Яндекс Диск (возможно станет недоступна после получения ответа на вопрос).
Разметка
<ComboBox Name="boxOrig" IsEditable="True" Height="30" >
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Padding="0 0 10 0" Text="{Binding id}"></TextBlock>
<TextBlock Text="{Binding name}"></TextBlock>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Список с элементами
class Lol
{
public int id { get; set; }
public string name { get; set; }
public override string ToString()
{
return id + " " + name;
}
}
List<Lol> list = new List<Lol>()
{
new Lol()
{
id = 1,
name = "Andrew Invanov"
},
new Lol()
{
id = 2,
name = "Sergey Petrov"
},
new Lol()
{
id = 3,
name = "Valadimir Sidorov"
},
new Lol()
{
id = 4,
name = "Nikolay Kuznetsow"
}
};
Фильтрация
public MainWindow()
{
InitializeComponent();
boxOrig.ItemsSource = list;
boxOrig.DropDownOpened+= delegate(object sender, EventArgs args)
{
filter(boxOrig.Text, true);
};
boxOrig.PreviewTextInput += (sender, args) =>
{
string text = boxOrig.Text + args.Text;
filter(text);
};
}
private void filter(string text, bool drop=false)
{
var filtered = list
.Where(x => x.id.ToString().StartsWith(text, true) || x.name.StartsWith(text, true))
.ToList();
if (filtered.Count > 0 )
{
boxOrig.ItemsSource = filtered;
boxOrig.SelectedItem = filtered.First();
if (!drop) //Обновление текста в ComboBox
{
boxOrig.IsEditable = false;
boxOrig.IsEditable = true;
}
}
}
Нашел метод расширения для отображения Dropdown'a
при изменении текста в ComboBox
и возможности фильтрации не только по началу текста.
boxOrig.MakeComboBoxSearchable(
searchText => (item =>
{
Lol lolItem = (Lol) item;
return lolItem.id.ToString().StartsWith(searchText, true, CultureInfo.InvariantCulture)
|| lolItem.name.StartsWith(searchText, true, CultureInfo.InvariantCulture);
})
);
Класс с расширением
public static class Extensions
{
public static void MakeComboBoxSearchable(this ComboBox targetComboBox,
Func<string, Predicate<object>> itemsFilter = null)
{
if (itemsFilter == null)
{
itemsFilter = searchText => (item =>
item.ToString().ToLower().Contains(searchText.ToLower()));
}
targetComboBox.Loaded += (sender, e) => TargetComboBox_Loaded(sender, e, itemsFilter);
}
private static void TargetComboBox_Loaded(object sender, RoutedEventArgs e,
Func<string, Predicate<object>> itemsFilter)
{
var targetComboBox = sender as ComboBox;
var targetTextBox = targetComboBox?.Template.FindName("PART_EditableTextBox", targetComboBox) as TextBox;
if (targetTextBox == null) return;
targetComboBox.Tag = "TextInput";
targetComboBox.StaysOpenOnEdit = true;
targetComboBox.IsEditable = true;
targetComboBox.IsTextSearchEnabled = false;
targetTextBox.TextChanged += (o, args) =>
{
var textBox = (TextBox) o;
var searchText = textBox.Text;
if (targetComboBox.Tag.ToString() == "Selection")
{
targetComboBox.Tag = "TextInput";
targetComboBox.IsDropDownOpen = true;
}
else
{
if (targetComboBox.SelectionBoxItem != null)
{
targetComboBox.SelectedItem = null;
targetTextBox.Text = searchText;
textBox.CaretIndex = targetTextBox.Text.Length;
}
if (string.IsNullOrEmpty(searchText))
{
targetComboBox.Items.Filter = item => true;
targetComboBox.SelectedItem = default(object);
}
else
targetComboBox.Items.Filter = itemsFilter(searchText);
Keyboard.ClearFocus();
Keyboard.Focus(targetTextBox);
targetComboBox.IsDropDownOpen = true;
targetTextBox.SelectionStart = targetTextBox.Text.Length;
}
};
targetComboBox.SelectionChanged += (o, args) =>
{
var comboBox = o as ComboBox;
if (comboBox?.SelectedItem == null) return;
comboBox.Tag = "Selection";
};
}
}
Разметка
<ComboBox Name="boxOrig" Height="30" >
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Padding="0 0 10 0" Text="{Binding id}"></TextBlock>
<TextBlock Text="{Binding name}"></TextBlock>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Список с элементами
class Lol
{
public int id { get; set; }
public string name { get; set; }
public override string ToString()
{
return id + " " + name;
}
}
List<Lol> list = new List<Lol>()
{
new Lol() {id = 1, name = "Andrew Invanov"},
new Lol() {id = 2, name = "Sergey Petrov"},
new Lol() {id = 3, name = "Valadimir Sidorov"},
new Lol() {id = 4, name = "Nikolay Kuznetsow"},
new Lol() {id = 5, name = "Nikolay Petrov"}
};
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Виртуальный выделенный сервер (VDS) становится отличным выбором
Как это было отмечено в одном из комментариев к вопросу Ввод данных во ViewModel, хранение данных во ViewModel является противоречием шаблону MVVM, но во всех...
Без шаблона MVVM, вызов нового окна в приложениях WPF довольно прост:
ПриветсвтуюНаписал на c# простое приложение клиент-сервер
Помогите пожалуйстаМне нужно, чтобы пользователь мог вводить символы (на месте курсора), и введенные данные отображались в том же месте (на месте...