Update issue with dropdownlist and an ObservableCollection datasource with Async

Hi,

If the datasource for a dropdownlist is an Async ObservableCollection then inserts and deletes to the ObservableCollection do not update the dropdown.

Remove the Task from the creation of the ObservableCollection then the dropdownlist correctly updates.

 protected override async Task OnInitializedAsync()
        {
            // Get list of dashboards to bind to the dropdown
            //this.DashBoards = new ObservableCollection<DashBoard>(await this.DashBoardRepositoryObj.GetDashBoardsAsync());

            this.DashBoards = await Task.Run(() => new ObservableCollection<DashBoard>(new List<DashBoard>() {
            new DashBoard { DashBoardId = 0, Name = "Bob" },
            new DashBoard { DashBoardId = 1, Name = "Mike" },
            new DashBoard { DashBoardId = 2, Name = "Glenn" },
            new DashBoard { DashBoardId = 3, Name = "Guy" },
            new DashBoard { DashBoardId = 4, Name = "Johnny" },
            new DashBoard { DashBoardId = 5, Name = "Nick" } }));

        }

16 Replies 1 reply marked as answer

SP Sureshkumar P Syncfusion Team October 30, 2020 02:14 AM UTC

Hi Michael, 
 
Greetings from Syncfusion support. 
 
Based on your shared information with code example. We have created the sample and we cannot able to replicate the reported issue from our end.  
 
Please find the code example here: 
<SfDropDownList @ref="ddl1" TValue="int?" Index="IndexVal" TItem="SpareNameViewModel" @bind-Value="@DDLValue" DataSource="@customData"> 
    <DropDownListFieldSettings Text="Name" Value="Code"></DropDownListFieldSettings> 
</SfDropDownList> 



 
@code { 
    SfDropDownList<int?, SpareNameViewModel> genericCustomerPicker; 
 
    public IEnumerable<SpareNameViewModel> DataSource { get; set; } 
 
    public int? CustomCustDropValue 
    { 
        get; set; 
    } 
    SfDropDownList<int?, SpareNameViewModel> ddl1; 
    public ObservableCollection<SpareNameViewModel> customData { get; set; } 
    public int? DDLValue { get; set; } 
    public int? IndexVal { get; set; } = null; 
    protected override async Task OnInitializedAsync() 
    { 
        customData = await ForecastService.GetSpareNamesAsync(); 
        this.StateHasChanged(); 
        this.DDLValue = await ForecastService.GetSpareNamesValueAsync();   // Change Value 
        // add the datasource dynamically using addItems method  
        this.customData.Insert(0new SpareNameViewModel() { Name = "Bob", Id = 10 }); 
 
    } 
 
} 
 
 
Please find the screen shot here: 
 
 
 
If still you have facing the issue, then please replicate the reported issue from above attached sample and revert us with detailed issue replication steps. That will help us to provide exact solution as earlier as possible. 
 
Regards, 
Sureshkumar P 



MA Michael Aston November 13, 2020 11:26 AM UTC

Hi,

Hopefully the following code will demo the issue.

The Add and Remove will update the dropdown when the ObservableCollection is created in OnInitialized. If you comment out OnInitialized and uncomment OnInitializedAsync so the ObservableCollection is created in the Async,  then the Add and Remove do not update the dropdown.

Regards,
Mike

@page "/"

@using Syncfusion.Blazor.DropDowns;
@using Syncfusion.Blazor.Buttons;
@using System.Collections.Generic;
@using System.Collections.ObjectModel;


<SfDropDownList Width="250px" DataSource=@DashBoards TValue=int? TItem=@DashBoard @bind-Value=@DashBoardId @ref=ddlDashBoards>
    <DropDownListFieldSettings Value=@nameof(DashBoard.DashBoardId) Text=@nameof(DashBoard.Name) />
</SfDropDownList>

<SfButton OnClick=@Add>Add Fred</SfButton>
<SfButton OnClick=@Delete>Delete Mike</SfButton>

