Need advice for "Are You Sure" condition

Need advice for "Are You Sure" condition

Old forum URL: forums.lhotka.net/forums/t/2718.aspx


bgilbert posted on Tuesday, April 17, 2007

I would like a particular business object to ask for validation when a property is set to a specific value. In this case, I have a TimeStart property and a TimeEnd property. When creating a new object, the default for these properties is Now. However, saving the data with both values set to now would be highly unusual, so I'd want the class to ask for verification. I think this rule should be maintained by the class and not the UI.

One thought I had is to expose a boolean property called ZeroTimeAllowed. The default would be False. If the rule found that the time properties are the same and ZeroTimeAllowed is false, it would be a broken rule. The UI could then show a messagebox and then change the ZeroTimeAllowed to True if the response is Yes.

I know this is more of a generic OO question, but I'm looking for the best practice.

Thanks,
Barry

ajj3085 replied on Tuesday, April 17, 2007

Well you could create a rule that is just a warning, and have the UI check for any warnigns and display them before it calls save.  The UI wouldn't know anything about the rule or how its enforced, it would simply display them.

bgilbert replied on Tuesday, April 17, 2007

Andy,

Thanks for the response. I must've missed the severity property in my 2.1 docs. I think it helps, but I'm still not clear on how to use it at the UI level.

The result I'm looking for is that the UI displays a msgbox with an "Are you sure?" message in the form's Save button. I can have the UI look into the BrokenRulesCollection and look for Warnings, but I would still need to interpret the warning messages through a Select Case, show a Yes/No/Cancel messagebox. The problem is, how does the UI signal back to the business object that the user is, in fact, sure?

As an aside, Warning and Information broken rules don't seem to show up in the DataGridView the way they do with Errors.

Barry

DansDreams replied on Wednesday, April 18, 2007

I think the answer to your question lies in the understanding that the business layer should not know anything about the specifics that go on in the UI.  That is to say, the business object can't possibly be responsible for doing anything in the UI.

I think the broken rules method could be made to work, but you'd end up with some fragile link with the UI looking for some specific wording in a broken rule.

As an alternative, the business object could either raise an event indicating a "suspicious" value was selected, or have an additional property indicating the value is currently suspicious.  The UI could do whatever it wants with that information.

bgilbert replied on Wednesday, April 18, 2007

Thanks for your reply.
DansDreams:

I think the answer to your question lies in the understanding that the business layer should not know anything about the specifics that go on in the UI.  That is to say, the business object can't possibly be responsible for doing anything in the UI.

I certainly agree with this, which is what makes this a challenge.

DansDreams:

As an alternative, the business object could either raise an event indicating a "suspicious" value was selected, or have an additional property indicating the value is currently suspicious.  The UI could do whatever it wants with that information.



Yes, I could raise an event, throw an exception, or return a broken rule. The question remains: when the UI gets this message, displays a messagebox, a recieves a reply, how does it signal back to the business object that, the second time around, it should ignore the warning and not raise/throw again?

I'm convinced that the only tool I have is something like a ZeroTimeAllowed property.

mr_lasseter replied on Wednesday, April 18, 2007

I don't understand why you would want to add the complexity of a ZeroTimeAllowed proeprty.  In the UI you check if there are any brokenrules that are warnings (see my post above).  If there are you display the user a messagebox with the warnings and ask if they would like to continue with the save.  There is no need to raise any events or throw any exceptions. 

The way I see your problem,  it is a UI issue not a business object issue.  The business object should not care that there are warnings when saving the business object.  In my opinion, the warnings are there for the UI to do with what they want. 

ajj3085 replied on Wednesday, April 18, 2007

The BO doesn't do that; your UI, when save is clicked, checks the warnings and displays them and offers the user a chance to back out.  If they choose to back out, you simply do nothing.  If they do want to continue, then you simply call save on the BO.

bgilbert replied on Wednesday, April 18, 2007

Andy and mr_lassiter,

I see that now. One thing I think I'll need is to have my collection class expose a list of all warnings in its child objects. Does this make sense? Something like:

    Public Function WarningList() As ArrayList
        Dim returnList As New ArrayList
        For Each emp As Employee In Me
            For Each brokenRule As Csla.Validation.BrokenRule In emp.BrokenRulesCollection
                If brokenRule.Severity = Validation.RuleSeverity.Warning Then
                    returnList.Add(brokenRule.Description)
                End If
            Next
        Next
        Return returnList
    End Function

This way the UI could just have:
Dim empWarnings as ArrayList=_employees.WarningList
If empWarnings.Count > 0 then
    Dim strMsg as String=""
    For each item as string in empWarnings
       strMsg += item & Environment.NewLine
   Next
      Dim returnVal as DialogResult = Messagebox.Show(strMsg & "Save anyway?")
    SelectCase returnVal
       blah,blah...
End If

Does this make most sense?

Thanks again for you help.

ajj3085 replied on Wednesday, April 18, 2007

I think there's already a way to get warnings from Csla; check out the BrokenRulesCollection class, I believe there's a ToArray overload that will take a Severity parameter so you can get only the warnings.

mr_lasseter replied on Wednesday, April 18, 2007

Wouldn't the following logic in your UI work for you?

 If _bill.BrokenRulesCollection.WarningCount > 0 Then
            '  Display Warnings to the user - but still allow them to save
            Dim displayMessage As New StringBuilder()
            displayMessage.Append(CChar(Environment.NewLine), 2)
            displayMessage.Append(_bill.BrokenRulesCollection.ToString(Validation.RuleSeverity.Warning))
            displayMessage.Append(CChar(Environment.NewLine), 2)

            If Not Messages.Question(String.Format(My.Resources.WarningsFound, displayMessage)) Then Exit Sub
        End If

        Using New StatusBusy("Saving Bill....")
            Try
                _bill.Save()
            Catch ex As Exception
                Messages.Critical("Error Saving.", ex)
            End Try
        End Using

bgilbert replied on Thursday, September 13, 2007

For posterity, I found a better solution that moves the majority of the logic into my business class. I created a custom event and a new event args class that has properties to contain the question and the response. I then raise the event that the UI subscribes to. It sets the response property based on a msgbox response.

DansDreams replied on Thursday, September 13, 2007

I'm a little unclear about what you actually did.  At the end of the day, you still need something similar to what you originally described, except for the decoupling of the alert to the UI (accomplished by using an event).

So, the BO has an event ZeroTimeSpanSet.

BO has a bool property ZeroTimeSpanNeedsVerify which is false by default

Whenever the TimeStart or TimeEnd properties are set, the BO raises the event and sets the property to true if necessary based on examining the time span.

IsValid checks to make sure the property is false.

UI should provide way to set the property to false when the event is raised.

Is that close to what you did?

bgilbert replied on Thursday, September 13, 2007

I was able to do away with the property. I have a validation rule wired to both of the time properties. In the rule handler, if the two time properties are the same, I raise the event. If the response passed back in the event args is that this is an acceptable condition, I return true. Otherwise I return false.

Copyright (c) Marimer LLC