神秘的“没有足够的配额来处理这个命令”在DataGrid的WinRT端口 [英] Mysterious "Not enough quota is available to process this command" in WinRT port of DataGrid

查看:1706
本文介绍了神秘的“没有足够的配额来处理这个命令”在DataGrid的WinRT端口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编辑9月26日



请参阅下面的完整背景。 tl; dr:数据网格控件引起奇怪的异常,我正在寻找帮助隔离原因并找到解决方案。



我缩小了这进一步下降了。我已经能够在更小的测试应用程序中重现这种行为,更可靠地触发不稳定的行为。



我绝对可以排除线程和(我认为)内存问题新的应用程序不使用任务或其他线程/异步功能,我可以通过添加将常量返回到DataGrid中显示的对象类的属性来触发未处理的异常。这表明我的问题是在无人管理的资源枯竭或我还没有想到的东西。



修改后的程序是这样构造的。我创建了一个名为 EntityCollectionGridView 的用户控件,它具有标签和数据网格。在控件的Loaded事件处理程序中,我为数据网格分配一个1000或10000行的 List< TestClass> ,让网格生成列。该用户控件在MainPage.xaml中的页面 OnNavigatedTo 事件(或加载)中实例化了2-4次,它没有似乎很重要)。如果发生异常,则会在显示MainPage之后立即发生。



有趣的是,行为似乎不同于显示的行数(将会以10000行可靠地工作或可靠地失败,每个网格中只有1000行),而是在给定时间加载的所有网格中的列数总数。有20个属性显示,4个网格工作正常。有35个属性和4个网格,抛出异常。但是如果我消除了两个网格,那么35个属性的同一个类可以正常工作。



请注意,我添加到 TestClass 从20到35列的格式是:

  public string StringXYZ {get {returnasdfasdfasdfasdfasf ; }} 

所以,在备份数据中没有额外的内存(再次,我不认为记忆压力是问题,无论如何)。



你们都想什么?再次,任务管理器中的句柄/用户对象/ etc看起来不错,但还有其他可能丢失的东西?



原始帖子 / p>

我一直在Silverlight Toolkit DataGrid的WinRT端口上工作,在简单的测试(多种配置和多达10000行)中已经做得很好。然而,正如我已经尝试将其嵌入到另一个WinRT应用程序中,我遇到了一个零星的异常(在App.UnhandledException处理程序中引发的System.Exception类型),这是非常难以调试的。

 没有足够的配额来处理此命令。 (HRESULT的异常:0x80070718)

该错误始终是可重复的,但不是确定性的。也就是说,我可以在每次运行应用程序时进行,但并不总是通过执行相同次数的精确步骤来实现。错误似乎发生在页面转换(无论是前进到前一页还是前往页面),而不是(例如)更改datagrid的ItemsSource。



应用程序结构基本上是通过层次结构的递归访问,每个层次结构都显示一个页面。在层次结构中当前节点的页面上,显示每个子节点和一些孙子节点,对于任何子节点,可能会显示数据网格。在实践中,我一直用以下导航结构重现:

 根页:显示没有datagrid 
子页面:显示一个datagrid和一些列表浏览
Grandchild页面:显示两个datagrids,一个绑定到
与Child页面相同的源,另一个空的

一个典型的测试场景是,从根开始,移动到Child,移动到Sunchild,回到Child,然后当我再次导航到Grandchild时失败,但我上面提到的例外。但是,在第一次遇到孙子时可能会失败,否则可能会让我在失败之前来回移动几次。



调用堆栈只有一个托管框架它是未处理的异常事件处理程序。这是非常无益的。切换到混合模式调试,我得到以下内容:

  WinRTClient.exe!WinRTClient.App.InitializeComponent.AnonymousMethod__14(对象发件人, Windows.UI.Xaml.UnhandledExceptionEventArgs e)行50 + 0x20字节C#
