WPF + MVVM: переопределить автозаполнение в DataGridComboBoxColumn

1

Я искал довольно долгое время, но не могу понять, как переопределить функциональность автозаполнения в 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, и снабдить его некоторой пользовательской логикой, например, предоставление анонимной функции в ее конструкторе, чтобы в будущем поведение автозаполнения можно было переопределить по-разному.

Возможно ли это, или я об этом совершенно неправильно?

Теги:
wpf
combobox
mvvm
autocomplete

1 ответ

0

Я не говорю, что ваш подход ошибочен, однако я бы поступил иначе. Для меня проще использовать 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 не должна возникать. Правильно ли вы используете его? См. Эту ссылку для примера.

  • 0
    Привет Мартейн, спасибо за твой ответ. Я абстрагировался от DataGridComboBoxColumn, который уже является пользовательским классом. Я не собираюсь менять это прямо сейчас. Однако могу ли я также использовать <Style TargetType = "MyCustomComboBox">? Кроме того, у меня проблемы не только с сеткой: как бы я добавил функцию автозаполнения в ComboBox? Могу ли я прикрепить обработчик к событию? Если да, то какое событие? Фрагмент кода будет высоко ценится.
  • 0
    Изменить: Обратите внимание, что при использовании вашего предложения я получаю сообщение об ошибке «Элемент« CellTemplate »не распознан или недоступен».
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню