Я искал довольно долгое время, но не могу понять, как переопределить функциональность автозаполнения в DataGridComboBoxColumn.
То, что я хочу сделать, это то, что объясняется здесь, за исключением combobox: Поиск элементов в списке
То есть: я хочу иметь возможность вводить любую строку, а затем применять фильтр к элементам ComboBox в DataGridComboBoxColumn для отображения только тех элементов, которые соответствуют этому как подстрока.
Я новичок в WPF и некоторое время искал в Интернете. Я нашел такие вещи, как EventSetters и CommandBehaviorCollection.Behaviors, но я не могу получить четкую картину возможностей (и невозможностей).
У меня есть:
<DataGrid ... >
...
<DataGrid.Columns>
...
<MyCustomDataGridComboBoxColumn Header="My Header" MinWidth="200" >
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding DataContext.MyData, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
<Setter Property="SelectedItem" Value="{Binding DataItem, UpdateSourceTrigger=LostFocus, ValidatesOnDataErrors=True}" />
<Setter Property="DisplayMemberPath" Value="HardwareId" />
</Style>
</DataGridComboBoxColumn.ElementStyle>
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding DataContext.MyFilteredData, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
<Setter Property="SelectedItem" Value="{Binding DataItem, UpdateSourceTrigger=LostFocus}" />
<Setter Property="DisplayMemberPath" Value="HardwareId" />
<Setter Property="IsEditable" Value="True"/>
<Setter Property="Text" Value="{Binding DataContext.MyNewDataItem, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, UpdateSourceTrigger=LostFocus, ValidatesOnDataErrors=True, NotifyOnValidationError=True}" />
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
</MyCustomDataGridComboBoxColumn>
...
</DataGrid.Columns>
</DataGrid>
В идеале я хотел бы создать новый класс, который наследует от DataGridComboBoxColumn, и снабдить его некоторой пользовательской логикой, например, предоставление анонимной функции в ее конструкторе, чтобы в будущем поведение автозаполнения можно было переопределить по-разному.
Возможно ли это, или я об этом совершенно неправильно?
Я не говорю, что ваш подход ошибочен, однако я бы поступил иначе. Для меня проще использовать DataGridTemplateColumn и поставлять ComboBox, у которого есть функциональность, о которой вы говорите.
<DataGridTemplateColumn Header="ColumnName" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<YourCustomComboBox/>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Редактировать:
Некоторое время назад мне нужен ComboBox с такой же функциональностью. Я закончил комбинирование TextBox с элементом управления Popup, потому что он дал мне гораздо больше контроля над ним.
<TextBox Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}" x:Name="editBox"/>
<Popup x:Name="textboxPopup" Width="{Binding ElementName=editBox, Path=ActualWidth, Mode=OneWay}"
PlacementTarget="{Binding ElementName=editBox}"
StaysOpen="False"
IsOpen="{Binding Path=IsOpen, Mode=OneWay}">
<Grid>
<DockPanel MaxHeight="500">
<ListView SelectionMode="Single"
ItemsSource="{Binding Path=Suggestions}"
Name="popupList">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"Color="LightBlue"/>
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="LightBlue"/>
</Style.Resources>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="LightBlue"/>
</Trigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
</ListView>
</DockPanel>
</Grid>
В codebehind я подписался на событие TextChanged и несколько других событий, которые вам пригодились. Я не могу использовать весь свой код, потому что это производственный код. Однако есть несколько других людей в Интернете с аналогичными реализациями: использование ComboBox, использование текстового поля и, конечно, ссылка, которую вы разместили в своем вопросе. Там более чем достаточно.
И об использовании вашего настраиваемого элемента управления в качестве TargetType... Я не вижу в этом ничего плохого, я делаю это все время.
Ошибка с CellTemplate не должна возникать. Правильно ли вы используете его? См. Эту ссылку для примера.