2015-06-15 30 views
0

我有一個函數來更新從答案的幫助作出了cxGrid到Loop through records on a cxgrid and update a field/column更新外地代理奇怪

但有時行事有點怪。如果我用cxGrid打開表單並單擊沒有做任何事情的欄目標題,記錄就會更新。但是如果'selectorbar'從頂部移開,標記的記錄不會更新。 我相信這是一個需要改變的財產,但是哪一個。

變量fSelected在FormShow中設置爲False,並且它也是用戶可以取消選擇記錄。

procedure TfrmContactsSelect.colContactSelectedHeaderClick(Sender: TObject); 
var 
    i: Integer; 
    Index: Integer; 
    BookMark : TBookMark; 
    Contact: variant; 
begin 
    if fMulti = True then 
    begin 
    Screen.Cursor := crHourGlass; 
    fSelected := not fSelected; 
     BookMark := qryContacts.GetBookmark; 
     qryContacts.DisableControls; 
     try 
     for i := 0 to grdContactsView1.DataController.FilteredRecordCount - 1 do 
      begin 
      Index := grdContactsView1.DataController.FilteredRecordIndex[i]; 
      Contact := grdContactsView1.DataController.Values[Index, 4]; 
      if grdContactsView1.DataController.LocateByKey(Contact) then 
       begin 
       qryContacts.Edit; 
       qryContacts.FieldByName('fldcontact_selected').AsBoolean := fSelected; 
       qryContacts.Post; 
       end; 
      end; 
     finally 
     qryContacts.EnableControls; 
     qryContacts.GotoBookmark(BookMark); 
     qryContacts.FreeBookmark(BookMark); 
     end; 
     Screen.Cursor := crDefault; 
    end; 
end; 

德爾福XE7,DevExpress的14.2.2,UniDAC 5.5.12 DB訪問

評論: 我已經結束了與基於來自MartynA

procedure TfrmContactsSelect.colContactSelectedHeaderClick(Sender: TObject); 
var 
    i: Integer; 
    Index: Integer; 
    MarkedRecord: variant; 
    CurrentRecord: variant; 
begin 
    if fMulti = True then 
    begin 
     Screen.Cursor := crHourGlass; 
     fSelected := not fSelected; 

     Index := grdContactsView1.DataController.FocusedRecordIndex; 
     MarkedRecord := grdContactsView1.DataController.Values[Index, colContactGuid.ID]; 

     try 
     for i := 0 to grdContactsView1.DataController.FilteredRecordCount - 1 do 
      begin 
      Index := grdContactsView1.DataController.FilteredRecordIndex[i]; 
      CurrentRecord := grdContactsView1.DataController.Values[Index, colContactGuid.ID]; 
      if grdContactsView1.DataController.LocateByKey(CurrentRecord) then 
       begin 
       grdContactsView1.DataController.Edit; 
       grdContactsView1.DataController.SetEditValue(colContactSelected.ID, fSelected, evsText); 
       grdContactsView1.DataController.Post; 
       end; 
      end; 
     finally 
     grdContactsView1.DataController.LocateByKey(MarkedRecord); 
     end; 

     Screen.Cursor := crDefault; 
    end; 
end; 
的答案,輸入以下解決方案
+0

你使用的是什麼版本的DevExpress?你是否已經問DevExpress支持?他們通常也會很快響應 – Zam

+0

,你正在使用的是什麼版本的Delphi?如果它是「現代」的德爾福(高於2007年或2009年),那麼你不需要叫「FreeBookbark」。 – Zam

+0

其他建議,與DevExpress無關 - 「早退」 - 意思是:「如果不是fMulti則退出」; - 將使代碼更容易閱讀 – Zam

回答

1

我可以使用我在我的答案中發佈的示例項目來重現您的問題。

嘗試此操作:將TMemo添加到您的表單中,然後在'if grdContactsView1.DataController.LocateByKey(Contact)'塊中,將行唯一數據字段的值和選定數據字段值寫入備忘錄。

然後,當我選擇除頂行之外的某行時,我得到的是一行在備忘錄中列出兩次,既選擇了假和真,也沒有列出過濾器中的一行所有這些,我認爲這是你看到的行爲的原因。如果我然後將.Edit .. .Post行註釋掉,它會正確列出過濾器中的所有行。