[本机到托管转换]
Windows.UI.Xaml.dll!DirectUI :: CFTMEventSource< Windows :: UI :: Xaml: :IUnhandledExceptionEventHandler,Windows :: UI :: Xaml :: IApplication,Windows :: UI :: Xaml :: IUnhandledExceptionEventArgs> :: Raise(Windows :: UI :: Xaml :: IApplication * pSource,Windows :: UI :: Xaml: :IUnhandledExceptionEventArgs * pArgs)行327 C ++
Windows.UI.Xaml.dll!DirectUI :: Application :: RaiseUnhandledExceptionEventHelper(long hrEnceed,unsigned short * pszErrorMessage,unsigned int * pfIsHandled)行920 + 0xa字节C ++
Windows.UI.Xaml.dll!DirectUI :: ErrorHelper :: CallAUHandler(unsigned int errorCode,unsigned int * pfIsHandled,wchar_t * * pbstrErrorMessage)行39 + 0x14字节C ++
Windows.UI.Xaml.dll!DirectUI :: ErrorHel per :: ProcessUnhandledErrorForUserCode(长错误)行82 + 0x10字节C ++
Windows.UI.Xaml.dll!AgCoreCallbacks :: CallAUHandler(unsigned int errorCode)行1104 + 0x8字节C ++
Windows.UI.Xaml .dll!CCoreServices :: ReportUnhandledError(long errorXR)Line 6582 C ++
Windows.UI.Xaml.dll!CXcpDispatcher :: Tick()Line 1126 + 0xb bytes C ++
Windows.UI.Xaml.dll! CXcpDispatcher :: OnReentrancyProtectedWindowMessage(HWND__ * hwnd,unsigned int msg,unsigned int wParam,long lParam)行653 C ++
Windows.UI.Xaml.dll!CXcpDispatcher :: WindowProc(HWND__ * hwnd,unsigned int msg,unsigned int wParam,long lParam)行401 + 0x24字节C ++
user32.dll !_InternalCallWinProc@20()+ 0x23 bytes
user32.dll !_UserCallWinProcCheckWow@36()+ 0xbd bytes
user32.dll !_DispatchMessageWorker @ 8()+ 0xf8 bytes
user32.dll !_DispatchMessageW@4()+ 0x10 bytes
Windows.UI.dll!Windows :: UI :: Core :: CDispatcher :: ProcessMessage(int bDrainQueue,int * pbAnyMessages) Line 121 C ++
Windows.UI.dll!Windows :: UI :: Core :: CDispatcher :: ProcessEvents(Windows :: UI :: Core :: CoreProcessEventsOption选项)行184 + 0x10字节C ++
Windows .UI.Xaml.dll!CJupiterWindow :: RunCoreWindowMessageLoop()行416 + 0xb字节C ++
Windows.UI.Xaml.dll!CJupiterControl :: RunMessageLoop()行714 + 0x5字节C ++
Windows.UI .Xaml.dll!DirectUI :: DXamlCore :: RunMessageLoop()行2539 + 0x5 bytes C ++
Windows.UI.Xaml.dll!DirectUI :: FrameworkView :: Run()Line 91 C ++
twinapi。 dll!`Windows :: ApplicationModel :: Core :: CoreApplicationViewAgileContainer :: RuntimeClassInitialize'::`55'::< lambda_A2234BA2CCD64E2C> :: operator()(void * pv)行560 C ++
twinapi.dll! Windows :: ApplicationModel :: Core :: CoreApplicationViewAgileContainer :: RuntimeClassInitialize'::`55'::< lambda_A2234BA2CCD64E2C> ::< helper_func>(void * pv)行613 + 0xe字节C ++
SHCore.dll! _SHWaitForThreadWithWakeMask @ 12()+ 0xceab bytes
kernel32.dll !@Ba seThreadInitThunk @ 12()+ 0xe bytes
ntdll.dll!___ RtlUserThreadStart @ 8()+ 0x27 bytes
ntdll.dll!__ RtlUserThreadStart @ 8()+ 0x1b bytes

