Subclassed TextField to Call Business Object Method

I’m trying to subclass a TextField where in the LostFocus event, calls the parent method where the value will be saved to a database.

So, I’m subclassing TextField to be TextFieldAutoSave.
In the TextFieldAutoSave.LostFocus event, I try to have code similar to{Parent}.SaveValue( me.Name, me.Text )
I’d like to create instances of these TextFieldAutoSave controls in containers that get instantiated in numerous Windows.

In fact, it would be ideal to call to a business object that is a property of the Window. The business object would have the primary key for the record that is being edited in the TextFieldAutoSave control. What is the best practice here?

Add events to the textfield and containers to propagate the request out to the window.

I’m not sure I understand what you’re saying. Add a TextFieldAutoSave.SaveValue() method and then … how do I call the event in the container that the instance of TextFieldAutoSave belongs to? This is where I’m lost.

the textfield should not save itself

that puts the responsibility very low down the chain which is the wrong place

the window presumably holds a lot of information about lots of aspects of something being show and IT should determine IF there are changes (maybe by asking each item if it was changed from the original) and then saving everything

otherwise what you have is a field by field “save me”, “save me”, “save me” set up and its quite possible that you need to save everything all at once not piecemeal

Assuming it is appropriate to save the fields one at a time…

You create the container. You put a field on the container and name it something appropriate, like FirstName. In the LostFocus event, you call a method on the container, passing it the field name and value. Now the container needs to know what to do with the value. It might talk to the database directly, or it might delegate everything to the window by raising an event and passing everything on.

When you place the container in the window, you add an event handler to the container (which runs in the context of the window) and call a window method that updates the database.

LostFocus -> Container.Method1 -> Container.Event1 -> Window.UpdateDatabase

If the container is nested inside another container, you add more ripples to the pond.

I agree with Norman on this one. That said…

[quote]So, I’m subclassing TextField to be TextFieldAutoSave.
In the TextFieldAutoSave.LostFocus event, I try to have code similar to{Parent}.SaveValue( me.Name, me.Text )
I’d like to create instances of these TextFieldAutoSave controls in containers that get instantiated in numerous Windows.[/quote]

TextField.Window should contain the parent window even if the control is nested in a container. I would go straight to the window rather then ripple events up the hierarchy if the window is going to contain the business object.

Multiple windows will either need a common ancestor which implements your business logic, or they will need to implement an interface. In either case, your LostFocus event can do something like:

If Me.Window IsA BusinessObjectWindow Then
BusinessObjectWindow(Me.Window).SaveValue( me.Name, me.Text )
End If

But…again…it just doesn’t seem right that individual fields would be responsible for this.

[quote=80376:@Daniel Taylor]
If Me.Window IsA BusinessObjectWindow Then
BusinessObjectWindow(Me.Window).SaveValue( me.Name, me.Text )
End If[/quote]

This did the trick. I’m able to rework things to get this to work.

I understand that this is a special case where I’m needing to save after each field. Not your typical CRUD operation, but I think it fits nicely with my needs.

In another programming language know (that will not be named!) I was able to subclass a control and call me.Parent.SaveValue() and even me.Parent.Parent.SaveValue(). This may not fit well with a strict typed language, but it was handy to fully utilize OOP and the object hierarchy.

Thank you for everyone’s help!

That’s not particularly OOP - just a nice handy way of traversing the Windows control hierarchy

Remember EVENTS CAN RETURN VALUES !

IF I were doing this I’d actually add an event to the subclassed field that gets raised that gets the business object from whatever layout contains the field

Then any window that has one of these can implement that event & return it to the text field in whatever fashion is suitable for that layout & the text field just knows that the event returns an object that it can use (or nil & handles that accordingly)

I’m sure some are going “What ?”

Like this