因此,很明顯,在迭代了DBTableView的FilteredRecordIndex屬性的塊內部進行選擇字段更改是導致問題的原因。個人而言,我發現它通過數據庫感知控件修改代碼中的數據集行有點違背(因爲通常最終會與控件的數據庫意識發生衝突),但在這種情況下,它是直接通過cxGrid的DBTableView進行處理。

procedure TForm1.ProcessFilteredRecords; 
var 
    PrevV, 
    V : Variant; 
    i, 
    Index: Integer; 
    S : String; 
begin 

    // First, pick up a reference to the current record 
    // so that we can return to it afterwards 
    Index := cxGrid1DBTableView1.DataController.FocusedRecordIndex; 
    PrevV := cxGrid1DBTableView1.DataController.Values[Index, 0]; 

    try 
    for i := 0 to cxGrid1DBTableView1.DataController.FilteredRecordCount - 1 do begin 
     Index := cxGrid1DBTableView1.DataController.FilteredRecordIndex[i]; 
     V := cxGrid1DBTableView1.DataController.Values[Index, 0]; 
     if cxGrid1DBTableView1.DataController.LocateByKey(V) then begin 
     cxGrid1DBTableView1.DataController.Edit; 
     // 2 is the index of my Selected column in the grid 
     if cxGrid1DBTableView1.DataController.SetEditValue(2, True, evsText) then 
      Caption := 'OK' 
     else 
      Caption := 'Failed'; 
     cxGrid1DBTableView1.DataController.Post; 
     end; 
    end; 
    finally 
    if cxGrid1DBTableView1.DataController.LocateByKey(PrevV) then 
     Caption := 'OK' 
    else 
     Caption := 'Failed'; 
    end; 
end; 

另一種方式來避免此問題是改變兩個步驟選定的狀態:

  • 迭代的FilteredRecordIndex建行列表的改變 - 在你的情況下,這將是一個列表的指令

  • 然後,迭代行列表並更新它們的Selected狀態。

代碼:

procedure TForm1.ProcessFilteredRecords; 
var 
    V : Variant; 
    i, 
    Index: Integer; 
    BM : TBookMark; 
    S : String; 
    TL : TStringList; 
begin 
    Memo1.Lines.Clear; 
    TL := TStringList.Create; 
    try 
    for i := 0 to cxGrid1DBTableView1.DataController.FilteredRecordCount - 1 do begin 
     Index := cxGrid1DBTableView1.DataController.FilteredRecordIndex[i]; 
     V := cxGrid1DBTableView1.DataController.Values[Index, 0]; 

     if cxGrid1DBTableView1.DataController.LocateByKey(V) then begin 
     if CDS1.FieldByName('Selected').AsBoolean then 
      S := 'True' 
     else 
      S := 'False'; 
     S := CDS1.FieldByName('Name').AsString + ' ' + S; 
     Memo1.Lines.Add(S); 
     TL.Add(CDS1.FieldByName('Guid').AsString); 
     end; 
    end; 

    try 
     BM := CDS1.GetBookMark; 
     CDS1.DisableControls; 
     for i := 0 to TL.Count - 1 do begin 
     if CDS1.Locate('guid', TL[i], []) then begin 
      CDS1.Edit; 
      CDS1.FieldByName('Selected').AsBoolean := True; 
      CDS1.Post; 
     end 
     end; 
    finally 
     CDS1.EnableControls; 
     CDS1.GotoBookmark(BM); 
     CDS1.FreeBookmark(BM); 
    end; 
    finally 
    TL.Free; 
    end; 
end; 

和你一樣,我期待的是改變cxGrid的財產或兩個可能避免沒有任何代碼的問題,但我一直沒能找到任何這確實。

+0

我認爲我找到了一些東西。如果我刪除了書籤的使用,那麼它就像人們期望的那樣行事。在選擇更新後跳到網格中的最後一條記錄,但這不是問題(或者我可以忍受並且用戶需要這樣做) – OZ8HP

+0

剛剛發佈了一個更新,顯示如何執行所需操作僅使用cxGrid代碼。 – MartynA

+0

我已經把我的解決方案作爲我的問題的註釋(我無法在其他地方添加代碼,只要我能看到) - 它基於最後一個答案。我只做了小的調整(使用列的ID,所以我不必擔心是否更改列的順序) – OZ8HP