IndexOutOfRangeException in FlexGridExplorer Sample OnDemand

Posted by: rand.random on 21 January 2021, 6:19 pm EST

    • Post Options:
    • Link

    Posted 21 January 2021, 6:19 pm EST

    In the OnDemand Sample found at this path:

    ComponentOne Samples\WPF.Net 5\CS\Grid\FlexGridExplorer\View\OnDemand.xaml

    I am getting the following exception

    Index was out of range. Must be non-negative and less than the size of the collection. (Parameter ‘index’)

    
       at System.ThrowHelper.ThrowArgumentOutOfRange_IndexException() in /_/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs:line 94
       at System.Collections.Generic.List`1.get_Item(Int32 index) in /_/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/List.cs:line 150
       at C1.DataCollection.C1CacheDataCollection`1.get_Item(Int32 index)
       at C1.WPF.Grid.GridRowColCollection`1.get_Item(Int32 index)
       at C1.WPF.Grid.FlexGrid.GetRow(GridCellType cellType, Int32 row)
       at C1.WPF.Grid.GridCellFactory.UnbindCellContent(GridCellType cellType, GridCellRange range, FrameworkElement cellContent)
       at C1.WPF.Grid.GridCellFactoryBase.UnbindCellContent(GridCellsPanelRange range, FrameworkElement cellContent)
       at C1.WPF.Grid.GridCellsPanel.RecycleCell(CellHolder cellHolder)
       at C1.WPF.Grid.GridCellsPanel.RecycleUnusedCells()
       at C1.WPF.Grid.GridCellsPanel.GetIntrinsicContentSize()
       at C1.WPF.Grid.GridCellsPanel.MeasureOverride(Size availableSize)
       at System.Windows.FrameworkElement.MeasureCore(Size availableSize) in /_/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/FrameworkElement.cs:line 4406
       at System.Windows.UIElement.Measure(Size availableSize) in /_/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/UIElement.cs:line 656
       at System.Windows.ContextLayoutManager.UpdateLayout() in /_/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/LayoutManager.cs:line 315
       at System.Windows.ContextLayoutManager.UpdateLayoutCallback(Object arg) in /_/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/LayoutManager.cs:line 582
       at System.Windows.Media.MediaContext.FireInvokeOnRenderCallbacks() in /_/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/MediaContext.cs:line 1968
       at System.Windows.Media.MediaContext.RenderMessageHandlerCore(Object resizedCompositionTarget) in /_/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/MediaContext.cs:line 1841
       at System.Windows.Media.MediaContext.RenderMessageHandler(Object resizedCompositionTarget) in /_/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/MediaContext.cs:line 1744
       at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs) in /_/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/Threading/ExceptionWrapper.cs:line 103
       at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler) in /_/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/Threading/ExceptionWrapper.cs:line 36
       at System.Windows.Threading.DispatcherOperation.InvokeImpl() in /_/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Threading/DispatcherOperation.cs:line 540
       at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state) in /_/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Threading/DispatcherOperation.cs:line 487
       at MS.Internal.CulturePreservingExecutionContext.CallbackWrapper(Object obj) in /_/src/Microsoft.DotNet.Wpf/src/shared/MS/Internal/CulturePreservingExecutionContext.cs:line 214
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) in /_/src/libraries/System.Private.CoreLib/src/System/Threading/ExecutionContext.cs:line 186
       at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() in /_/src/libraries/System.Private.CoreLib/src/System/Runtime/ExceptionServices/ExceptionDispatchInfo.cs:line 56
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) in /_/src/libraries/System.Private.CoreLib/src/System/Threading/ExecutionContext.cs:line 214
       at MS.Internal.CulturePreservingExecutionContext.Run(CulturePreservingExecutionContext executionContext, ContextCallback callback, Object state) in /_/src/Microsoft.DotNet.Wpf/src/shared/MS/Internal/CulturePreservingExecutionContext.cs:line 172
       at System.Windows.Threading.DispatcherOperation.Invoke() in /_/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Threading/DispatcherOperation.cs:line 409
       at System.Windows.Threading.Dispatcher.ProcessQueue() in /_/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Threading/Dispatcher.cs:line 2085
       at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled) in /_/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Threading/Dispatcher.cs:line 2296
       at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled) in /_/src/Microsoft.DotNet.Wpf/src/shared/MS/Win32/HwndWrapper.cs:line 295
       at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o) in /_/src/Microsoft.DotNet.Wpf/src/shared/MS/Win32/HwndSubclass.cs:line 429
       at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs) in /_/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/Threading/ExceptionWrapper.cs:line 103
       at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler) in /_/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/Threading/ExceptionWrapper.cs:line 36
       at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs) in /_/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Threading/Dispatcher.cs:line 1342
       at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam) in /_/src/Microsoft.DotNet.Wpf/src/shared/MS/Win32/HwndSubclass.cs:line 378
       at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
       at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame) in /_/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Threading/Dispatcher.cs:line 2135
       at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame) in /_/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Threading/Dispatcher.cs:line 328
       at System.Windows.Threading.Dispatcher.Run() in /_/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Threading/Dispatcher.cs:line 296
       at System.Windows.Application.RunDispatcher(Object ignore) in /_/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Application.cs:line 2404
       at System.Windows.Application.RunInternal(Window window) in /_/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Application.cs:line 1686
       at System.Windows.Application.Run() in /_/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Application.cs:line 198
       at FlexGridExplorer.App.Main()
    
    

    I have made the following changes to get this exception

    In the constructur of YouTubeCollectionView I added this line

    
    _q = ".Net5";
    
    

    In LoadVideosAsync I have replaced the existing code with this:

    
            public static async Task<Tuple<string, IReadOnlyList<YouTubeVideo>>> LoadVideosAsync(string q, string orderBy, string pageToken, int maxResults, CancellationToken cancellationToken = default(CancellationToken))
            {
                if (q == null) q = "";
    
                return new Tuple<string, IReadOnlyList<YouTubeVideo>>(pageToken, Enumerable.Range(0, maxResults).Select(x => new YouTubeVideo()
                {
                    ChannelTitle = "Foo",
                    Description = "Foo",
                    Link = "Foo",
                    Thumbnail = "Foo",
                    Title = "Foo,"
                }).ToList());
        }
    
    

    In OnDemand.xaml.cs I have increased the PageSize to 1000

    
    _dataCollection = new YouTubeCollectionView() { PageSize = 1000 };
    
    

    In OnDemand.xaml.cs I have commented out the search in constructor

    
    //search.Text = ".Net5";
    //var task = PerformSearch();
    
    

    In OnDemand.xaml I have changed the flexGrid to AutoGenerateColumns

    
            <c1:FlexGrid x:Name="grid" AutoGenerateColumns="True" HeadersVisibility="Column" IsReadOnly="True" Grid.Row="1">
                <!--<c1:FlexGrid.Columns>
                    <c1:GridImageColumn Binding="Thumbnail" Header=" " Width="62" PlaceHolder="/FlexGridExplorer;component/Images/default.png"/>
                    <c1:GridHyperlinkColumn Binding="Link" ContentBinding="Title" Header="Title" TargetName="_blank" MinWidth="300" Width="*"/>
                    <c1:GridColumn Binding="ChannelTitle" Header="Channel"/>
                </c1:FlexGrid.Columns>-->
                <e:Interaction.Behaviors>
                    <c1:EmptyGridBehavior EmptyView="{Binding ElementName=emptyListLabel}" />
                </e:Interaction.Behaviors>
            </c1:FlexGrid>
    
    

    To get the error all I have to do is open the OnDemand demo and try to scroll.

    You may also get the exception without scrolling right after opening the demo.

    Notice, that the following changes introduces a couple of glitches.

    1. The UI won’t have all the rows loaded on start and the may only appear after scrolling a bit
    2. The first cell [0,0] wont be displayed at all, sometimes instead of the blank there will be a loading circle visible
    3. The above exception, may come after some pages have already been loaded when the GetPageAsync method finishes to fast, adding this code seems to help
    
    await Task.Delay(100);
    
    
    1. If you manage to scroll without the crash, loading a second page seems to fail when you work with a pageToken of null, I could fix this by adding a Guid.NewGuid as a pageToken, like this
    
            public static async Task<Tuple<string, IReadOnlyList<YouTubeVideo>>> LoadVideosAsync(string q, string orderBy, string pageToken, int maxResults, CancellationToken cancellationToken = default(CancellationToken))
            {
                if (q == null) q = "";
    
                return new Tuple<string, IReadOnlyList<YouTubeVideo>>(Guid.NewGuid().ToString("D"), Enumerable.Range(0, maxResults).Select(x => new YouTubeVideo()
                {
                    ChannelTitle = "Foo",
                    Description = "Foo",
                    Link = "Foo",
                    Thumbnail = "Foo",
                    Title = "Foo,"
                }).ToList());
        }
    
    

    I have attached the changed files.

    OnDemand.zip

  • Posted 24 January 2021, 11:25 pm EST

    Hi,

    Thank you for sharing the information.

    I have used the same code provided by you but I didn’t got any exception. However, I noticed the inconsistent UI behavior and it seems like this was because of synchronously returning the result from the LoadVideosAsync method.

    Therefore, returning the results asynchronously resolved the inconsistent UI behavior as follows:

    
    public static async Task<Tuple<string, IReadOnlyList<YouTubeVideo>>> LoadVideosAsync(string q, string orderBy, string pageToken, int maxResults, CancellationToken cancellationToken = default(CancellationToken))
    {
          if (q == null) q = "";
    
          [b]var result = await[/b] Task.Run(() =>
          {
                 return new Tuple<string, IReadOnlyList<YouTubeVideo>>(pageToken, Enumerable.Range(0, maxResults).Select(x => new YouTubeVideo()
                {
                        ChannelTitle = "Foo",
                        Description = "Foo",
                        Link = "Foo",
                        Thumbnail = "Foo",
                        Title = "Foo"
                    }).ToList());
                });
    
          [b]return result;[/b]
    }
    

    And regarding the exception message, I would request you to share the modified product sample replicating the behavior so that I can investigate it further and assist you accordingly.

    Regards,

    Kartik

  • Posted 25 January 2021, 11:38 pm EST

    Here is the complete FlexGridExplorer project:

    FlexGridExplorer.zip

    Notice that you may have to disable “Enable Just My Code” in

    Tools → Options → Debugging → General

    to get the exception, since the exception doesn’t occure in “my code” but in the C1.

  • Posted 26 January 2021, 10:15 am EST

    rand.random,

    Are you looking into migrating C1DataGrid to C1FlexGrid?

    If so, I am interested to know any pain points you hit, so please feel free to post them here in the forums or you can email me at greg.lutz@grapecity.com. We are interested in helping you (or anyone reading this) with this task.

    Thanks

    Greg

  • Posted 26 January 2021, 5:16 pm EST

    Hi,

    Thank you for sharing the sample.

    I am able to reproduce this behavior by clicking on the half loaded row. However, this behavior is also because of returning data synchronously from an asynchronous method which is disturbing the FlexGrid’s rendering and causing it to load before the data is fetched/created and hence the behavior.

    So, I would recommend you to return data asynchronously from the LoadVideosAsync method.

    Regards,

    Kartik

  • Posted 26 January 2021, 6:01 pm EST - Updated 3 October 2022, 11:43 pm EST

    @greg.lutz

    For our “old” project we have decided to stick with C1DataGrid and .NET 47, for the new project we are currently evaluating C1FlexGrid in .NET 5.

    Though there are a couple of things we still need to figure out.

    What we are currently missing is those two features from the demo application.

    There seems to be only “Text Filter” in C1FlexGrid and no way to use all those filters, so basically everything the NuGet package “C1.Xaml.WPF.DataGrid.Filters” has to offer.

    But we are in a very early stage and just doing a proof of concept project.

    @kartik.sagar

    So, in my real application even if I don’t fetch the data async from the server eg. calling ReadAsync https://docs.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqldatareader.readasync

    and instead use the data from an in-memory cache eg. a simple List which doesn’t provide Async methods, since there isn’t a thing that actually does async operation eg. I/O bound stuff, I am supposed to wrap the List into a Task.Run to “off-load” the execution?

    I like to remind you that you haven’t replied to my concern about the pagetoken.

    Quote from my original post:

    To rephrase this:

    Is it necessary to use the pageToken, why doesn’t a second page load when the pageToken is null?

    In my scenario I don’t rely on pageTokens is my idea of Guid.NewGuid any good or would you recommend something else?

    The basic idea I have is that GetPageAsync should be triggered as long as HasMoreItems is true, regardless of what the pageToken might be.

  • Posted 27 January 2021, 7:05 pm EST

    Hi,

    It seems like you have interpreted me incorrectly. The response was specific to C1CursorDataCollection. Basically, C1CursorDataCollection is used for wrapping data services that return the data in pages and give a token to get the next page, like Facebook, Twitter, YouTube, etc.

    And also it is expected to return data asynchronously from an async method otherwise it might cause issues with the tasks execution.

    Is it necessary to use the pageToken, why doesn’t a second page load when the pageToken is null?

    Sorry it was skipped by mistake. As we know GetPageAsync is an abstract method, therefore it needs to be implemented with respect to the data service. Since the product sample uses Youtube service which doesn’t return any data when page token is null and hence the behavior.

    JFYI, It totally depends on your data service how it uses the page token.

    Regards,

    Kartik

  • Posted 8 February 2021, 2:16 am EST

    Sorry for my late response was busy with something else.

    Thanks for the clarification.

    I was actually talking about my dummy code that doesn’t use the Youtube Service, and provides data no matter what the value the pageToken is.

    In the attached file see the recommended changes about wrapping the code into Task.Run, and still using a null pageToken.

    With this you should see that the C1CursorDataCollection won’t fire a second GetPageAsync and my code doesn’t handle the pageToken at all, so I don’t see how my code prevents a second call to GetPageAsync.

    I can only make it work with specifing a pageToken, since my code doesn’t need it I am passing Guid.NewGuid().

    I have changed it to this, also left a comment to make the necessary changes with the Guid.NewGuid()

    
            public static async Task<Tuple<string, IReadOnlyList<YouTubeVideo>>> LoadVideosAsync(string q, string orderBy, string pageToken, int maxResults, CancellationToken cancellationToken = default(CancellationToken))
            {
                if (q == null) q = "";
    
                //returning a Tuple with pageToken null, will prevent C1.FlexGrid from calling GetPageAsync more than once
                //un-comment this line to make C1.FlexGrid fire GetPageAsync endlessly
                //pageToken = Guid.NewGuid().ToString("D");
                
                var result = await Task.Run(() =>
                {
                    return new Tuple<string, IReadOnlyList<YouTubeVideo>>(pageToken, Enumerable.Range(0, maxResults).Select(x => new YouTubeVideo()
                    {
                        ChannelTitle = "Foo",
                        Description = "Foo",
                        Link = "Foo",
                        Thumbnail = "Foo",
                        Title = "Foo,"
                    }).ToList());
                });
    
                return result;
            }
    
    

    Notice I have also decreased the pageSize from 1000 to 100 to more easily see the scroll behaviour.FlexGridExplorer.zip

  • Posted 8 February 2021, 6:31 pm EST

    Hi,

    Thank you for sharing the sample.

    C1FlexGrid internally uses the C1CursorDataCollection’s HasMoreItems property to ensure whether the GetPageAsync method needs to be called or not i.e when the ‘pageToken’ is null, HasMoreItems returns false and hence the behavior.

    However, you can make GetPageAsync method to be called always by overriding the C1CursorDataCollection’s HasMoretems property to return true as follows:

    
    public class YouTubeCollectionView : C1CursorDataCollection<YouTubeVideo>
    {
            ...
            public override bool HasMoreItems => true;
           ...
    }
    
    

    I hope it helped.

    Best Regards,

    Kartik

  • Posted 8 February 2021, 6:39 pm EST

    Thanks, didn’t notice that base.HasMoreItems says false if GetPageAsync used a null pageToken.

    Kinda thought that it will always say True and the user has to override it to make it stop.

Need extra support?

Upgrade your support plan and get personal unlimited phone support with our customer engagement team

Learn More

Forum Channels