[code]class myNewTextField
event definition GetBusinessObject() as BusinessObject

 event LostFocus
        dim bo as BusinessObject = GetBusinessObject()
        if bo <> nil then
              bo.SaveValue(me.text) // or whatever is correct
        end if

end class

class Window
control myNewTextField1 inherits myNewTextField
event GetBusinessObject
return self.mBusinessObject
end event
end control

        property mBusinessObject as BusinessObject

end class[/code]

This has the upside of making it so the control is still relatively self contained and DOESN"T need to know much beyond “I can get a business object - somehow and if I get one I can ask it to save my value” and it doesn’t rely on where in the control hierarchy the control is embedded.

HOW it gets access to the business object is NOT something it should know or care - just that it has a way to

But that means adding the event and code everywhere you use the control. That sounds painful :slight_smile: Events are best where each instance will implement unique behavior. I think this is a case where each instance will likely implement the same behavior.

If I wanted to abstract the save out to a generic BusinessObject I think I would have the control check to see if the Window was a BusinessObjectProvider. If so, call GetBusinessObject and then BusinessObject.DoSomething. A single ancestor could implement the BOP interface but child classes could still easily override it.

I’d says its a better delegation of responsibility to the view (controller) rather than to a single field

If you want a form where everything doesn’t save itself and is saved after some kind of edit check it’s pretty trivial to do with how I suggest. Or to have them save one by one.

Much more difficult with each field being responsible for saving itself in the way you’re suggesting.

[quote=80628:@Norman Palardy]I’d says its a better delegation of responsibility to the view (controller) rather than to a single field

If you want a form where everything doesn’t save itself and is saved after some kind of edit check it’s pretty trivial to do with how I suggest. Or to have them save one by one.

Much more difficult with each field being responsible for saving itself in the way you’re suggesting.[/quote]

I thought you were just trying to make the control use a generic BO rather then the window.

In your example and mine each control tries to save itself. The only difference is that GetBusinessObject is an event in yours. I’m afraid I don’t see how making GetBusinessObject an event would make it easier to invert behavior so that the window saves everything at once. If you’re thinking that you could just not implement the event so that GetBusinessObject returns Nil and interrupts the default save behavior, you could do the same thing by overriding GetBusinessObject in the window subclass.

If the control goes directly to the window, it has to make an assumption about the outside environment and breaks encapsulation. If you use events, then the container could be placed in another container and that container could be the business object provider instead of the window. The control and its container really shouldn’t need to know.

Events are still going to result in duplicated effort and code for every field. You could argue that the field should get the BO from Parent instead of Window, but it should be via an interface check and method call. The code should be implemented in the classes, not in the instances.

All but the very last event IS implemented in the class. It’s just the last event that connects the outermost container to the window that has to be coded. It’s no more work than talking to the window directly, and it’s encapsulated correctly.

The way it’s described above every single field instance that is dragged to a window or container will need to implement the event and copy the code to provide the BO. That is a lot more work, and a code maintenance nightmare.

If you implement the event in the class instead then there is no difference vs. using a method except for the fact that child classes cannot override events to provide their own implementation.

I can’t imagine an application with so many data stores that they have to be determined per field instance. Generally this is class behavior, not instance behavior.

For the record, I’m not trying to be argumentative :slight_smile: I just do not see the reason for making it possible to wire every single field up to a separate BO. Even though Kevin wants each field to save itself on LostFocus, he has one BO per window.

If the flexibility to wire each field instance up to a different BO is needed, then yes, events…instance behavior…is the way to go. But if that’s not a requirement then there’s no reason to create or maintain all that code. That’s all I’m saying.

That’s why I prefaced my comments with “Assuming it is appropriate to save the fields one at a time…” I personally wouldn’t do it this way, but I respect Kevin’s reasons for wanting to do so. It was an interesting discussion and I didn’t mean to be argumentative either. There’s always more than one way to skin a cat, and it’s good to look at some of the strengths of each approach. You do bring up some good points. Thank you for the discussion, as always.