我使用CodePlex的一些想法和Bea Stollnitz的博客以及Vincent Da Ven Berhge的论文(同一链接)实现了数据虚拟化解决方案.但是我需要一种不同的方法,所以我决定编写自己的解决方案.
我DataGrid用这个解决方案来显示大约一百万行.我也在使用UI虚拟化.我的解决方案是可行的,但我在某些情况下遇到了一些奇怪的行为,这些行为是关于如何DataGrid从源头请求数据的.
关于解决方案
我最终编写了一份列表来完成所有繁重的工作.它是一个名为VirtualList<T>.It 的泛型类,它实现了ICollectionViewFactory接口,因此集合视图创建机制可以创建一个VirtualListCollectionView<T>实例来包装它.这个类继承自ListCollectionView.我没有按照建议编写我自己的ICollectionView实现.继承似乎也很好.
在VirtualList<T>分裂整个数据到页.它获取总项数,每次DataGrid通过列表索引器对行进行请求时,它会加载相应的页面或从缓存中返回.页面在内部回收,并DispatcherTimer在空闲时间处理未使用的页面.
数据请求模式
我学到的第一件事就是VirtualList<T>实现IList(非泛型).否则,ItemsControl它将把它视为一个IEnumerable并查询/枚举所有行.这是合乎逻辑的,因为DataGrid它不是类型安全的,所以它不能使用IList<T>接口.
带有0索引的行经常被问到DataGrid.它似乎用于视觉项目测量(根据调用堆栈).所以,我只是缓存这一个.
内部的缓存机制DataGrid使用可预测的模式来查询它显示的行.首先它要求从上到下的可见行(每行两次),然后它在可见区域(包括第一个可见行)之前查询几行(取决于可见区域的大小)从下到上依次订购.之后,它在从上到下的可见行(包括最后一个可见行)之后请求相同数量的行.
如果可见行索引是4,5,6.数据请求将是:4,4,5,5,6,6,4,3,2,1,6,7,8,9.
如果我的页面大小设置正确,我可以从当前和以前加载的页面提供所有这些请求.
如果CanSelectMultipleItems是True并且用户使用SHIFT按钮或鼠标拖动选择多个项目,则DataGrid枚举从列表开头到选择结尾的所有行.IEnumerable无论IList是否实现,此枚举都通过接口发生.
如果所选行不可见且当前可见区域与所选行"远",则有时DataGrid会开始请求从所选行到可见区域末尾的所有项目.包括其间甚至不可见的所有行.我无法弄清楚这种行为的确切模式.也许我的实施就是这个原因.
我的问题
我想知道,为什么DataGrid不可见行的请求,因为这些行将在可见时再次请求?
为什么有必要要求每一行两到三次?
任何人都可以告诉我如何使DataGrid不使用IEnumerable,除了关闭多个项目选择?
请检查以下代码段:
public interface ICountable { }
public class Counter<T>
where T : ICountable
{
public int Count(IEnumerable<T> items)
{
return 0;
}
public int Count(T Item)
{
return 0;
}
}
public class Counter
{
public int Count<T>(IEnumerable<T> items)
where T : ICountable
{
return 0;
}
public int Count<T>(T Item)
where T : ICountable
{
return 0;
}
}
Run Code Online (Sandbox Code Playgroud)
Counter的两个版本仅在泛型参数的规范上有所不同.其中一个定义为泛型类型参数,另一个定义为泛型参数.两者都限制方法参数以实现ICountable接口.我将分别称他们为具体和非具体.
现在,我定义了一个实现ICountable接口的类,以及一组实例:
public class CItem : ICountable { }
var countables = new List<CItem>(); …Run Code Online (Sandbox Code Playgroud) 我有两个aspnet.core服务.一个用于IdentityServer 4,另一个用于Angular4 +客户端使用的API.SignalR集线器在API上运行.整个解决方案在docker上运行,但这无关紧要(见下文).
我使用隐式身份验证流程,它可以完美运行.NG应用程序重定向到用户登录的IdentityServer的登录页面.之后,浏览器将被重定向回带有访问令牌的NG应用程序.然后,令牌用于调用API并与SignalR建立通信.我想我已经阅读了所有可用的内容(参见下面的资料).
由于SignalR使用不支持头的websockets,因此令牌应该在查询字符串中发送.然后在API端,提取令牌并为请求设置令牌,就像它在标题中一样.然后验证令牌并授权用户.
API在没有任何问题的情况下工作,用户获得授权,并且可以在API端检索声明.因此,IdentityServer应该没有问题,因为SignalR不需要任何特殊配置.我对吗?
当我不使用SignalR集线器上的[Authorized]属性时,握手成功.这就是为什么我认为我使用的docker基础设施和反向代理没有任何问题(代理设置为启用websockets).
所以,没有授权SignalR工作.通过授权,NG客户端在握手期间获得以下响应:
Failed to load resource: the server responded with a status of 401
Error: Failed to complete negotiation with the server: Error
Error: Failed to start the connection: Error
Run Code Online (Sandbox Code Playgroud)
请求是
Request URL: https://publicapi.localhost/context/negotiate?signalr_token=eyJhbGciOiJSUz... (token is truncated for simplicity)
Request Method: POST
Status Code: 401
Remote Address: 127.0.0.1:443
Referrer Policy: no-referrer-when-downgrade
Run Code Online (Sandbox Code Playgroud)
我得到的回应:
access-control-allow-credentials: true
access-control-allow-origin: http://localhost:4200
content-length: 0
date: Fri, 01 Jun 2018 09:00:41 GMT
server: nginx/1.13.10
status: 401
vary: Origin
www-authenticate: …Run Code Online (Sandbox Code Playgroud) c# websocket asp.net-core identityserver4 asp.net-core-signalr
Flutter Web 应用程序发送一个 HTTP REST API POST 请求,并在 Set-Cookie 标头中获取一个 JSON 响应和一个 cookie,如下所示。
(Flutter (Channel beta, 1.22.0, on Microsoft Windows)
提取 cookie 时,响应似乎没有找到标头值。调用和提取代码为:
var response = await http.post(url, headers: {"Content-Type": "application/json"}, body: jsonEncode(data));
if (response.statusCode == 200) {
var cookie = response.headers['set-cookie'];
print('cookie: $cookie');
}
Run Code Online (Sandbox Code Playgroud)
控制台结果是:
cookie: null
Run Code Online (Sandbox Code Playgroud)
服务器端在 Docker 容器中的 ASPNet.Core 3.1 上运行,但是这应该不是问题,因为 cookie 位于标头中。那么,如何在 Flutter Web 中提取它呢?
实际上,我的最终目标是将 cookie 与所有其他请求一起发回。但它似乎不会在浏览器中自动发生。因此,如果有人可以指出处理这种情况的正确方法,这也是一个很好的解决方案。
任何帮助表示赞赏。谢谢。
c# ×2
.net ×1
asp.net-core ×1
cookies ×1
datagrid ×1
flutter ×1
flutter-web ×1
generics ×1
websocket ×1
wpf ×1