这表明,无论我做错了什么都不会注册,直到应用程序的消息循环至少有一个循环(并且我也尝试过使用Debug |打破所有抛出的异常异常... - 据我所知,没有任何东西被丢弃和吞下)我看到的有趣的堆栈框架是 WindowProc OnReentrancyProtectedWindowMessage Tick msg 是0x402(1026),这并不意味着此页面列出了以下上下文中使用的消息:

  CBEM_SETIMAGELIST 
DDM_CLOSE
DM_REPOSITION
HKM_GETHOTKEY
PBM_SETPOS
RB_DELETEBAND
SB_GETTEXTA
TB_CHECKBUTTON
TBM_GETRANGEMAX
WM_PSD_MINMARGINRECT

...但这并不意味着我,或者(甚至可能不相关)。



我可以想出的三个理论是:


  1. 内存压力。但是,我已经遇到了24%的物理内存空间,而应用程序消耗的内存不到100MB。有时候,该应用程序不会在一段时间内导致任何问题,并且占用了400MB的内存

  2. 线程问题,例如访问UI线程从工作线程。而且,事实上,我有一个后台线程发生数据访问。但是这是使用一个在WinForms环境和Outlook插件中非常可靠的(移植的)框架,我认为线程使用是安全的。此外,我可以使用相同的数据在这个应用程序没有任何问题绑定到ListViews等等。最后,配置Grandchild节点,使得在第一个数据网格中选择一行可以启动对第二个数据网格(最初为空,并且不会阻止异常)显示的第二个数据网格的详细信息的请求。没有页面转换就会发生,只要我选择了选择,就可以完美地运行。但是导航回儿童可能会立即杀死我,即使在那一点上不应该有数据访问,因此不知道我所了解的线程操作。

  3. 资源耗尽某种,也许是GUI句柄。但是我不认为我对这个系统施加了很大的压力。在一个执行中,打破异常处理程序,与使用734,37和19分别没有问题的Tweetro相比,Task Manager报告使用662句柄,21个用户对象和12个GDI对象的进程。我还有什么可以在这个类别中丢失?

我有足够的磁盘空间,并且没有使用磁盘而不是配置文件(所有这些都可以在添加datagrids之前运行得很好)。



我的下一个想法是试图通过一些潜在的有趣部分datagrid代码,跳过任何有问题的。我尝试使用datagrid的ArrangeOverride,但异常似乎并不在乎我是否做到这一点。此外,我不知道这是一个有用的策略。由于在消息循环周期之后不会抛出异常,并且由于我不知道它将要发生什么,所以我需要覆盖大量的排列,运行每个排列很多时间,以隔离问题代码。



在Debug和Release模式下都会抛出该错误。而且,作为最后的背景说明,我们在这里处理的数据量很小,远远小于我的10000行数据网格隔离。它可能在50-100行的顺序,也许30-40列。在抛出异常之前,数据和网格似乎工作正常,并且回复正常。



所以,这就是为什么我来找你。我的两个问题是:


  1. 错误信息是否提供了关于什么可能是问题的提示? >
  2. 您将用什么调试策略来隔离问题代码?

非常感谢您的任何帮助你可以提供!

解决方案

确定,一些 Tim Heuer [MSFT] 的关键输入,我弄清楚发生了什么,以及如何获得围绕这个问题。



令人惊讶的是,我的三个初步猜测都不正确。这不是关于内存,线程或系统资源。相反,它是关于Windows消息传递系统的限制。显然它有点像一个堆栈溢出异常,因为当你一次性对可视化树进行太多的更改时,异步更新队列就会变得很长时间,以至于它跳过了一个线程,异常被抛出。



在这种情况下,问题是有足够的UIElements进入我正在使用的数据网格,允许网格一次生成所有自己的列,在某些情况下可以超过限制。我一直在使用一些网格,并且所有的加载都是为了响应页面导航事件,这使得它变得更棘手。