@code {
    public class DashBoard
    {
        public DashBoard() { }
        public int DashBoardId { get; set; }
        public string Name { get; set; }
    }

    SfDropDownList<int?, DashBoard> ddlDashBoards;
    protected int? DashBoardId { get; set; } = 1;
    protected ObservableCollection<DashBoard> DashBoards { get; set; }

    //protected override async Task OnInitializedAsync()
    //{

    //    this.DashBoards = await Task.Run(() => new ObservableCollection<DashBoard>(new List<DashBoard>() {
    //    new DashBoard { DashBoardId = 0, Name = "Bob" },
    //    new DashBoard { DashBoardId = 1, Name = "Mike" },
    //    new DashBoard { DashBoardId = 2, Name = "Glenn" },
    //    new DashBoard { DashBoardId = 3, Name = "Guy" },
    //    new DashBoard { DashBoardId = 4, Name = "Johnny" },
    //    new DashBoard { DashBoardId = 5, Name = "Nick" } }));
    //}

    protected override void OnInitialized()
    {

        this.DashBoards = new ObservableCollection<DashBoard>(new List<DashBoard>() {
        new DashBoard { DashBoardId = 0, Name = "Bob" },
        new DashBoard { DashBoardId = 1, Name = "Mike" },
        new DashBoard { DashBoardId = 2, Name = "Glenn" },
        new DashBoard { DashBoardId = 3, Name = "Guy" },
        new DashBoard { DashBoardId = 4, Name = "Johnny" },
        new DashBoard { DashBoardId = 5, Name = "Nick" } });
    }

    protected void Add()
    {
        this.DashBoards.Add(new DashBoard() { DashBoardId = 6, Name = "Fred" });
    }

    protected void Delete()
    {
        DashBoard DashBoardObj = this.DashBoards.Where(x => x.DashBoardId == 1).First<DashBoard>();

        this.DashBoards.Remove(DashBoardObj);
    }
}


BC Berly Christopher Syncfusion Team November 18, 2020 11:31 AM UTC

Hi Michael, 
  
Thanks for providing information. 
  
We can add and remove the item to the DropDownList component while assigning the data source asynchronously  by implement INotifyPropertyChanged to the model class of DropDownList. In the below example, DashBoard class implements the INotifyPropertyChanged and it raises the event when the value gets changed. 
  
<SfDropDownList Width="250px" DataSource=@DashBoards TValue=int? TItem=@DashBoard @bind-Value=@DashBoardId @ref=ddlDashBoards> 
    <DropDownListFieldSettings Value=@nameof(DashBoard.DashBoardId) Text=@nameof(DashBoard.Name) /> 
</SfDropDownList> 
 
<SfButton OnClick=@Add>Add Fred</SfButton> 
<SfButton OnClick=@Delete>Delete Mike</SfButton> 
 
@code { 
    public class DashBoard : INotifyPropertyChanged 
    { 
        public DashBoard() { }       
        public string Name { get; set; } 
        public int DashBoardId 
        { 
            get { return _DashBoardId; } 
            set 
            { 
                _DashBoardId = value; 
                NotifyPropertyChanged("DashBoardId"); 
            } 
        } 
        public int _DashBoardId { get; set; } 
        public event PropertyChangedEventHandler PropertyChanged; 
        private void NotifyPropertyChanged(String propertyName) 
        { 
            if (PropertyChanged != null) 
            { 
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
            } 
        } 
    } 
 
    SfDropDownList<int?, DashBoard> ddlDashBoards; 
    protected int? DashBoardId { get; set; } = 1; 
    protected ObservableCollection<DashBoard> DashBoards { get; set; } 
 
    protected override async Task OnInitializedAsync() 
    { 
        this.DashBoards = new ObservableCollection<DashBoard>(new List<DashBoard>() { 
        new DashBoard { DashBoardId = 0, Name = "Bob" }, 
        new DashBoard { DashBoardId = 1, Name = "Mike" }, 
        new DashBoard { DashBoardId = 2, Name = "Glenn" }, 
        new DashBoard { DashBoardId = 3, Name = "Guy" }, 
        new DashBoard { DashBoardId = 4, Name = "Johnny" }, 
        new DashBoard { DashBoardId = 5, Name = "Nick" } }); 
    } 
 
    protected async Task Add() 
    {         
        this.DashBoards.Add(new DashBoard() { DashBoardId = 6, Name = "Fred" }); 
    } 
    protected async Task Delete() 
    { 
        DashBoard DashBoardObj = this.DashBoards.Where(x => x.DashBoardId == 1).First<DashBoard>(); 
        this.DashBoards.Remove(DashBoardObj); 
    } 
    public async Task<DashBoard> updateDate() 
    { 
        var data = new DashBoard() { DashBoardId = 6, Name = "Fred" }; 
        return await Task.FromResult(data); 
    } 
 
} 
 
  
Please find the modified sample from the below link. 
  
Regards, 
Berly B.C 



MA Michael Aston November 18, 2020 03:02 PM UTC

Hi,

Your sample has missed the await on the creation of the collection. If you add this back in then it fails again.

Wouldn't a better approach be to drop the use of the ObservableCollection due its issues with async/threading and use a List and expose a StateHasChanged/CollectionHasChanged method on the dropdown that can be called to notify of an update to the collection.

Regards,
Mike


BC Berly Christopher Syncfusion Team November 19, 2020 02:23 PM UTC

Hi Michael, 
  
We will check the reported issue and provide the further details in two business days (23rd November 2020). We appreciate your patience until then. 
  
