Async ComboBox Filtration

Viewed 30

I am new to asynchronous methods and struggling with such a case (I made a simple example of my problem):

Let's say I've got a ComboBox, which Items are binded with a ***BindableCollection NameList *** which items are some names.

            <ComboBox
                x:Name="SubbranchComboBox"
                Margin="20 0 0 0"
                Width="100"
                Height="20"
                IsEnabled="True"
                IsEditable="True"
                IsTextSearchEnabled="False"
                InputScope="Xml"
                ItemsSource="{Binding NameList}" KeyUp="ComboBox_KeyUp">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding}" />
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>

The ComboBox_KeyUp looks like this:

        private void ComboBox_KeyUp(object sender, KeyEventArgs e)
    {
        var combobox = (ComboBox)sender;
        var ctb = combobox.Template.FindName("PART_EditableTextBox", combobox) as TextBox;
        if (ctb == null) return;
        if (Keyboard.Modifiers.HasFlag(ModifierKeys.Shift) || Keyboard.Modifiers.HasFlag(ModifierKeys.Control) || Keyboard.Modifiers.HasFlag(ModifierKeys.Alt))
            return;
        var caretPos = ctb.CaretIndex;
        var searchedText = combobox.Text.ToLower();
        combobox.SelectedIndex = -1;
        combobox.IsDropDownOpen = true;

        CollectionView itemsViewOriginal = (CollectionView)CollectionViewSource.GetDefaultView(combobox.Items);
        itemsViewOriginal.Filter = ((o) =>
        {
            if (String.IsNullOrEmpty(searchedText))
            {
                return true;
            }
            else
            {
                if (((string)o).ToLower().Contains(searchedText.ToLower()))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        });
        itemsViewOriginal.Refresh();
        ctb.CaretIndex = caretPos;
    }

and serves as search function for a typed phrase in the combobox. The Problem is, I'd like the filtration to be done asynchronously, but whenever I try to do it I get an error: The calling thread cannot access this object because a different thread owns it

Please give me some advice, how it should be done. All the example code:

    public partial class MainWindow : Window
{
    public BindableCollection<String> NameList { get; set; }
    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;
        NameList = new BindableCollection<String>
            {
                "Tony",
                "Jerry",
                "George",
                "Harry",
                "Snape",
                "Sirius",
                "Dan",
                "Michael",
                "Mike",
                "Sebastian",
                "Simon",
                "Johny"
            };
    }

    private void ComboBox_KeyUp(object sender, KeyEventArgs e)
    {
        var combobox = (ComboBox)sender;
        var ctb = combobox.Template.FindName("PART_EditableTextBox", combobox) as TextBox;
        if (ctb == null) return;
        if (Keyboard.Modifiers.HasFlag(ModifierKeys.Shift) || Keyboard.Modifiers.HasFlag(ModifierKeys.Control) || Keyboard.Modifiers.HasFlag(ModifierKeys.Alt))
            return;
        var caretPos = ctb.CaretIndex;
        var searchedText = combobox.Text.ToLower();
        combobox.SelectedIndex = -1;
        combobox.IsDropDownOpen = true;

        CollectionView itemsViewOriginal = (CollectionView)CollectionViewSource.GetDefaultView(combobox.Items);
        itemsViewOriginal.Filter = ((o) =>
        {
            if (String.IsNullOrEmpty(searchedText))
            {
                return true;
            }
            else
            {
                if (((string)o).ToLower().Contains(searchedText.ToLower()))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        });
        itemsViewOriginal.Refresh();
        ctb.CaretIndex = caretPos;
    }
}
1 Answers

The Problem is, I'd like the filtration to be done asynchronously, but whenever I try to do it I get an error: The calling thread cannot access this object because a different thread owns it

If you want to update the UI from a background thread, you should run the code in Application's dispatcher

Application.Current.Dispatcher.Invoke(() => /* modify combobox here */);
Related