0

I have a winform with a SfComboBox. When a selection is made a list of dates is retrieved from a cloud data base, and those dates are used to populated another combobox.

The combobox has .DropDownStyle set to DropDownList and SelectedIndexChanged handled by

    private async void Sf_collectionDDL_SelectedIndexChanged(object sender, EventArgs e)
    {
        var cmb = sender as SfComboBox;

        if (cmb.SelectedIndex < 0)
        {
            sf_datesDDL.SelectedItems.Clear();
            return;
        }

        string collectionName = cmb.SelectedItem.ToString();

        await GetCollectionDates(collectionName);

        sf_datesDDL.DataSource = CollectionDates;
        sf_datesDDL.ValueMember = "Value";
        sf_datesDDL.DisplayMember = "Formatted";
        sf_datesDDL.MaxDropDownItems = 12;
    }

    private Task GetCollectionDates(string collectionName)
    {
        return Task.Run(() =>
        {
            var builder = Builders<BsonDocument>.Filter;
            var filter = builder.Eq("Type", "Header");
            var headerDocuments =
                Database
                .GetCollection<BsonDocument>(collectionName)
                .Find(filter)
                .ToList()
            ;

            CollectionDates = new SortedSet<ListItem_Date>();

            foreach (BsonDocument doc in headerDocuments)
            {
                DateTime rangeStart = doc["DateStart"].ToUniversalTime().Date;
                DateTime rangeEnd = doc["DateEnd"].ToUniversalTime().Date;

                for (DateTime dt = rangeStart; dt < rangeEnd; dt = dt.AddDays(1))
                {
                    CollectionDates.Add(new ListItem_Date(dt));
                }
            }
        });
    }

Everything works fine when events triggered by person driven UI operations, mouse clicks, etc.

To speed up some debugging (by reaching a specific state of selections and data retrievals) I am trying to make the selections programmatically from inside the form constructor.

    private SortedSet<ListItem_Date> CollectionDates { get; set; }
    public Form1()
    {
        InitializeComponent();
        WindowState = FormWindowState.Maximized;

        sfDataGrid1.EnableDataVirtualization = true;

        // host during debugging
        sf_hostDDL.DataSource = new List<string>() { "###hidden###" };
        sf_hostDDL.SelectedIndex = 0; // loads database names into DDL

        sf_databaseDDL.SelectedIndex = 0;  // automatically select first database
        radioXYZ.Checked = true;
        CollectionsDDL_Update();  // do same "DDL_update" UI click on radioXYZ would have done



        // Changing the selected index triggers the async/await method
        sf_collectionDDL.SelectedIndex = 0;  // automatically select first collection

        // At this point the CollectionDates property is still null and exception ensues
        // The selectedIndex assignment did not 'await' the innards of
        // Sf_collectionDDL_SelectedIndexChanged() as I expected.

        // Check first three dates 
        sf_datesDDL.SelectedItems.Add(CollectionDates.Take(3));
    }

What is a good strategy to avoid the exception and programmatically achieve the selections I want in order to reach the 'state' I need to be at.

Richard
  • 25,390
  • 3
  • 25
  • 38
  • We try to replicate the scenario you have mentioned with SfComboBox, but we could not actually understand what you need to do in the constructor. We have tried the same in our simple sample, but we could not face any exception. Also we have observed that in your constructor, you have not set the DataSource,DisplayMember property for ComboBox, since this will be used to display the member. So please briefly explain about your requirement in details with screenshot if possible. https://www.syncfusion.com/downloads/support/directtrac/249999/ze/SfComboBox1795502243 – Jagadeesan Oct 08 '19 at 06:58

2 Answers2

0

You shouldn't do that on the constructor because events aren't being fired yet.

Try the OnLoad override or the Load event.

Paulo Morgado
  • 14,111
  • 3
  • 31
  • 59
0

The problem is that the event handler is async void.

private async void Sf_collectionDDL_SelectedIndexChanged(object sender, EventArgs e)

An async void method can't be awaited, so you must find some indirect way to await the handler to complete. There must surely exist better ways to do it, but here is a not particularly pretty one. You can declare a TaskCompletionSource member inside the Form, that will represent the asynchronous completion of the event handler:

private TaskCompletionSource<bool> Sf_collectionDDL_SelectedIndexChangedAsync;

private async void Sf_collectionDDL_SelectedIndexChanged(object sender, EventArgs e)
{
    Sf_collectionDDL_SelectedIndexChangedAsync = new TaskCompletionSource<bool>();
    try
    {
        var cmb = sender as SfComboBox;
        //...
        await GetCollectionDates(collectionName);
        //...
        sf_datesDDL.MaxDropDownItems = 12;
        Sf_collectionDDL_SelectedIndexChangedAsync.SetResult(true);
    }
    catch (Exception ex)
    {
        Sf_collectionDDL_SelectedIndexChangedAsync.SetException(ex);
    }
}

Then in the constructor after changing the SelectedIndex, wait for the completion of the asynchronous operation:

sf_collectionDDL.SelectedIndex = 0;
Sf_collectionDDL_SelectedIndexChangedAsync.Wait();
Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104