幸运的是,限制我正在进入视觉树或XAML UI子系统本身的限制,只是在用于更新它的消息中。这意味着如果我可以在调度员的时钟的多个滴答上展开相同的操作,我可以完成相同的最终结果。



我最后做的是指示我的数据网格不会自动生成自己的列。相反,我将网格嵌入到用户控件中,当加载数据时,将分析所需的列并将其加载到列表中。然后,我调用以下方法:

  void LoadNextColumns(List< ColumnDisplaySetup> colDef,int startIdx,int numToLoad)
{
for(int idx = startIdx; idx< startIdx + numToLoad&&id;< colDef.Count; idx ++)
{
DataGridTextColumn newCol = new DataGridTextColumn();
newCol.Header = colDef [idx] .Header;
newCol.Binding = new Binding(){Path = new PropertyPath(colDef [idx] .Property)};
dgMainGrid.Columns.Add(newCol);
}

if(startIdx + numToLoad< colDef.Count)
{
Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,()= &$
{
LoadNextColumns(colDef,startIdx + numToLoad,numToLoad);
});
}
}

ColumnDisplaySetup 是用于容纳已解析配置或从文件加载的配置的简单类型。)



此方法分别使用以下参数进行调用:列的列表,0和我的任意猜测5作为一个相当安全的列数一次加载;但是这个数字是基于测试和期望,可以同时加载大量的网格。我向蒂姆提供了更多信息,可能会通知这一部分过程,如果我进一步了解如何确定多少安全性,那么这里将会回报。



在实践中,这似乎有效地工作,尽管它会导致您期望的渐进式渲染,列可以弹出。我希望这可以通过使用最大可能的值 numToLoad 和其他UI滑行手。我可能调查在生成列时隐藏网格,并且只有在所有内容准备就绪时才显示结果。最终,这个决定会让人感觉更加快速和流动。



再次,如果我得到更多信息,我会更新这个答案,但我希望这个帮助未来遇到类似问题的人。在投入更多的时间比我想要承认的追捕之后,我不希望任何人不得不杀死自己。


Edit Sept 26

See below for the full background. tl;dr: A data grid control is causing odd exceptions, and I am looking for help isolating the cause and finding a solution.

I've narrowed this down a bit further. I have been able to reproduce the behavior in a smaller test app with more reliable triggering of the erratic behavior.

I can definitely rule out both threading and (I think) memory issues. The new app uses no Tasks or other threading/asynchronous features, and I can trigger the unhandled exception simply by adding properties that return a constant to the class of objects shown in the DataGrid. This indicates to me that the problem is either in unmanaged resource exhaustion or something I haven't thought of yet.

The revised program is structured like this. I have created a user control called EntityCollectionGridView which has a label and a data grid. In the control's Loaded event handler, I assign a List<TestClass> to the data grid with 1000 or 10000 rows, letting the grid generate the columns. This user control is instantiated 2-4 times in MainPage.xaml in the page's OnNavigatedTo event (or Loaded, it doesn't seem to matter). If an exception occurs, it occurs immediately after MainPage is shown.

The interesting thing is, the behavior doesn't seem to vary with the number of rows shown (it will work reliably with 10000 rows or fail reliably with only 1000 rows in each grid) but rather with the total number of columns in all the grids loaded at a given time. With 20 properties to show, 4 grids works fine. With 35 properties and 4 grids, the exception is thrown. But if I eliminate two grids, the same class with 35 properties will work fine.

Note that all of the properties I add to TestClass to jump from 20 to 35 columns are of the form:

public string StringXYZ { get { return "asdfasdfasdfasdfasf"; } }

So, there's no additional memory in the backing data (and again, I don't think memory pressure is the problem anyway).

What do you all think? Again, the handles/user objects/etc in Task Manager look good, but is there something else I might be missing?

Original post

