имбирь ниндзя |Келли |Diederik Krols определенно предлагает отличное решение «все в одном», но для простых случаев использования оно может оказаться сложным.Например, производная ComboBox
получает ссылку на внутреннее редактируемое текстовое поле.Как указывает Дидерик, «Нам нужно это, чтобы получить доступ к выбору». .Что не может быть требованием вообще.Вместо этого мы могли бы просто привязать свойство Text
.
<ComboBox
ItemsSource="{Binding Agencies}"
SelectedItem="{Binding SelectedAgency}"
Text="{Binding SearchText}"
IsTextSearchEnabled="False"
DisplayMemberPath="ComboText"
IsEditable="True"
StaysOpenOnEdit="True"
MinWidth="200" />
Еще одно возможное улучшение - это выставить фильтр, чтобы разработчики могли легко его изменить.Оказывается, все это можно сделать из модели представления.Чтобы было интересно, я решил использовать свойство Agency
ComboText
для DisplayMemberPath
, но его свойство Name
для пользовательского фильтра.Конечно, вы можете настроить это так, как вам нравится.
public class MainViewModel : ViewModelBase
{
private readonly ObservableCollection<Agency> _agencies;
public MainViewModel()
{
_agencies = GetAgencies();
Agencies = (CollectionView)new CollectionViewSource { Source = _agencies }.View;
Agencies.Filter = DropDownFilter;
}
#region ComboBox
public CollectionView Agencies { get; }
private Agency selectedAgency;
public Agency SelectedAgency
{
get { return selectedAgency; }
set
{
if (value != null)
{
selectedAgency = value;
OnPropertyChanged();
SearchText = selectedAgency.ComboText;
}
}
}
private string searchText;
public string SearchText
{
get { return searchText; }
set
{
if (value != null)
{
searchText = value;
OnPropertyChanged();
if(searchText != SelectedAgency.ComboText) Agencies.Refresh();
}
}
}
private bool DropDownFilter(object item)
{
var agency = item as Agency;
if (agency == null) return false;
// No filter
if (string.IsNullOrEmpty(SearchText)) return true;
// Filtered prop here is Name != DisplayMemberPath ComboText
return agency.Name.ToLower().Contains(SearchText.ToLower());
}
#endregion ComboBox
private static ObservableCollection<Agency> GetAgencies()
{
var agencies = new ObservableCollection<Agency>
{
new Agency { AgencyNumber = 1, Name = "Foo", Title = "A" },
new Agency { AgencyNumber = 2, Name = "Bar", Title = "C" },
new Agency { AgencyNumber = 3, Name = "Elo", Title = "B" },
new Agency { AgencyNumber = 4, Name = "Baz", Title = "D" },
new Agency { AgencyNumber = 5, Name = "Hello", Title = "E" },
};
return agencies;
}
}
Основные ошибки:
- Когда пользователь вводит запрос, а затем выбирает элемент из отфильтрованного списка,мы хотим, чтобы
SearchText
соответственно обновлялся. - Когда это происходит, мы не хотим обновлять фильтр.Для этой демонстрации мы используем другое свойство для
DisplayMemberPath
и наш пользовательский фильтр.Поэтому, если бы мы позволили фильтру обновиться, отфильтрованный список был бы пустым (совпадений не найдено), а выбранный элемент также был бы очищен.
В заключительной ноте, если указать ComboBox
ItemTemplate
, вам нужно будет установить TextSearch.TextPath
вместо DisplayMemberPath
.