我的流程如下:
用户执行一个复杂的搜索,该搜索通过 ajaxly 完成,返回一堆 id(可能是 1,可能是 10000)
一旦他们有了用户,他们就可以选择一些内容,然后下载一个文件(这是一个基于 ID 和他们选择的内容的报告)
为了实现这一点,我使用了 $.download 的高度修改版本。
在这里看到:
jQuery.download = function (url, data, method, loadingHolderDivId) {
if (url && typeof data == 'object') {
//for this version, data needs to be a json object.
//loop through the data object..
$('#' + loadingHolderDivId).html($('#LoadingScreen').html());
var theForm = $('<form></form>').attr('action', url).attr('method', method).attr('id', 'jqueryDownloadForm').attr('target', 'iframeX');
$.each(data, function (propertyName, propertyVal) {
if (propertyVal != null) {
if (typeof propertyVal == 'object') {
//HANDLE ARRAYS!
for (var i = 0, len = propertyVal.length; i < len; ++i) {
theForm.append($("<input />").attr('type', 'hidden').attr('id', propertyName + i.toString).attr('name', propertyName).val(propertyVal[i]));
}
}
else {
theForm.append($("<input />").attr('type', 'hidden').attr('id', propertyName).attr('name', propertyName).val(propertyVal));
}
}
});
var iframeX;
var downloadInterval;
// remove old iframe if has
$("#iframeX").remove();
// create new iframe
iframeX = $('<iframe src="javascript:false;" name="iframeX" id="iframeX"></iframe>').appendTo('body').hide();
if ($.browser.msie) {
downloadInterval = setInterval(function () {
// if loading then readyState is “loading” else readyState is “interactive”
if (iframeX && iframeX[0].readyState !== "loading") {
$('#' + loadingHolderDivId).empty();
clearInterval(downloadInterval);
}
}, 23);
}
else {
iframeX.load(function () {
$('#' + loadingHolderDivId).empty();
});
}
theForm.appendTo('body').trigger('submit').remove();
return false;
}
else {
//they didn't fill in the params. do nothing
}
};
基本上,它的作用是解析数据中的内容,并从中构建一个表单。当没有很多 id 时,这非常有效。但是当有 8000 时,在 IE 中需要 5 或 10 秒,这并不奇怪,众所周知 IE 在 dom 操作方面很糟糕。
另一个问题是在 IE 中。 $('#' + loadingHolderDivId).html($('#LoadingScreen').html());
在完成表单构建之后才会真正发生。我猜测这是因为需要一秒钟才能完成此操作,并且在完成之前它已经忙于构建表单。
我以这种方式构建表单的原因是,默认模型绑定(bind)器会很高兴并将我的表单直接绑定(bind)到一个可爱的模型中。 id 列表被绑定(bind)到 ilist(整数)
以下是 Controller 操作的示例:
Function ExportUsers(ByVal model As ExportUsersPostModel) As ActionResult
这是模型的示例:
<Serializable()> _
Public Class ExportUsersPostModel
Public Property FilterUserIds As IList(Of Integer) = New List(Of Integer)
Public Property FilterColumnIds As IList(Of Integer) = New List(Of Integer)
public property ShowThis as boolean
public property OtherStuff as string = string.empty
Public Property FormatId As Integer
End Class
所以实际的问题有两个:
如何在开始极其缓慢的死亡形式构建之前显示“正在加载”消息?
如何加快表单构建速度,或者以不慢的方式构建表单,但仍能让模型绑定(bind)器满意?
最佳答案
如果您能够将模型作为 JSON 传递,则可以创建自定义 ModelBinder 来处理将 JSON 映射到您的数据结构。我最近为无法自动映射的对象类型执行了此操作。 Json.Net提供了一个名为 JObject 的类,它接受 JSON 字符串并将其映射到动态 C# 对象。然后,您可以将动态对象映射到强类型对象。
要创建自定义 ModelBinder,只需创建一个继承自 IModelBinder 的类并实现 BindModel 方法即可。这是我的实现的副本。您的显然会略有不同:
internal class FilterBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (controllerContext == null)
throw new ArgumentNullException("controllerContext");
if (bindingContext == null)
throw new ArgumentNullException("bindingContext");
if ((controllerContext.HttpContext.Request.Form.Count > 1 || (controllerContext.HttpContext.Request.Form.Count == 1 && !string.IsNullOrWhiteSpace(controllerContext.HttpContext.Request.Form.AllKeys[0]))) || (controllerContext.HttpContext.Request.QueryString.Count > 1 || (controllerContext.HttpContext.Request.QueryString.Count == 1 && !string.IsNullOrWhiteSpace(controllerContext.HttpContext.Request.QueryString.AllKeys[0]))))
{
ValueProviderResult val = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
string value = val == null || string.IsNullOrEmpty(val.AttemptedValue) ? string.Empty : val.AttemptedValue;
if (string.IsNullOrEmpty(value)) return null;
dynamic obj = JObject.Parse(value);
return new FilterSet(obj);
}
else
return null;
}
}
我有很多检查来确保我得到的内容是有效的,您可能需要也可能不需要。然后,在获取 JObject 后,我将其传递给执行映射的构造函数。
关于jquery - 使用 jquery $.download 处理可能非常大的表单创建/发布的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5980548/