2014-10-02 38 views
1

我們最近開始研究一個新應用程序,該應用程序將用於非常有限帶寬的環境中。因爲我的設計師擔心加載數據的時間。取消對存儲過程的調用

目前我們有一個系統,如下所示:

一個ListView充滿了出貨量,點擊出貨顯示了側面板。 側面板上有一個「Details」按鈕,點擊此按鈕將進行存儲過程調用以加載所選貨件的詳細信息。

現在在我們以前的應用程序中,這不是線程化的,加載時間很短以至於不會引起任何問題(位於內部網絡上)。然而,由於新的限制,我們現在將調用過程調用並顯示加載動畫,但是我的設計人員想要添加取消加載的功能。

這是我卡住的地方,因爲按鈕調用我的靜態庫(LoadDetails)上的單個方法我看不到一種方法來取消此加載。除此之外,用戶可以選擇貨件點擊細節,然後選擇第二個,第三個貨件點擊所有這些細節,並對多個線程加載數據進行後臺處理。

資源庫LoadDetails如下:

private static bool LoadDetails(int shipmentId) 
    { 
     DataConnection dbCon = null; 
     try 
     { 
      dbCon = ApplicationRoleService.EnableAppRole(); 
      if (dbCon.SqlConn == null) 
      { 
       return false; 
      } 

      SqlCommand cmd = new SqlCommand("LBN.sel_shipments_details"); 
      cmd.CommandType = CommandType.StoredProcedure; 
      cmd.Connection = dbCon.SqlConn; 

      SqlParameter paramShipmentId = new SqlParameter(); 
      paramShipmentId.ParameterName = "shipment_id"; 
      paramShipmentId.Direction = ParameterDirection.Input; 
      paramShipmentId.Value = shipmentId; 
      cmd.Parameters.Add(paramShipmentId); 

      SqlParameter paramReturn = new SqlParameter(); 
      paramReturn.ParameterName = "@return_value"; 
      paramReturn.Direction = ParameterDirection.ReturnValue; 
      cmd.Parameters.Add(paramReturn); 

      SqlDataAdapter adp = new SqlDataAdapter(cmd); 
      DataSet ds = new DataSet(); 
      adp.Fill(ds); 

      if ((int)paramReturn.Value < 0) 
      { 
       //TODO: Log Error here. 
       log.Error("Get Shipment Details Failed."); 
      } 

      foreach (DataRow row in ds.Tables[0].Rows) 
      { 
       App.Current.Dispatcher.Invoke((System.Action)delegate 
       { 
        Shipment s = GetShipment(shipmentId); 
        s.ShipmentDetails(
          row["bankContact"] as string, 
          row["bankContactTel"] as string, 
          (row["containerCount"] == DBNull.Value) ? 0 : (int)row["containerCount"], 
          (row["sentToSiteComp"] == DBNull.Value) ? 0 : (int)row["sentToSiteComp"], 
          (row["arrivedAtSiteComp"] == DBNull.Value) ? 0 : (int)row["arrivedAtSiteComp"],               
          (row["sentToPortComp"] == DBNull.Value) ? 0 : (int)row["sentToPortComp"], 
          (row["depostRecComp"] == DBNull.Value) ? 0 : (int)row["depostRecComp"] 
         ); 
       }); 
      } 
      IoC.Get<IEventAggregator>().PublishOnUIThread(new ShipmentDetailsLoaded()); 
      return true; 
     } 
     catch (Exception ex) 
     { 
      log.Error("Unable to get ShipmentsList.", ex); 
      return false; 
     } 
     finally 
     { 
      ApplicationRoleService.CloseConnection(dbCon); 
     } 
    } 

我怎麼可能去加入取消從主線程這種方法的能力嗎?

+0

您正在爲每個LoadDetails創建一個新線程?你不能使用thread.abort()嗎?或者你想取消存儲過程調用? – artm 2014-10-02 11:06:42

+0

如果是帶寬瓶頸,那麼最耗費資源的操作就是DataAdapter.Fill(你必須通過網讀取所有數據);使它異步,並讓它被取消請參閱http://stackoverflow.com/questions/2108917/sqldataadapter-fill-asynchronous-approach – 2014-10-02 11:07:29

+0

還有SqlCommand.Cancel – artm 2014-10-02 11:09:20

回答

2

沒有可靠和安全的方法來強制取消.NET代碼中的任何後臺操作,除非在單獨的進程中運行該操作並殺死進程(這不是通用解決方案)。特別是,如果該操作目前正在運行本機代碼。

,你可以在這裏做的最好的選擇是:

  • 分割成數據塊的巨量;
  • 跟隨在你的代碼優雅消除圖案(見thisthis
  • 關於當前加載操作的結果給忘了,如果用戶按下「取消」按鈕(或做類似的東西,像離開當前記錄和定位下一個)。

我不會依靠SqlCommand.CancelThread.Abort也不是一個選項。

+0

您可否詳細說明爲什麼'Thread.Abort'和'SqlCommand.Cancel'是糟糕的選擇? – 2014-10-02 12:25:20

+0

關於'Thread.Abort':http://stackoverflow.com/questions/1559255/whats-wrong-with-using-thread-abort關於'SqlCommand.Cancel':正如它在文檔中所說的,'Cancel'只是*嘗試* 取消。這種嘗試*可能會成功(並且可能不會,並且有客觀的原因)。此外,無法保證,「取消」將在某個時間結束,符合您的要求。 – Dennis 2014-10-02 12:30:44