In my WPF window app I a have a combo box which gets populated on the app is launched & I also wanted to enable a suggestappend type feature for the combo box (using this). But when I try to type something on the combo box I get the error : System.InvalidOperationException: Items collection must be empty before using ItemsSource.
How do I get rid of this? I want to both select from drop down list or start typing in combo box and then select item from there on window load.
public partial class Window1 : Window
{
List<string> Names= new List<string>();
int lastRow = 0;
string file_Bills=@"BILLS.xlsx";
string file_CNDN=@"CN_DN.xlsx";
string file_supp=@"suppliers.xlsx";
public Window1()
{
InitializeComponent();
ExcelPackage.LicenseContext =LicenseContext.NonCommercial;
FillCombo();
}
public List<string> FillCombo()
{
using (ExcelPackage package = new ExcelPackage(new System.IO.FileInfo(file_Bills), false))
{
ExcelWorksheet mainSheet = package.Workbook.Worksheets.First();
for (int i = 2; i <= mainSheet.Dimension.End.Row; i++)
{
if (!string.IsNullOrEmpty(mainSheet.Cells["A"+i].Text))
{
lastRow =i;
}
}
List<string> party = new List<string>();
for (int row = 2; row <= lastRow; row++)
{
if (!string.IsNullOrEmpty(mainSheet.Cells[row, 1].Text))
{
party.Add(mainSheet.Cells[row, 1].Text);
}
}
foreach (var element in party.OrderBy(a=>a.ToLowerInvariant()).Distinct())
{
cmb.Items.Add(element);
Names.Add(element);
}
}
return Names;
}
//portion implementing the suggestappend like feature
public static T GetChildOfType<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj == null) return null;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
var child = VisualTreeHelper.GetChild(depObj, i);
var result = (child as T) ?? GetChildOfType<T>(child);
if (result != null) return result;
}
return null;
}
private void PreviewTextInput_EnhanceComboSearch(object sender, TextCompositionEventArgs e)
{
ComboBox cmb = (ComboBox)sender;
cmb.IsDropDownOpen = true;
if (!string.IsNullOrEmpty(cmb.Text))
{
string fullText = cmb.Text.Insert(GetChildOfType<TextBox>(cmb).CaretIndex, e.Text);
cmb.ItemsSource = Names.Where(s => s.IndexOf(fullText, StringComparison.InvariantCultureIgnoreCase) != -1).ToList();
}
else if (!string.IsNullOrEmpty(e.Text))
{
cmb.ItemsSource = Names.Where(s => s.IndexOf(e.Text, StringComparison.InvariantCultureIgnoreCase) != -1).ToList();
}
else
{
cmb.ItemsSource = Names;
}
}
private void Pasting_EnhanceComboSearch(object sender, DataObjectPastingEventArgs e)
{
ComboBox cmb = (ComboBox)sender;
cmb.IsDropDownOpen = true;
string pastedText = (string)e.DataObject.GetData(typeof(string));
string fullText = cmb.Text.Insert(GetChildOfType<TextBox>(cmb).CaretIndex, pastedText);
if (!string.IsNullOrEmpty(fullText))
{
cmb.ItemsSource = Names.Where(s => s.IndexOf(fullText, StringComparison.InvariantCultureIgnoreCase) != -1).ToList();
}
else
{
cmb.ItemsSource = Names;
}
}
private void PreviewKeyUp_EnhanceComboSearch(object sender, KeyEventArgs e)
{
if (e.Key == Key.Back || e.Key == Key.Delete)
{
ComboBox cmb = (ComboBox)sender;
cmb.IsDropDownOpen = true;
if (!string.IsNullOrEmpty(cmb.Text))
{
cmb.ItemsSource = Names.Where(s => s.IndexOf(cmb.Text, StringComparison.InvariantCultureIgnoreCase) != -1).ToList();
}
else
{
cmb.ItemsSource = Names;
}
}
}
}
XAML:
<ComboBox
IsTextSearchEnabled="False"
PreviewTextInput="PreviewTextInput_EnhanceComboSearch"
PreviewKeyUp="PreviewKeyUp_EnhanceComboSearch"
DataObject.Pasting="Pasting_EnhanceComboSearch"
IsEditable="True"
Name="cmb"
Grid.Column="0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
FontFamily="Segoe UI"
FontStyle="Normal"
FontSize="18"
Margin="10 10 10 0"
Height="35"
MaxHeight="40"
Width="300"
MaxWidth="450" />