Skip to Content

UPDATE: The code posted below is not the best way to accomplish this task. Instead use the OpenForm method in the Application object. (Pedro Magueija points this out in the comments section below.)

My add-on needed the ability to programmatically open a related form just the way the LinkedButton object does. In my case, my users will be editing a Sales Order form, and they need to pop open a related Production Order whose key resides in the system-defined matrix object holding the order’s lines–not in any control I have added.

I searched for ways to solve this problem, and what I came up with is to create some hidden objects on the form: a LinkedButton connected to an EditText connected to a DataSource. Although I have only tested with Production Orders, I believe I can open any system form that can be opened by a LinkedButton.

I’m posting my code here in case (a) it helps anyone, or (b) someone can chime in with “hey, you dummy! There’s a built-in function you can call directly!” I suspect such a function exists, but SAP’s SDK documentation leaves a lot to be desired.

Here is the code for my solution. I use it by calling CreateLink() when handling the et_FORM_LOAD after-event, then calling OpenLink() when handling et_CLICK on the matrix column containing the key to a related Production Order.

Please comment if this helps you, or if you know of a better way!


using SAPbouiCOM;
namespace Product {
  public class SapDocumentLinker {
    //--------------------------------------
    #region Public Methods
    //--------------------------------------
    /// <summary>
    /// Create form objects to support linking to the window of a particular SAP object
    /// </summary>
    /// <param name="form">Form the user is editing</param>
    /// <param name="linkId">8-character unique link ID string</param>
    /// <param name="linkedSapObject">Object type for the link</param>
    /// <remarks>
    /// Call this method when handling the BoEventTypes.et_FORM_LOAD after-event of the form the user
    /// will be linking FROM. An exception will result if the linkId clashes with the ID of any
    /// other element on the form. Only the first 8 characters of linkId will be used, with the
    /// prefixes "Ds", "Et", and "Lb".
    /// </remarks>
    static public void CreateLink(
      SAPbouiCOM.Form form,
      string linkId,
      BoLinkedObject linkedSapObject
    ) {
      // Add a DataSource to support an EditText field
      var dsId = MakeId( DATA_SOURCE_PREFIX, linkId );
      var userDs = form.DataSources.UserDataSources;
      userDs.Add( dsId, BoDataType.dt_SHORT_TEXT );
      // Add EditText to store the record key of the object we want to link to
      var etId = MakeId( EDIT_TEXT_PREFIX, linkId );
      var etItem = form.Items.Add( etId, BoFormItemTypes.it_EDIT );
      var etSpec = etItem.Specific as EditText;
      etItem.AffectsFormMode = false;
      etItem.Left = -100;
      etItem.Top = -100;
      etItem.Width = 10;
      etItem.Height = 10;
      if ( etSpec != null ) {
        etSpec.DataBind.SetBound( true, "", dsId );
        etSpec.Value = "";
      }
      // Add LinkedButton to the EditText, specifying the type of object we link to
      var lbId = MakeId( LINKED_BUTTON_PREFIX, linkId );
      var lbItem = form.Items.Add( lbId, BoFormItemTypes.it_LINKED_BUTTON );
      var lbSpec = lbItem.Specific as LinkedButton;
      if ( lbSpec != null ) {
        lbItem.LinkTo = etId;
        lbSpec.LinkedObject = linkedSapObject;
      }
    }
    /// <summary>
    /// Open the edit window of the record specified by recordKey and
    /// the type specified in SapDocumentLinker.CreateLink()
    /// </summary>
    /// <param name="form">Form the user is editing</param>
    /// <param name="linkId">8-character unique link ID string</param>
    /// <param name="recordKey">Key of the record to open</param>
    /// <remarks>
    /// Call this method whenever you need to pop open the window of an associated record.
    /// An exception will result if the form instance or linkId don't agree with the ones
    /// sent to SapDocumentLinker.CreateLink(), and you should check that the recordKey is
    /// valid before calling OpenLink(): if it is not valid, the window will open anyway
    /// </remarks>
    static public void OpenLink(
      Form form,
      string linkId,
      string recordKey
    ) {
      // Copy record key into the EditText field
      var etId = MakeId( EDIT_TEXT_PREFIX, linkId );
      var etSpec = form.Items.Item( etId ).Specific as EditText;
      etSpec.Value = recordKey;
      // Simulate a click on the associated LinkButton so SAP will open the required form
      var lbId = MakeId( LINKED_BUTTON_PREFIX, linkId );
      var lbItem = form.Items.Item( lbId );
      lbItem?.Click( BoCellClickType.ct_Regular );
    }
    #endregion Public Methods
    //--------------------------------------
    #region Non-Public Methods
    //--------------------------------------
    static private string MakeId( string prefix, string suffix ) {
      var id = $"{prefix}{suffix}".Trim();
      if ( id.Length > MAX_ID_LENGTH ) {
        id = id.Substring( 0, MAX_ID_LENGTH );
      }
      return id;
    }
    #endregion Non-Public Methods
    //--------------------------------------
    #region Fields
    //--------------------------------------
    private const int MAX_ID_LENGTH = 10;
    private const string DATA_SOURCE_PREFIX = "Ds";
    private const string EDIT_TEXT_PREFIX = "Et";
    private const string LINKED_BUTTON_PREFIX = "Lb";
    #endregion Fields
  }
}



To report this post you need to login first.

3 Comments

You must be Logged on to comment or reply to a post.

  1. Charles Jenkins Post author

    I have no idea why this web page presents my code with no whitespace. This class is written in C# 6.0. If you are using an earlier version, the line to format the id will be something like:

    var id = string.Format( "{0}{1}", prefix, suffix ).Trim();

    (0) 
    1. Pedro Magueija

      Hi Charles,

      Thank you for your code, but indeed there is a function for that in the application object:

      Public Function OpenForm( _
        ByVal sysObjectType As BoFormObjectEnum, _
        ByVal bstrUDOObjectType As String, _
        ByVal bstrObjectKey As String _
      ) As Form

      You can find more information on the SDK Help Center file.

      Cheers.


      Pedro Magueija

      LinkedIn Logo View Pedro Magueija’s profile on LinkedIn
      Follow @pedromagueija on Twitter

      If this answer was helpful or correct consider marking it as such.

      (1) 

Leave a Reply