2

Container.RetrieveItems() 调用一个需要一段时间的服务,所以我想异步调用它(在检索到项目后,它们被设置为 Container 类的 List 属性)。完成检索项目后,我希望它更新 updatePanel 内的 gridView(updatePanel Mode="Conditional" 和 ScriptManager EnablePartialRendering="true"。UpdatePanel 没有触发项目)。

我已经设置了断点并逐步完成了每一步。检索项目,网格是数据绑定然后它调用更新。没有抛出异常,但网格没有随内容更新。如果我将 UpdatePanel 设置为使用触发器和 Timer.OnTick 事件进行更新,它可以完美运行,但是我只需要在检索项目后更新它,因此在服务调用完成后触发手动 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() 但没有变化。

根据 Jaimes 的建议,然后我尝试在 Button_click 的回发中调用手动更新,它确实更新了标签。这就是为什么我当前的设置不起作用的原因,尽管我仍在寻找在完成异步任务时更新内容的最佳方法。

4

2 回答 2

2

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

网络服务方法

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

于 2012-04-21T03:21:58.183 回答
1

我想分享我对这个问题的完整解决方案。虽然 msigman 的回答帮了我很大的忙,但它并没有让我一路走好。我还没有找到从客户端绑定到 GridView 的可行解决方案,因此我从 javascript 创建网格。

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

MVC 控制器可以通过 AJAX 从客户端调用,这允许您从客户端调用任何 .NET 代码。这是一个关键部分,因为所有的功能和繁重的工作都可以由控制器/服务完成,但您仍然拥有 javascript 的灵活性。我在这里发布了一个完整的示例,说明如何执行此操作,从 JavaScript 调用 ASP.NET 函数?. (可以与 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 框架可以为您执行此操作。Kendo UI ( http ://demos.kendoui.c​​om/web/grid/index.html ) (以及许多其他有用的小部件)是一个这样的 UI 框架,它有一个很好的网格对象,您可以直接将 JSON 数据绑定到该对象。这篇 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
        });
    }   
于 2012-06-19T07:26:23.280 回答