异步调用.NET方法并在完成时绑定到网格

时间:2012-04-19 23:20:40

标签: c# asp.net gridview updatepanel ajax.net

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的回发中调用手动更新,它确实更新了标签。这就是为什么我当前的设置不起作用的原因,尽管我仍然在寻找在完成异步任务时更新内容的最佳方法。

2 个答案:

答案 0 :(得分:2)

杰米走在正确的轨道上。在呈现页面后,您的服务器无法将新数据“推送”到客户端。客户端必须发起请求。我会在客户端设置一个计时器或使用JavaScript setTimeout来定期轮询服务器以查看它是否完成。

Web服务方法

另一种方法是在服务器上设置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();
        }
    }
}

从客户端调用Web服务

接下来,您需要使用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>

参考 http://aspalliance.com/1301_Unveil_the_Data_Binding_Architecture_inside_Microsoft_ASPNET_Ajax_10__Part_1

http://aspalliance.com/1301_Unveil_the_Data_Binding_Architecture_inside_Microsoft_ASPNET_Ajax_10__Part_2

答案 1 :(得分:1)

我想分享这个问题的完整解决方案。虽然msigman的答案是一个很大的帮助,但它并没有让我一路走来。我还没有找到从客户端绑定到GridView的可行解决方案,所以我正在从javascript创建网格。

1 - 设置控制器以处理请求

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")
        );
    }
}

2 - 使用AJAX

启动请求

这可以在页面加载时通过手动执行$(document).ready()事件,按钮单击或定期使用计时器来完成。

        $.ajax({
            url: "api/timers",
            dataType: "json",
            success: function (result) { bindGrid(result); }
        })

3 - 将数据绑定到网格

正如我所说,我还没有找到一种方法将数据从客户端绑定到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
        });
    }