Using DBGrid in Unbound Mode

This sample was contributed by Adrian Roman.

It took me some time to notice all this, and because I couldn't find anywhere documentation about DBGrid unbound programming in VC++ (only in VB), I think that will be nice to share my observations with others.

First, even documentation says that it accepts (almost) any type of Variant as bookmark, it seems that it is not true. DaoRecordsets have SAFEARRAY as bookmarks (GetBookmark returns Variant which contains VT_ARRAY | VT_UI1), and did not work with DBGrid (the grid simply converts the variant to VT_BSTR).

It may work with VT_I4, or something like this, but because somewhere it says that strings are the best, I used them. Of course, I converted the bookmarks to strings and back.

SchedQ is a dynaset (CDaoRecordset) resulted from a query.

If you find any bugs or have some ideas, please share your findings with me.

And, I almost forgotten! IMPORTANT! If you generate RowBuffer class from OCX's type library, modify the constructor that gets LPDISPACH as parameter to call base class constructor with the second one setted to FALSE (it is implicitly TRUE). Or else, the whole thing will crash when RowBuffer object gets destroyed.

Some supplementary tips: use BeforeColUpdate and KeyPress events to validate a field and, respectively, to filter key input.

Please don't send me e-mails with questions about using it in bound mode. Just add on the dialog the Microsoft Remote Data Control before inserting the dbgrid, and play a little with properties. You'll figure out how to use it.

For those who want to modify columns at run-time: The generated GetColumns() member function of dbgrid's class is really a GetColumn function (returns a LPDISPATCH to a single column - so you can use this LPDISPATCH to construct Column objects, not Columns). If you want to obtain the LPDISPATCH to Columns collection, rename it as GetColumn, and rewrite GetColumns like this one:

LPDISPATCH CMsDgridCtrl::GetColumns()
{
   LPDISPATCH result;
   InvokeHelper(0x8,DISPATCH_PROPERTYGET,VT_DISPATCH,
                (void*)&result,NULL,NULL);
   return result;
}

You can use the returned LPDISPATCH to construct the Columns object.

Now, the code for feeding the grid with data, deletind records, and obtaining data back when writes occur:

void CMyView::OnUnboundReadDataDbgridMy(LPDISPATCH RowBuf,
                                        VARIANT FAR* StartLocation,
                                        BOOL ReadPriorRows)

{
   // TODO: Add your control notification handler code here
   RowBuffer buf(RowBuf);
   VARIANT varbok;
   varbok.vt=VT_ARRAY | VT_UI1;
   long Row,RowsFetched;
   VARIANT var;
   RowsFetched=0;
   if(StartLocation->vt==VT_NULL){
      if(ReadPriorRows){
         try{
            SchedQ->MoveLast();
         }catch(CDaoException* e){
            e->Delete();
         }
      }else{
         try{
            SchedQ->MoveFirst();
         }catch(CDaoException* e){
            e->Delete();
         }
      }
   }else{
      // Find the position to start reading based on the
      // StartLocation bookmark and ReadPriorRows parameter
      try{
         VectorFromBstr(StartLocation->bstrVal,&varbok.parray);
         SchedQ->SetBookmark(COleVariant(varbok));
         if(ReadPriorRows)SchedQ->MovePrev();
         else SchedQ->MoveNext();
      }catch(CDaoException* e){
         e->Delete();
      }
   }
   // Transfer data from our data set array to the RowBuf
   // object which DBGrid uses to display the data
   for(Row = 0; Row<buf.GetRowCount() ;Row++){
      if(SchedQ->IsEOF() || SchedQ->IsBOF())break;
      var.vt=VT_I4;
      var.lVal=SchedQ->m_WorkCodeID;
      if(buf.GetColumnCount()>0)buf.SetValue(Row, 0,var);
      COleVariant olvi(SchedQ->m_TimeIn);
      var=*((LPVARIANT)olvi);
      if(buf.GetColumnCount()>1)buf.SetValue(Row, 1,var);
      COleVariant olvo(SchedQ->m_TimeOut);
      var=*((LPVARIANT)olvo);
      if(buf.GetColumnCount()>2)buf.SetValue(Row, 2,var);
      // Set bookmark using CurRow which is also our
      // array index
      var.vt=VT_BSTR;
      BstrFromVector(((LPVARIANT)SchedQ->GetBookmark())->
                     parray,&var.bstrVal);
      buf.SetBookmark(Row,var);
      RowsFetched++;
      if(ReadPriorRows)SchedQ->MovePrev();
      else SchedQ->MoveNext();
   }
   buf.SetRowCount(RowsFetched);
}


