Search code examples
c++user-interfacemfclogic

Handling Complex Rules in GUI applications (C++ or C#)


Im working on a dialog box in which several rules must be satisfied before the OK button is enabled.

Currently any action on the page such as entering data or selecting an item from a drop down list (amongst other things) calls a single function called ProcessEvent() - this function handles all logic and either enables or disables the OK button.

My problem is I finding it difficult making the rules concise and understandable.

Some of the rules can be negated by another action on the dialog and I have now ended up with if else statements all over the place or which are difficult to read and follow & extend.

The code below is a simplification of the problem but demonstrates it well. How do I handle this problem better (If its Possible)

bool CWorkstation::ProcessEvent(void)
    {   
        UpdateData();

        CharCount = GetDlgItemInt(IDC_CharCount, NULL, FALSE); //get latest

        if ( IsDlgButtonChecked(IDC_USEDBNAME))
            {   
                if (!IsDlgButtonChecked(IDC_MAXDBNAME))
                    {
                        EnableNext(TRUE);
                    }
            }

        if (IsDlgButtonChecked(IDC_MAXDBNAME) && CharCount)
            {                   
                if (IsDlgButtonChecked(IDC_USEXMLNAME))
                    {
                        if ( PrefixName.IsEmpty() ) 
                            {
                                EnableNext(FALSE);
                            }
                        else
                            {
                                EnableNext(TRUE);
                            }
            }



            }   


        if (IsDlgButtonChecked(IDC_USEXMLNAME) && PrefixName.GetLength() > 1)
            {
                EnableNext(TRUE);
            }



        if  ( IsDlgButtonChecked(IDC_WSAUTONAME) || IsDlgButtonChecked(IDC_RENAMEIFDUP))
            {

            // TRACE("IDC_WSAUTONAME is Checked\n");

            if ( IsDlgButtonChecked(IDC_USEXMLNAME) && PrefixName.GetLength() > 1 ) 

                {   


                if ( IsDlgButtonChecked(IDC_IDC_USESHORTNAME) ) 

                    {

                    EnableNext(TRUE);
                    }

                else if ( IsDlgButtonChecked(IDC_USELONGNAME) )

                    {

                    EnableNext(TRUE);

                    }

                else

                    {
                    EnableNext(FALSE);
                    }



                }


            if ( !IsDlgButtonChecked(IDC_USEPREFIX) )

                {


                if ( IsDlgButtonChecked(IDC_IDC_USESHORTNAME) ||  IsDlgButtonChecked(IDC_USELONGNAME) )

                    {
                    EnableNext(TRUE);
                    }

                }


            return false;


            }

        } 

Solution

  • I would split your if/else statements into multiple functions, and do an &= on the parameter you send to EnableNext. You should be calling EnableNext only once.

    So, for example:

    // in CWorkStation::ProcessEvent
    bool enableNext = true; // start with true
    
    enableNext &= Condition1(); // of course pick better names than Condition1
    enableNext &= Condition2(); // this is just for an example
    
    EnableNext(enableNext);
    

    Where Condition1() might be:

    bool Condition1()
    {
        return (IsDlgButtonChecked(IDC_USEDBNAME) 
             && !IsDlgButtonChecked(IDC_MAXDBNAME));
    }
    

    And so on.

    What's happening here is that the enableNext variable starts with true. Then, each &= you do means that if any of the ConditionX() functions returns false, enableNext will end up false. It will only be true at the end if ALL of the conditions are true.