views:

120

answers:

2

I have a webpage that needs to selectively show or hide a substantial number of controls. Each control's visibility is determined based on which of 3 conditions are true.

So, for example, given the conditions A, B, and C;

  • Control1 needs to be visible only when A and B are true and C is false.
  • Control2 needs to be visible only when B and C are true and A is false.
  • Control3 needs to be visible only when A and C are true and it doesn't care what B is.
  • and so on...

If each control looked at every condition, the control logic would be ugly, but doable.

If A Then
    If B Then
        If C Then

        Else

        End If
    Else
        If C Then

        Else

        End If
    End If
Else
    If B Then
        If C Then

        Else

        End If
    Else
        If C Then

        Else

        End If
    End If
End If

But unfortunately, when you mix in the fact that many controls only care about 1 or 2 of the 3 conditions, the code starts to grow into a maintenance nightmare. Here are all 26 of the possible conditions:

A   False   B   Any     C   Any  
A   True    B   Any     C   Any  
A   Any     B   Any     C   False
A   False   B   Any     C   False
A   True    B   Any     C   False
A   Any     B   Any     C   True 
A   False   B   Any     C   True 
A   True    B   Any     C   True 
A   Any     B   False   C   Any  
A   False   B   False   C   Any  
A   True    B   False   C   Any  
A   Any     B   False   C   False
A   False   B   False   C   False
A   True    B   False   C   False
A   Any     B   False   C   True 
A   False   B   False   C   True 
A   True    B   False   C   True 
A   Any     B   True    C   Any  
A   False   B   True    C   Any  
A   True    B   True    C   Any  
A   Any     B   True    C   False
A   False   B   True    C   False
A   True    B   True    C   False
A   Any     B   True    C   True 
A   False   B   True    C   True 
A   True    B   True    C   True 

Is there a better pattern to handle checking for multiple conditions?

Edit: I had started going down the road that Marcelo Cantos suggested, but my A, B, and C conditions are quite long. So I made a helper function:

Dim isMatch = Function(A As Boolean?, B As Boolean?, C As Boolean?) As Boolean
        Return (Not A.HasValue OrElse A.Value = SomeLongConditionA) _
        AndAlso (Not B.HasValue OrElse B.Value = SomeLongConditionB) _
        AndAlso (Not C.HasValue OrElse C.Value = SomeLongConditionC)
    End Function

Control1.Visible = isMatch(True, True, False)
Control2.Visible = isMatch(False, True, True)
Control3.Visible = isMatch(True, Nothing, True)
+14  A: 
Control1.Visible = A And B And Not C
Control2.Visible = Not A And B And C
Control3.Visible = A And C
...

Note that this form looks like the description of the rules you provided. This is a good way to think about most problems: "How can I make the code look like my description of the problem?"

EDIT: If A, B and C represent long-winded expressions, you don't have to copy-paste those expressions onto every line, or write a helper function. Just pre-compute the values:

Dim A As Boolean = SomeLongConditionA
Dim B As Boolean = SomeLongConditionB
Dim C As Boolean = SomeLongConditionC

Control1.Visible = A And B And Not C
...

Also note that this will be much faster than the helper function, which saves on typing but still evaluates the conditions many times over.

Marcelo Cantos
+1. It doesn't need to be any more complicated than this. At least not if the OP has specified his requirements correctly...
Nailuj
Possible improvement: Line up the inputs with each other vertically. YMMV, though.
Christian Mann
@Christian: I originally did, but it gave a misleading impression, given that B was lining with C, and forcing variable names to line up looked weird, as there was no natural place for the single `And`.
Marcelo Cantos
If @adam0101 has 8 states, and a substantial (??) number of controls to deal with, you'll get a lot of duplication of the bitwise operations. @MainMa's example will be more readable, if you have more controls than state combinations. If you have more state combinations than controls, then this example is better.
Dave White
@Dave: If M and N are large, then MxN is going to be huge, no matter what. Besides, @MainMa's solution is structurally the same as mine and will thus exhibit exactly the same kind of growth in complexity. It just uses `if X then Y = True` instead of `Y = X`.
Marcelo Cantos
@Christian: One more thought just occurred to me. I vaguely remember that VB6 had a tendency to auto-trim excess whitespace, which made nice column layouts impossible. I don't know if VB.Net retains this mis-feature.
Marcelo Cantos
@Marcelo - I agree. I stated in my previous comments so that if someone stumbles upon this question they take the sizes of M and N into consideration when choosing which answer to follow.
Dave White
@Dave: You missed my point, which is that the sizes of M and N have absolutely no effect on which answer one should follow.
Marcelo Cantos
@Marcelo - We can agree to disagree. From a readability and ease of maintenance of view, I liked @MainMa's solution if there are only 8 states and some substantial (50?) number of controls as I felt it would be far more readable, easy to maintain, and less duplication than your solution. If you invert that though and say there are 50 combinations of state and 3 controls, you're answer is would be far more readable and easier to maintain.
Dave White
@Dave, there are more than 8 states because many controls only care about 1 or 2 of the 3 conditions.
adam0101
There are 26 possible states. (3^3)-1. See the edit to my question.
adam0101
@Dave: Sure, but I just cannot fathom your line of argument. My solution is only about 10 characters wider, regardless of the number of states, and four times shorter. How is 200 lines going to be more readable than 50?
Marcelo Cantos
@adam0101 - The any state throws a wrench in there doesn't it. :)
Dave White
@Dave: No it doesn't. `Control3` has an "Any" case. Also see my latest comment on the question.
Marcelo Cantos
+1  A: 

Wouldn't it be easier to group the conditions by control:

If A And B And Not C Then
    Control1.Visible = True
End If

If Not A And B And C Then
    Control2.Visible = True
End If

If A And C Then
    Control3.Visible = True
End If

Edit: or, in this particular case where you deal with boolean properties of controls, Marcelo Cantos answer provides even a shorter and easier to read way to do the same thing.

MainMa
I like this approach to this problem if he only has 3 states to worry about. If the number of states grow, this will become problematic.
Dave White
You have to be careful in-case you need to make sure that each control is set to False if their conditions are not met. Although this is not made clear from the question, I would think in most cases it is implied.
Akusete
@Dave White: agree. If the number of states grow, and there are no similarities, than yes, both my and Marcelo Cantos approaches will become problematic. But I don't think there is something to do with this.
MainMa
@Akusete: oh, yes, you're right. So obviously Marcelo Cantos answer IS more readable, since in mine, it would require to add the Else branch, making the code two times longer.
MainMa
Why a downvote? What is wrong with the answer?
MainMa
@MainMa actually, an else branch isn't necessary if you take an aggressively false stance by default. I do this with buttons in our ASP.NET app that are enabled or disabled based on user credentials. All controls are disabled by default, then selectively turned on if the user is allowed to use them and the page is in a state where they are valid to use.
CodexArcanum
EDIT: Ack, should probably make clear that this only works because ASP.NET reloads the page each time and I don't store enabled state in the viewstate. Essentially the whole page is a big async loop.
CodexArcanum