void CMyView::OnUnboundWriteDataDbgridMy(LPDISPATCH RowBuf,
                                         VARIANT FAR* WriteLocation)
{
   // TODO: Add your control notification handler code here
   RowBuffer buf(RowBuf);
   VARIANT varbok;
   varbok.vt=VT_ARRAY | VT_UI1;
   COleVariant var;
   CString str;
   try{
      VectorFromBstr(WriteLocation->bstrVal,&varbok.parray);
      SchedQ->SetBookmark(COleVariant(varbok));
   }catch(CDaoException* e){
      e->Delete();
      buf.SetRowCount(0);
      return;
   }

   //****************************************************
   //Here was a portion of code that validated the record
   //****************************************************
   // Only columns that have been changed will be updated.
   // Otherwise, the value will be set to NULL
   try{
      SchedQ->Edit();
   }
   catch(CDaoException* e){
      e->Delete();
      buf.SetRowCount(0);
      return;
   } 
   if(buf.GetValue(0L, 0).vt!=VT_NULL){
      var=buf.GetValue(0, 0);
      str=CString(var.bstrVal);
      SchedQ->m_WorkCodeID=atol(str);
   }
   if(buf.GetValue(0L, 1).vt!=VT_NULL){
      var=buf.GetValue(0, 1);
      str=CString(var.bstrVal);
      SchedQ->m_TimeIn.ParseDateTime(str);
   }
   if(buf.GetValue(0L, 2).vt!=VT_NULL){
      var=buf.GetValue(0, 2);
      str=CString(var.bstrVal);
      SchedQ->m_TimeOut.ParseDateTime(str);
   }
   try{
      SchedQ->Update();
   }catch(CDaoException *e){
      SchedQ->CancelUpdate();
      e->Delete();
      buf.SetRowCount(0);
   }
}


void CMyView::OnUnboundAddDataDbgridMy(LPDISPATCH RowBuf,
                                       VARIANT FAR* NewRowBookmark) 
{
   // TODO: Add your control notification handler code here
   RowBuffer buf(RowBuf);
   COleVariant var;
   CString str;
   NewRowBookmark->vt=VT_NULL;

   //****************************************************
   //Here was a portion of code that validated the record
   //****************************************************
   try{
      SchedQ->AddNew();
      SchedQ->Update();
      SchedQ->SetBookmark(SchedQ->GetLastModifiedBookmark());
      SchedQ->Edit();
   }catch(CDaoException* e){
      e->Delete();
      buf.SetRowCount(0);
      return;
   } 
   SchedQ->m_EmployeeID=m_pSet->m_EmployeeID;
   try{
      if(buf.GetValue(0L, 0).vt!=VT_NULL){ 
         var=buf.GetValue(0, 0);
      }else{
         var.vt=VT_I4; 
         var.lVal=0;
         Column col(m_SchedGrid.GetColumns(var));
         var=col.GetDefaultValue();
      }
      str=(char*)_bstr_t(var.bstrVal);
      SchedQ->m_WorkCodeID=atol(str);
      if(buf.GetValue(0L, 1).vt!=VT_NULL){
         var=buf.GetValue(0, 1);
      }else{
         var.vt=VT_I4; 
         var.lVal=1;
         Column col(m_SchedGrid.GetColumns(var));
         var=col.GetDefaultValue();
      }
      str=(char*)_bstr_t(var.bstrVal);
      SchedQ->m_TimeIn.ParseDateTime(str);
      if(buf.GetValue(0L, 2).vt!=VT_NULL){
         var=buf.GetValue(0, 2);
      }else{
         var.vt=VT_I4; 
         var.lVal=2;
         Column col(m_SchedGrid.GetColumns(var));
         var=col.GetDefaultValue();
      }
      str=(char*)_bstr_t(var.bstrVal);
      SchedQ->m_TimeOut.ParseDateTime(str);
      var.vt=VT_I4;
      SchedQ->Update();
   }catch(CDaoException *e){
      e->Delete();
      SchedQ->CancelUpdate();
      SchedQ->Delete();
      buf.SetRowCount(0);
   }
   NewRowBookmark->vt=VT_BSTR;
   BstrFromVector(((LPVARIANT)SchedQ->GetBookmark())->parray,
                   &(NewRowBookmark->bstrVal));
}


