.NET Core 3.0 is the latest version of .NET Core and now supports WinForms and WPF. This sample shows how you can perform fill data to Autocomplete TextBox in another thread without slowing down the main UI (User Interface). With this sample, you can create a better user experience for the end-user.

TextBox Autocomplete

Autocomplete helps the user to search/type from a known list. In my application, I built a list to Autocomplete with > 10.000 items and is very fast even on slow computers.
Autocomplete is an old feature, but this post will demonstrate how to perform this to load data quickly in NET Core 3.0.
When you fill a Collection, if you have a huge suggestion list, this will make the UI (User Interface) freeze. But if you process it in another thread the UI will not have any issues.
More technical information is here.

How it works

Like the other POST that uses a delegate, here, we use another thread to load data and delegate to bind the Autocomplete Collection in the current UI thread.
  1. using System;
  2. using System.Data.SqlClient;
  3. using System.Drawing;
  4. using System.Windows.Forms;
  5. namespace TextBoxWithAutoComplete
  6. {
  7. /// <summary>
  8. /// 10-10-2019
  9. /// </summary>
  10. public partial class Form1 : Form
  11. {
  12. private TextBox textBox1;
  13. public Form1()
  14. {
  15. InitializeComponent();
  16. textBox1 = new TextBox
  17. {
  18. Location = new Point(0, 0),
  19. Size = new Size(100, 32),
  20. Visible = true,
  21. TabIndex = 0
  22. };
  23. Controls.Add(textBox1);
  24. Load += Form1_Load;
  25. }
  26. public void Form1_Load(object sender, EventArgs e)
  27. {
  28. Show(); // You need to show the form to avoid a thread error
  29. LoadData(); // Start to load Data
  30. }
  31. private SqlConnection GetConnection()
  32. {
  33. // Init your connection
  34. var oCnn = new SqlConnection
  35. {
  36. ConnectionString = "YOUR_CONNECTION_STRING"
  37. };
  38. oCnn.Open();
  39. return oCnn;
  40. }
  41. #region TreadSafeLoading
  42. private delegate void UpdateUIDelegate(AutoCompleteStringCollection myCollection);
  43. /// <summary>
  44. /// Load Data - You can make public to load as you need
  45. /// </summary>
  46. private void LoadData()
  47. => // Start this process in a new thread
  48. new System.Threading.Thread(() => OutOfThreadProcess()).Start();
  49. // You can start others, every one in a new thread!
  50. /// <summary>
  51. /// Start fill in another Thread
  52. /// </summary>
  53. private void OutOfThreadProcess()
  54. {
  55. // inialize the collection
  56. var myCollection = new AutoCompleteStringCollection();
  57. using var oCnn = GetConnection();
  58. // Start your SQL Query
  59. var cmd = new SqlCommand($"Select [FirstName] + ' ' + [LastName] as [contactName] From [AdventureWorks].[Person].[Contact] Order By [FirstName], [LastName]", oCnn);
  60. // Read and fill the collection
  61. using var reader = cmd.ExecuteReader();
  62. while (reader.Read())
  63. myCollection.Add(reader.GetString(0));
  64. // Invoke in a UI thread
  65. _ = Invoke(new UpdateUIDelegate(UpdateUIInvoke), myCollection);
  66. }
  67. /// <summary>
  68. /// Current UI Thread threatment
  69. /// </summary>
  70. /// <param name="myCollection"></param>
  71. private void UpdateUIInvoke(AutoCompleteStringCollection myCollection)
  72. {
  73. // Setup up in corrent UI Thread
  74. textBox1.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
  75. textBox1.AutoCompleteSource = AutoCompleteSource.CustomSource;
  76. textBox1.AutoCompleteCustomSource = myCollection;
  77. #if (IS_TELERIK_RadTextBoxControl)
  78. // If you use Telerik
  79. // I found an issue in Telerik by Progress, without fix.
  80. if (ParentForm != null)
  81. ParentForm.FormClosing += new FormClosingEventHandler(UIFormClosing);
  82. #endif
  83. }
  84. #if (IS_TELERIK_RadTextBoxControl)
  85. private void UIFormClosing(object sender, FormClosingEventArgs e) => textBox1.AutoCompleteCustomSource = null;
  86. #endif
  87. #endregion
  88. }
  89. }

Observation

When you use this technique you may receive errors if you run the new thread without firing the Show() method from the form, this occurs because the current window(form) hasn't initialized.

Conclusion

I designed this technique when I upgraded to .NET Core 3 and developed a fix for the FileSystemWatcher event that fires in a new thread, so I took the same idea to make Autocomplete load collection work in a new thread.
I hope you can bring a better experience to your end-users.
Happy coding.