I have been working on a port of the Silverlight Toolkit DataGrid to WinRT, and it has done well enough in simple tests (a variety of configurations and up to 10000 rows). However, as I have tried to embed it into another WinRT app I have run into a sporadic exception (of type System.Exception, raised in the App.UnhandledException handler) that is proving very difficult to debug.

Not enough quota is available to process this command. (Exception from HRESULT: 0x80070718)

The error is consistently reproducible, but not deterministically. That is, I can make it happen every time I run the App, but it doesn't always happen by performing the same exact set of steps the same number of times. The error seems to occur on page transitions (whether navigating to a new page forward or back to a previous page), and not (for instance) when changing the ItemsSource of the datagrid.

The application structure is basically recursive access through a hierarchy, with a page shown at each hierarchy level. On the page for the current node in the hierarchy, each child node and some grandchild nodes are shown, and for any subnode a datagrid may be shown. In practice, I consistently reproduce this with the following navigation structure:

Root page: shows no datagrid
  Child page: shows one datagrid and a few listviews
    Grandchild page: shows two datagrids, one bound to the
                     same source as Child page, the other one empty

A typical test scenario is, start at Root, move to Child, move to Grandchild, move back to Child, and then when I try to navigate to Grandchild again, it fails with the exception I mentioned above. But it might fail the first time I hit Grandchild, or it might let me move back and forth a few times before failing.

The call stack has only one managed frame on it, which is the unhandled exception event handler. This is very unhelpful. Switching to mixed mode debugging, I get the following:

WinRTClient.exe!WinRTClient.App.InitializeComponent.AnonymousMethod__14(object sender, Windows.UI.Xaml.UnhandledExceptionEventArgs e) Line 50 + 0x20 bytes  C#
[Native to Managed Transition]  
Windows.UI.Xaml.dll!DirectUI::CFTMEventSource<Windows::UI::Xaml::IUnhandledExceptionEventHandler,Windows::UI::Xaml::IApplication,Windows::UI::Xaml::IUnhandledExceptionEventArgs>::Raise(Windows::UI::Xaml::IApplication * pSource, Windows::UI::Xaml::IUnhandledExceptionEventArgs * pArgs)  Line 327  C++
Windows.UI.Xaml.dll!DirectUI::Application::RaiseUnhandledExceptionEventHelper(long hrEncountered, unsigned short * pszErrorMessage, unsigned int * pfIsHandled)  Line 920 + 0xa bytes   C++
Windows.UI.Xaml.dll!DirectUI::ErrorHelper::CallAUHandler(unsigned int errorCode, unsigned int * pfIsHandled, wchar_t * * pbstrErrorMessage)  Line 39 + 0x14 bytes   C++
Windows.UI.Xaml.dll!DirectUI::ErrorHelper::ProcessUnhandledErrorForUserCode(long error)  Line 82 + 0x10 bytes   C++
Windows.UI.Xaml.dll!AgCoreCallbacks::CallAUHandler(unsigned int errorCode)  Line 1104 + 0x8 bytes   C++
Windows.UI.Xaml.dll!CCoreServices::ReportUnhandledError(long errorXR)  Line 6582    C++
Windows.UI.Xaml.dll!CXcpDispatcher::Tick()  Line 1126 + 0xb bytes   C++
Windows.UI.Xaml.dll!CXcpDispatcher::OnReentrancyProtectedWindowMessage(HWND__ * hwnd, unsigned int msg, unsigned int wParam, long lParam)  Line 653 C++
Windows.UI.Xaml.dll!CXcpDispatcher::WindowProc(HWND__ * hwnd, unsigned int msg, unsigned int wParam, long lParam)  Line 401 + 0x24 bytes    C++
user32.dll!_InternalCallWinProc@20()  + 0x23 bytes  
user32.dll!_UserCallWinProcCheckWow@36()  + 0xbd bytes  
user32.dll!_DispatchMessageWorker@8()  + 0xf8 bytes 
user32.dll!_DispatchMessageW@4()  + 0x10 bytes  
Windows.UI.dll!Windows::UI::Core::CDispatcher::ProcessMessage(int bDrainQueue, int * pbAnyMessages)  Line 121   C++
Windows.UI.dll!Windows::UI::Core::CDispatcher::ProcessEvents(Windows::UI::Core::CoreProcessEventsOption options)  Line 184 + 0x10 bytes C++
Windows.UI.Xaml.dll!CJupiterWindow::RunCoreWindowMessageLoop()  Line 416 + 0xb bytes    C++
Windows.UI.Xaml.dll!CJupiterControl::RunMessageLoop()  Line 714 + 0x5 bytes C++
Windows.UI.Xaml.dll!DirectUI::DXamlCore::RunMessageLoop()  Line 2539 + 0x5 bytes    C++
Windows.UI.Xaml.dll!DirectUI::FrameworkView::Run()  Line 91 C++
twinapi.dll!`Windows::ApplicationModel::Core::CoreApplicationViewAgileContainer::RuntimeClassInitialize'::`55'::<lambda_A2234BA2CCD64E2C>::operator()(void * pv)  Line 560  C++
twinapi.dll!`Windows::ApplicationModel::Core::CoreApplicationViewAgileContainer::RuntimeClassInitialize'::`55'::<lambda_A2234BA2CCD64E2C>::<helper_func>(void * pv)  Line 613 + 0xe bytes   C++
SHCore.dll!_SHWaitForThreadWithWakeMask@12()  + 0xceab bytes    
kernel32.dll!@BaseThreadInitThunk@12()  + 0xe bytes 
ntdll.dll!___RtlUserThreadStart@8()  + 0x27 bytes   
ntdll.dll!__RtlUserThreadStart@8()  + 0x1b bytes    