void CMyView::OnUnboundDeleteRowDbgridMy(VARIANT FAR* Bookmark)
{
   // TODO: Add your control notification handler code here
   VARIANT varbok;
   varbok.vt=VT_ARRAY | VT_UI1;
   VectorFromBstr(Bookmark->bstrVal,&varbok.parray);
   try{
      SchedQ->SetBookmark(COleVariant(varbok));
      SchedQ->Delete();
   }catch(CDaoException* e){
      Bookmark->vt=VT_NULL;
      e->Delete();
   }
}


Comments

  • Columns Class

    Posted by Sreenivas on 03/19/2004 01:12am

    Dear Sir,
        Your code helps me a lot.But one problem I am facing is I able to get collection object as you said,All the functions are working fine except SetAdd method in "Columns" class.When I try to call that function it is giving error "Invalid number of parameters".The Code snippet is follows :
    
    LPDISPATCH pDisp = m_myGrid.GetColumns();
    Columns pColumns(pDisp);
    pColumns.SetAdd(0);
    
    I look forward to get a solution from you.
    
    Thanks and Regards,
    Sreenivas

    Reply
  • Plse , send me full sorce code

    Posted by Legacy on 02/23/2004 12:00am

    Originally posted by: Rajan Kapadia

    please send me full source code of your application.

    Reply
  • can u send full source code for this

    Posted by Legacy on 02/21/2004 12:00am

    Originally posted by: selva

    can u send full source code to my mail id.

    Reply
  • DBGrid

    Posted by Legacy on 02/13/2004 12:00am

    Originally posted by: Vladimir

    Please send me the source code

    Thanks
    Vladimir

    Reply
  • thank you

    Posted by Legacy on 01/31/2004 12:00am

    Originally posted by: omid

    please send me full source of this project
    thank you
    bye

    Reply
  • Please send me full code for this project,please......

    Posted by Legacy on 01/28/2004 12:00am

    Originally posted by: andreas ginting

    please sent to my email. I really want to program in VC but I don't have enough references and sample. so please help me


    best regards

    andreas ginting, jakarta indonesia

    Reply
  • Please send me full code for this project,please......

    Posted by Legacy on 01/28/2004 12:00am

    Originally posted by: andreas ginting

    please sent to my email. I really want to program in VC but I don't have enough references and sample. so please help me


    best regards

    andreas ginting, jakarta indonesia

    Reply
  • DataAcquisition

    Posted by Legacy on 01/17/2004 12:00am

    Originally posted by: SG Prasad

    Can Anyone pls send the code in Vb for Data Acquisition and transfer from PLC(programmable logic controller) to Database 
    

    • henhao

      Posted by luyi9798 on 04/03/2005 01:29am

      henhao

      Reply
    Reply
  • How to Add DBGrid functionalities in VC++ Programs

    Posted by Legacy on 10/13/2003 12:00am

    Originally posted by: Nitin Verma

    i will be goin' thru ur code at a later time...appeals good

    Reply
  • The source please for final proyect's school

    Posted by Legacy on 09/16/2003 12:00am

    Originally posted by: Neftaly

    Hi,
    Please, can you send me the source code.
    It's very important for me

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • On-demand Event Event Date: September 10, 2014 Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild." This loop of continuous delivery and continuous feedback is how the best mobile …

  • Packaged application development teams frequently operate with limited testing environments due to time and labor constraints. By virtualizing the entire application stack, packaged application development teams can deliver business results faster, at higher quality, and with lower risk.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds