Container.RetrieveItems()调用一段时间的服务,所以我想异步调用它(在检索项后,它们被设置为Container类的List属性)。完成检索项目后,我希望它更新一个在updatePanel内的gridView(updatePanel Mode =“Conditional”和ScriptManager EnablePartialRendering =“true”.UpdatePanel没有触发项)。
我设置了断点并逐步完成了每一步。检索项目,网格是数据绑定然后它调用更新。没有异常被抛出,但网格没有随内容更新。如果我使用触发器和Timer.OnTick事件将UpdatePanel设置为更新它工作正常,但是我只需要在检索项目后进行更新,因此在完成服务调用后触发手动UpdatePanel.Update()将是理想的。
我做了很多搜索,但所有答案都是'你忘了打电话给DataBind()'
我有什么遗漏的吗?
private void UpdateGrid()
{
grid.DataSource = Container.List;
grid.DataBind();
updatePanel.Update();
}
protected void Page_Load(object sender, EventArgs e)
{
var task = Task.Factory.StartNew(Container.RetrieveItems);
task.ContinueWith((x) => UpdateGrid());
}
更新 我设置了一个更简单的测试来尝试识别问题。我创建了一个标签,其Text属性将在完成方法后更新。当页面加载时,它调用方法,当方法完成时调用updatePanel.Update()但没有改变。
Per Jaimes的建议,然后我尝试在Button_click的回发中调用手动更新,它确实更新了标签。这就是为什么我当前的设置不起作用的原因,尽管我仍然在寻找在完成异步任务时更新内容的最佳方法。
答案 0 :(得分:2)
杰米走在正确的轨道上。在呈现页面后,您的服务器无法将新数据“推送”到客户端。客户端必须发起请求。我会在客户端设置一个计时器或使用JavaScript setTimeout
来定期轮询服务器以查看它是否完成。
另一种方法是在服务器上设置Web服务,然后从您的页面调用它。这将在新线程中执行,并在结果可用时立即异步更新网格。
首先,您需要设置WCF Web服务。如果您不确定,有数以千计的文章。以下是其中之一:http://www.codeproject.com/Articles/16973/Simple-Web-Service-using-WCF-Windows-Communication
以下是我的一个项目的示例代码:
namespace UI.Web.WebServices
{
[ServiceContract(Namespace = "WebServices")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class WebServiceName
{
[OperationContract]
[WebInvoke(ResponseFormat = WebMessageFormat.Json)]
public FacilityResult[] MethodName()
{
FacilityService facilityService = new
return facilityService .GetAssignments()).ToArray();
}
}
}
接下来,您需要使用JavaScript:http://blog.ashmind.com/2007/06/21/client-side-databinding-with-aspnet-ajax-futures/
在您的页面中对网格进行数据绑定以下是同一项目的一些示例代码。这个项目使用jQuery而不是像链接中的样本那样的纯JavaScript:
<script type="text/javascript">
function getGridData() {
var payload = { }; // Put data to include here, if any
$.ajax({
type: "POST",
url: "/WebServiceName.svc/MethodName",
data: JSON.stringify(payload),
contentType: "application/json",
dataType: "json",
success: function (msg) {
bindResultsToGrid(msg.d);
},
error: function (xhr) { alert('error' + xhr.responseText); }
});
}
function bindResultsToGrid(data)
{
...
}
</script>
答案 1 :(得分:1)
我想分享这个问题的完整解决方案。虽然msigman的答案是一个很大的帮助,但它并没有让我一路走来。我还没有找到从客户端绑定到GridView的可行解决方案,所以我正在从javascript创建网格。
MVC控制器可以通过AJAX从客户端调用,允许您从客户端调用任何.NET代码。这是一个关键部分,因为所有电源和重物都可以由控制器/服务完成,但您仍然具有javascript的灵活性。我在这里发布了一个完整的示例,说明如何执行此操作Call ASP.NET function from JavaScript?。 (可与Webforms或MVC一起使用)。
public class TimersController : ApiController
{
public HttpResponseMessage<TimerDisplay[]> Get()
{
return new HttpResponseMessage<TimerDisplay[]>(
TimerRepository.Get(), // all your .NET logic can be encapsulated here
new MediaTypeHeaderValue("application/json")
);
}
}
这可以在页面加载时通过手动执行$(document).ready()事件,按钮单击或定期使用计时器来完成。
$.ajax({
url: "api/timers",
dataType: "json",
success: function (result) { bindGrid(result); }
})
正如我所说,我还没有找到一种方法将数据从客户端绑定到GridView。我觉得更好的解决方案是使用完全删除GridView(这更像是服务器端控件而且对于这种情况不灵活),并且在它的位置你可以从Javascript生成网格。虽然您可以手动遍历数据并自己创建<tr>
和<td>
,但有很多网格/ ui框架可以为您执行此操作。一个这样的UI框架有一个很好的网格对象,可以直接将JSON数据绑定到Kendo UI(http://demos.kendoui.com/web/grid/index.html)(以及许多其他有用的小部件)。此SO帖子包含有关javascript UI框架https://stackoverflow.com/questions/159025/jquery-grid-recommendations的更多建议。
function bindGrid(gridData) {
var grid = $("#grid");
grid.html("");
grid.kendoGrid({
columns: [
{ field: "Place", title: "Place" },
{ field: "Time", title: "Time" }
],
dataSource: {
data: gridData
},
scrollable: false
});
}