Regards, 
Berly B.C 



BC Berly Christopher Syncfusion Team November 20, 2020 02:17 PM UTC

Hi Michael, 
  
Thanks for the patience.  
  
We would like to inform you that, when you are assigning the observable collection in the async method with await function, we suggest you to assign the values in the separate async method as mentioned below code snippet to get rid of the reported issue. 
  
   protected override async Task OnInitializedAsync() 
    { 
 
        this.DashBoards = await GetItemsAsync(); 
    } 
    public async Task<ObservableCollection<DashBoard>> GetItemsAsync() 
    { 
        return new ObservableCollection<DashBoard>() { 
        new DashBoard { DashBoardId = 0, Name = "Bob" }, 
        new DashBoard { DashBoardId = 1, Name = "Mike" }, 
        new DashBoard { DashBoardId = 2, Name = "Glenn" }, 
        new DashBoard { DashBoardId = 3, Name = "Guy" }, 
        new DashBoard { DashBoardId = 4, Name = "Johnny" }, 
        new DashBoard { DashBoardId = 5, Name = "Nick" } }; 
    } 

  
  
Regards, 
Berly B.C 



MA Michael Aston November 21, 2020 01:08 PM UTC

Hi,

As you've not awaited the creation of the observable collection in GetItemAsync() the call will be synchronous rather than asynchronous, so its like it's called from OnInitialized rather than OnInitializedAsync again.

The core problem here is that the creation of the observable collection and the add/removes to it must be on the same thread. I can't see how an observable collection will work with the threading model of Blazor server, which I'm using.

You either need another method to notify the dropdown of a change to the collection or you need to use an implementation of an observable collection that forces access to the collection to be on the same thread as the creation of the collection.

Regards,
Mike


MA Michael Aston November 26, 2020 10:52 AM UTC

Hi,

Anything happening on this?

Regards,
Mike


SN Sevvandhi Nagulan Syncfusion Team November 29, 2020 12:53 PM UTC

Hi Michael, 


Sorry for the inconvenience caused. 

We are validating the reported requirement. We will update further details on 1st December,2020. We appreciate your patience until then. 


Regards, 
Sevvandhi N 



BC Berly Christopher Syncfusion Team December 7, 2020 07:53 AM UTC

Hi Michael, 
  
Thanks for the patience. 
  
We have confirmed the reported issue as a bug at our end and this fix will be included in our Volume 4 Main release which is expected to be rolled out on end of December 2020. We appreciate your patience until then. 
  
Please track the status of the issue from the below feedback link. 
  
Regards, 
Berly B.C 



MA Michael Aston January 4, 2021 10:46 AM UTC

Can you tell me if a fix for this was implemented in Vol4 as scheduled?





BC Berly Christopher Syncfusion Team January 5, 2021 10:43 AM UTC

Hi Michael, 
  
Thanks for the patience. 
  
We are glad to announce that our release in the version 18.4.30 has been rolled out successfully and in that release, we have included the “Add and remove is not working while creating the data source as observable collection in async await function”.  So, we suggest you upgrade our Syncfusion packages to our latest version to resolve this issue in your end.  
  
  
Regards, 
Berly B.C 



CG Coder Gal August 4, 2021 11:21 PM UTC

This is still an issue in Syncfusion.Blazor 19.1.0.63




BC Berly Christopher Syncfusion Team August 5, 2021 10:20 AM UTC

Hi Coder Gal, 
  
Greetings from Syncfusion support. 
  
We have checked the sample in the 19.1.0.63 version and the reported issue is does not occurred at our end. We have taken video demonstration and attached it below. 
  
  
  
Still issue persists, please share the issue reproducing sample or modify the attached sample with reported issue that will help us to check and proceed further from our end. 
  
Regards, 
Berly B.C 


Marked as answer

CG Coder Gal August 5, 2021 05:35 PM UTC

Thank you for reply. You are correct: it works in your solution. 

One difference between your solution and what I have is that my solution targets net5.0 standard. 

The solution you've provided targets netstandard2.1

When I create a blank Blazor WASM solution targeting .net5.0 (not netstandard2.1), and try to implement the code, the control does not load Dashboards list.  It returns "no records found" 

Also, dropdown part of the control is not positioned correctly (its position is distorted) 




BC Berly Christopher Syncfusion Team August 6, 2021 06:20 AM UTC

Hi Coder Gal, 
  
We were able to reproduce the reported issue at our end and this issue has been resolved in our 19.2.0.44 version. So, we suggest you to upgrade the Syncfusion NuGet to the 19.2.0.44 or latest version 19.2.0.51 version to get rid of the reported issue. 
  
For your convenience, we have prepared the sample and attached it below. 
  
Regards, 
Berly B.C 


Loader.
Up arrow icon