This indicates to me that whatever I'm doing wrong doesn't register until after at least one cycle in the app's message loop (and I also tried breaking on all thrown exceptions using "Debug | Exceptions..." -- as far as I can tell, nothing is thrown and swallowed). The interesting stack frames I see are WindowProc, OnReentrancyProtectedWindowMessage, and Tick. The msg is 0x402 (1026), which doesn't mean anything to me. This page lists that message as used in the following contexts:

CBEM_SETIMAGELIST 
DDM_CLOSE 
DM_REPOSITION 
HKM_GETHOTKEY 
PBM_SETPOS 
RB_DELETEBAND 
SB_GETTEXTA 
TB_CHECKBUTTON 
TBM_GETRANGEMAX 
WM_PSD_MINMARGINRECT

...but that doesn't mean anything much to me, either (it might not even be relevant).

The three theories I can come up with are these:

  1. Memory pressure. But I have run into this with 24% of my physical memory free and the app consuming less than 100MB of memory. Other times, the app won't have hit any problems navigating around a while and racking up 400MB of memory
  2. Threading problems, such as access to the UI thread from a worker thread. And, in fact, I do have data access happening on a background thread. But this is using a (ported) framework that has been very reliable in a WinForms environment and in an Outlook plugin, and I think the thread use is safe. Additionally, I can use the same data in this app without any problems binding just to ListViews and so forth. Finally, the Grandchild node is configured such that selecting a row in the first datagrid kicks off a request for the row's detail items, which are displayed in the second datagrid (which is initially empty, and can remain so without preventing the exception). This happens without a page transition and works flawlessly for as long as I choose to fiddle with the selection. But navigating back to Child might kill me right away, even though there should be no data access at that point and therefore not threading operations that I know of.
  3. Resource exhaustion of some kind, maybe GUI handles. But I don't think I'm putting that much pressure on this system. In one execution, breaking in the exception handler, Task Manager reports the process using 662 handles, 21 User objects, and 12 GDI objects, as compared to Tweetro which is using 734, 37, and 19 respectively without problems. What else might I be missing in this category?

