Odd behavior when selecting customer code in different way (Customization)

SOLVED

Hi All,

I am doing customization  on few standard Sage 200 forms, and I found an odd behavior when selecting customer code in different way.

For example, on Sales Ledger>New Invoice, we can select customer code in 3 methods: 

1. click dropdown and select the customer code.

2. type in customer code and tab away

3. type in customer code and click outside of the customer code area (to be exact CustomerInvoiceLookup field.)

My customization works like this:

once user select customer code, I capture the event with CustomerSelected(), check if the exchange rate has expired, and let user decide what to do next.

If user click "Yes", then proceed. This is not a problem.

If user click "No", then I will close the form by calling closeButton.performClick(). It work well if I use method 1. But for methods 2 and 3, it did not work.

Then I monitor the standard event:

Using method 1, these are the event triggered.

Using method 2 and 3, these are the event triggered

All methods have CustomerSelected event but only method 1 works ok. I have used CustomerChanged and Leave, but it still the same. Anyone knows why? Thank you.

  • 0

    The short answer to this is : don't use closeButton.PerformClick(). Do this instead:

    ((Sage.MMS.BaseForm)_form.UnderlyingControl).Close();

    The long and boring answer is that the PerformClick() method (which is a method of the standard System.Windows.Forms.Form.Button) first calls an internal method, ValidateActiveControl, and will only continue and perform the Click action if that method returns true. Because the CustomerInvoiceLookup (which is made up of three PopupListTexteBoxes) won't have completed its validation by this point if you've entered text and tabbed/clicked off then this ValidateActiveControl will return false and the PerformClick method won't do anything.

  • 0 in reply to Chris Burke

    Hi Chris, thank you. it works, I come across CloseIgnoringSave() and use it as well.

    salesInvoiceForm = (Sage.MMS.BaseForm)_form.UnderlyingControl;
    salesInvoiceForm.CloseIgnoringSave();

  • 0 in reply to murni

    No - don't use CloseIgnoringSave(), there's a problem with it.  Whenever you open a form in Sage 200 an entry gets made in the SYSActiveLock table, and the entry is removed when the form is closed. This is to enable feature-level locking; for example, you won't be able to open the Sales Ledger Settings form if certain other forms are open.  CloseIgnoringSave doesn't remove the entry from SYSActiveLock and you'll end up with orphaned locks.

    Instead, add a handler to form.DataAbandon, and in the handler set the IsDirty flag on the DataAbandonEventArgs to false. Then just call the form Close() method.

  • 0 in reply to Chris Burke

    Hi Chris,

    this is by DataAbandon handler

    private void _form_DataAbandon(Sage.Common.UI.DataAbandonEventArgs e)
    {
        e.IsDirty = false;
    }

    and in my CustomerSelected, I am using ((Sage.MMS.BaseForm)_form.UnderlyingControl).Close()

    private void CustomerInvoiceLookup_CustomerSelected(object sender, EventArgs e)
            {
                CustomerInvoiceLookup cil = (CustomerInvoiceLookup)sender;
                try
                {
                    if (Convert.ToInt32(cil.Customer.SLCustomerAccount) != 0)
                    {
                        if (cil.Customer.CustomerAccount.ExchangeRateType == Sage.Accounting.EnumExchangeRateType.ExchangeRatePeriod
                        && cil.Customer.CustomerAccount.Currency.PeriodExchangeRatesToBase.First != null)
                        {
                            //validate if the exchange rate already expired and give warning to user
                            DialogResult ds = FXRateValidate.Business.BlockWarning.display(cil.Customer.CustomerAccount.Currency.PeriodExchangeRatesToBase, 
                                cil.Customer.CustomerAccount.Currency.Name);
    
                            if (ds == DialogResult.No)
                            {   //Close the current form
                                _form.Abandon(false);
                                ((Sage.MMS.BaseForm)_form.UnderlyingControl).Close()
                            }
                        }
                    }
                }
                catch(Exception ex)
                {
                    Logger.WriteLog("SalesInvoiceForm="+ex.ToString()+";");
                }
            }

    but the earlier problem happen again. When using method 2 & 3 it did not close the form. Is my code correct?

  • +1 in reply to murni
    verified answer

    Yeah, there *is* something weird going on with the CustomerInvoiceLookup control - it's to do with the event handlers of the three internal PopupListTextBoxes.  

    Frankly, life is too short to try and make the control behave. If I were writing this then I'd go back to the CloseIgnoringSave but make sure the locks are disposed.  Like this:

    private void CloseForm()
    {
        var unLockBase = GetUnlockBaseMethod(_form.UnderlyingControl.GetType());
        unLockBase.Invoke(_form.UnderlyingControl, null);
        ((Sage.Accounting.Common.Forms.BaseForm)_form.UnderlyingControl).CloseIgnoringSave();
                           
    }
    
    private MethodInfo GetUnlockBaseMethod(Type fType)
    {
        if (fType == typeof(object))
            return null;
        MethodInfo mi = fType.GetMethod("UnlockBase", 
        BindingFlags.Instance | BindingFlags.NonPublic);
        if (mi == null)
        {
            mi = GetUnlockBaseMethod(fType.BaseType);
        }
        return mi;
    }

    Then just call that custom CloseForm() method.

  • 0 in reply to Chris Burke

    Thank you Chris, I will take this as the answer

  • 0

    A couple of extra points:

    1. Rather than closing the form, it would be easier to follow the same pattern as Sage does for an account on hold: just clear the customerInvoiceLookup.  But I guess the spec says "Close the form"!

    2. Don't forget that the form can be launched with the customer preselected (eg. from a workspace or desktop list) in which case the CustomerSelected event doesn't fire.

    Good luck!

  • 0 in reply to Geoff Turner

    Hi Geoff, yes I got problem on point 2- I cannot catch the preselected customer on screen. Unable to monitor event as well to see which event are triggered. Any tips on how to catch it once customer is preselected?

  • 0 in reply to murni

    Add a handler for the form Shown event (you'll have to cast form.UnderlyingObject), and in the handler do this:

    private void MyTestForm_Shown(object sender, EventArgs e)
    {
        if(customerInvoiceLookup.Customer != null && 
            !customerInvoiceLookup.Customer.PrimaryKey.IsNull)
        {
            //do stuff
        }
    }

  • 0 in reply to Chris Burke

    Thank you Chris. That works!