Подскажите, как сделать, чтобы текст, раннее введенный в ячейку DataGrid, повторялся после следующего ввода в другую ячейку (примерно как в Excel, см. анимацию)?
Подобное поведение есть в штатном ComboBox
(в режиме IsEditable="True"
), можно этим воспользоваться. Я покопался в шаблоне и выбросил всё лишнее, получается вот что:
<ComboBox IsEditable="True" Padding="0" ItemsSource="{Binding Strings}">
<ComboBox.Template>
<ControlTemplate>
<TextBox x:Name="PART_EditableTextBox" Margin="{TemplateBinding Padding}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
</ControlTemplate>
</ComboBox.Template>
</ComboBox>
В ItemsSource
привязываете коллекцию строк из которых надо автодополнять, результат ввода можно забирать из свойства Text
:
Итак, применить этот трюк с ComboBox
совместно с DataGrid
мне до конца не удалось (с другой стороны, пихать ComboBox
внутрь шаблона TextBox
может быть не слишком уж и рационально), поэтому предлагаю другое решение — написать самостоятельно функционал автодополнения (на самом деле он довольно прост в написании) или взять готовый.
Я взял по одной из первых ссылок в google этот пакет: WPFTextBoxAutoComplete (здесь можно посмотреть как его использовать).
Пишем VM-часть. Мы должны подготовить строки для автодополнения. Пусть у меня такая простая сущность:
class ItemVm : Vm
{
string name;
public string Name
{
get => name;
set => Set(ref name, value);
}
}
А в главной VM коллекция этих сущностей:
public ObservableCollection<ItemVm> Items { get; } = new ObservableCollection<ItemVm>();
Тогда я могу в главной VM выставить такое свойство:
public IEnumerable<string> Strings => Items.Select(i => i.Name).Distinct().OrderBy(s => s);
Остается только как-то оповещать при изменениях строк, это не сильно сложно:
public MainVm()
{
Items.CollectionChanged += OnItemsCollectionChanged;
}
private void OnItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (ItemVm item in e.NewItems)
item.PropertyChanged += OnItemPropertyChanged;
break;
case NotifyCollectionChangedAction.Remove:
foreach (ItemVm item in e.OldItems)
item.PropertyChanged -= OnItemPropertyChanged;
break;
// Остальные Action
}
NotifyPropertyChanged(nameof(Strings));
}
private void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(ItemVm.Name))
NotifyPropertyChanged(nameof(Strings));
}
Готово. Теперь представление:
<DataGrid ItemsSource="{Binding Items}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}">
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
Ячейка во время редактирования превращается в TextBox без границ, переопределяем стиль для нее:
<DataGridTextColumn.EditingElementStyle>
<Style TargetType="TextBox">
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="behaviors:AutoCompleteBehavior.AutoCompleteItemsSource"
Value="{Binding DataContext.Strings, RelativeSource={RelativeSource AncestorType=DataGrid}}"/>
</Style>
</DataGridTextColumn.EditingElementStyle>
где xmlns:behaviors="clr-namespace:WPFTextBoxAutoComplete;assembly=WPFTextBoxAutoComplete"
— пространство имен, которое вам необходимо подключить
Пример почти работает, за исключением первого нажатия в ячейке — автодополнение срабатывает, но при этом слетает выделение, что ведет к неудобству использования, вы столкнетесь с этим независимо от того, будете ли писать свое автодополнение или возьмете готовое.
Я решил это следующим образом, добавим в стиль обработчик события Loaded
(да, TextBox еще не загружен в том момент, когда он обработал первое нажатие! и при загрузке сбрасывает выделение):
<EventSetter Event="Loaded" Handler="TextBox_Loaded"/>
В обработчике пишем:
private void TextBox_Loaded(object sender, RoutedEventArgs e)
{
var textBox = (TextBox)sender;
if (textBox.IsSelectionActive)
textBox.SelectionLength = textBox.Text.Length - textBox.SelectionStart;
}
т.е. просто восстанавливаем выделение.
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Допустим есть файлВ один момент времени им может пользоваться один инстанс программы
Допустим в поле БД надо поместить список id пользователей, для этого, вероятнее всего, надо юзать массив с разделителями