I have plenty of disk space free, and am not using the disk for anything other than configuration files anyway (and all that worked fine before adding the datagrids).

My next thought was to try to step through some of the potential 'interesting' parts of the datagrid code and jump over any that were questionable. I did try that with the datagrid's ArrangeOverride, but the exception didn't seem to care whether I did that or not. Also, I am not sure this is a useful strategy. Since the exception isn't being thrown until after a cycle on the message loop, and since I can't know for sure when it's about to happen, I would need to cover a huge number of permutations, running each permutation a whole lot of times, to isolate the problem code.

The error is thrown in both Debug and Release modes. And, as a final background note, the amount of data we're dealing with here is small, much smaller than my 10000-row runs of the datagrid in isolation. It's probably on the order of 50-100 rows, with perhaps 30-40 columns. And before the exception is thrown, the data and the grids seem to work and respond fine.

So, that's why I come to you. My two questions are:

  1. Does the error information give you any hints as to what might be the problem?
  2. What debugging strategy would you use to isolate the problem code?

Many thanks in advance for any help you can provide!

解决方案

OK, with some critical input from Tim Heuer [MSFT], I figured out what was going on and how to get around this problem.

Surprisingly, none of my three initial guesses were correct. This wasn't about memory, threading, or system resources. Instead, it was about limitations in the Windows messaging system. Apparently it is a little like a stack overflow exception, in that when you make too many changes to the visual tree all at once, the asynchronous update queue gets so long that it trips a wire and the exception gets thrown.

In this case, the problem is that there are enough UIElements going into the data grid I am working with that allowing the grid to generate all its own columns all at once can in some cases exceed the limit. I was using a number of grids all at once, and all loading in response to page navigation events, which made it all the trickier to nail down.

Thankfully, the limitations I was running into were NOT limitations in the visual tree or the XAML UI subsystem itself, just in the messaging used to update it. This means that if I could spread out the same operations over multiple ticks of the dispatcher's clock, I could accomplish the same end result.

What I ended up doing was to instruct my data grid not to autogenerate its own columns. Instead, I embedded the grid into a user control that, when the data was loaded, would parse out the columns needed and load them into a list. Then, I called the following method:

void LoadNextColumns(List<ColumnDisplaySetup> colDef, int startIdx, int numToLoad)
{
    for (int idx = startIdx; idx < startIdx + numToLoad && idx < colDef.Count; idx++)
    {
        DataGridTextColumn newCol = new DataGridTextColumn();
        newCol.Header = colDef[idx].Header;
        newCol.Binding = new Binding() { Path = new PropertyPath(colDef[idx].Property) };
        dgMainGrid.Columns.Add(newCol);
    }

    if (startIdx + numToLoad < colDef.Count)
    {
        Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                    LoadNextColumns(colDef, startIdx + numToLoad, numToLoad);
            });
    }
}

(ColumnDisplaySetup is a trivial type used to house the parsed-out configuration or a configuration loaded from a file.)

This method is called with the following arguments, respectively: list of columns, 0, and my arbitrary guess of 5 as a fairly safe number of columns to load at a time; but this number is based on testing and the expectation that a good number of grids could be loading simultaneously. I asked Tim for more information that might inform this part of the process, and will report back here if I learn more about how to determine how much is safe.

In practice, this seems to work adequately, although it results in the sort of progressive rendering you'd expect, with the columns visibly popping in. I expect this could be improved both by using the maximum possible value for numToLoad and by other UI sleight-of-hand. I may investigate hiding the grid while the columns are generated and only showing the result when everything is ready. Ultimately the decision will come down to which feels more 'fast and fluid'.

Again, I will update this answer with more information if I get it, but I hope this helps someone facing similar problems in the future. After pouring more time than I'd care to admit into the bug hunt, I don't want anyone else to have to kill themselves over this.

这篇关于神秘的“没有足够的配额来处理这个命令”在DataGrid的WinRT端口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