Avoiding WinForm Binding - If Possible...

J

jehugaleahsa

Hello:

I was forced to write some EXTREMELY complex code to make binding to
custom business objects possible in WinForms. The reason for so much
code was to handle state management. For instance, we needed a way to
determine whether an record was added, updated, deleted, etc. so when
it came time to save we knew which type of SQL to execute.

The problem with binding is that it leaves no obvious place for
complex form validation. 99% of the time, validation is very simple.
However, that 1% is very problematic. In these rare cases, avoiding
binding seems like a better solution overall.

The problem is that without binding, the larger forms start to become
a hodge-podge of event handling and are very error prone. Originally,
the folks in my office were talking about making our WinForms
stateless, so they acted a lot like web pages (one action per click/
screen). However, the whole point of client/server applications is to
allow many changes before needing to hit the database again.

So, the question comes down to: how can we achieve a proper MVC in a
stateful environment that doesn't result in a large amount of manual
UI manipulation? We want to maintain a large level of control without
the complexities of managing the UI manually. It seems like binding is
what MS is expecting people to use. However, managing state using
binding and NOT using data tables seems to result in extremely complex
code.

I am hoping someone has a good article I can view. Any suggestions for
how to achieve a stateful UI without complex binding and event
handling would be greatly appreciated. The more generally applicable
the approach, the better.

Thanks,
Travis Parks
 
V

vanderghast

Is there a typo? you mentioned binding up to near the end, where you say:
However, managing state using
binding and NOT using data tables


What do you have in mind with the expression "data tables"?


Anyhow, using ADONet, the "datasets" are collections of DataRow which
automatically maintains a RowState for you
(http://msdn.microsoft.com/en-us/library/system.data.datarow.rowstate.aspx)
allowing you to define particular procedures versus the rowstate
(http://msdn.microsoft.com/en-us/library/system.data.datarowstate.aspx).


My preferred reference about pre-LINQ data binding is the book
http://www.amazon.com/Windows-Forms-Programming-Microsoft-Development/dp/0321267966
Chapter 16 and 17.


Vanderghast, Access MVP
 
J

jehugaleahsa

Is there a typo? you mentioned binding up to near the end, where you say:


What do you have in mind with the expression "data tables"?

DataTables and other ADO .NET classes.
Anyhow, using ADONet, the "datasets" are collections of DataRow which
automatically maintains a RowState for you
(http://msdn.microsoft.com/en-us/library/system.data.datarow.rowstate....)
allowing you to define particular procedures versus the rowstate
(http://msdn.microsoft.com/en-us/library/system.data.datarowstate.aspx).

Our system already has a ton of data objects. It doesn't make sense to
rewrite all of our data layer logic and SQL just to utilize
DataTables. More importantly, on some forms, the binding mechanism
employed by DataTables is too restrictive. When validation becomes
complex, binding seems to make doing complex validation seem like
jumping through hoops.
My preferred reference about pre-LINQ data binding is the bookhttp://www.amazon.com/Windows-Forms-Programming-Microsoft-Development...
Chapter 16 and 17.

I have access to that book. It has a lot of good data on binding, but
mostly to the built-in ADO .NET classes. I have written an extensive
library that manages the state of custom data objects, working with
the BindingList class, etc. Unfortunately, binding to custom data
objects suffers the same limitations when it comes to validation.

Here is an example:

You have two customers that have charges that can be distributed back
and forth. We want to keep their bills about the same amount. So, we
give the user the ability to move charges between customers so that
they can even out the amounts manually. A typical implementation would
involve two ListViews, each bound to a list of charges. Say I have
binding set up so that when I remove an item from a list, it is marked
for deletion. When I try to move an item from one ListView to the
other, the charge will be marked for deletion in the old list and
marked as added in the new list. Great! However, later on, the user
decides to move the charge back to the original customer. Now it is
discarded (since it wasn't added) and re-added to the original list. I
could be smart and detect that the charge already exists in the
original list and simply unmark it for deletion. However, a simpler
approach would be to re-add the charge to the customer, praying that
the original charge gets deleted first before it is re-added to the
database (primary key violation). Mind you that this results in two
unnecessary hits to the database. Either way you go, this is a lot of
code for simply moving records between controls. In fact, I think this
much overhead is absolutely rediculous! All I really need to do is
track where charges go and apply the correct SQL once the user saves.
In other words, it would be easier to track these changes using a
custom state management process at the control level. A general-
purpose state tracker results in more problems than it solves! The
problem with discarding binding is that now it is fully my
responsibility to populate the controls and update the UI.
Furthermore, writing the custom state management code can result in a
lot of unreusable code.

The problem is that binding assumes the Form's environment follows the
standard load/edit/save mentality. 99% of forms seem to query data
from a database, allow the user to edit that data and then save their
changes. Typically, binding is simply column-to-control or property-to-
control and nothing more. Validation is typically as simple as
checking the type and bounds of a value. Whenever forms start to allow
more interaction, binding becomes a hassle. When 99% of your code set
is written to make creating the typical form easy, these irregular
forms can create an intolerable deal of inconsistency. It seems
WinForms are geared toward 99% of forms and leave the more advanced
forms to fend for themselves.

I did some research into this topic recently. It seems that the
solution depends on the scenario. Many times binding is only part of
the solution; use it to manage populating controls but rely on other
means for state management. Put an explicit disconnect between the
data layer and the binding mechanism.

Thanks for you response!
 
V

vanderghast

For the particular example you supplied, I would try a table design which
will consider that each charge, chargeID, owns, among other property, to be
handled by someone:

ChargeID, HandlerID (nullable) ' fields

and the job won't be one of appending/deleting rows (which is also
relatively expensive in time of execution), eliminating possible problems
you clearly mentioned, but to 'simply' update existing rows (rather than
append/delete rows). Sure, that assumes that the charges are already known,
'traceable (have some identity) and atomic (cannot eventually be broken into
many smaller ones). That may not be your case. Since the data is
disconnected, the complex validation (are all handlers have a similar total
charge load, etc. ) can be done in your code before your code is explicitly
asking for synchronization of the local data to the database.

Anyhow, the main point would be to have a database design which removes the
need to create/delete rows from tables, if possible, and that will probably
fit better in the standard DotNet model. Between "keep the DotNet model and
change the db model to fit", and between "keep the db model and re-invent a
data set model", which one is easier ? :)



Vanderghast, Access MVP
 
J

jehugaleahsa

For the particular example you supplied, I would try a table design which
will consider that each charge, chargeID, owns, among other property, to be
handled by someone:

ChargeID,    HandlerID (nullable)        ' fields

and the job won't be one of appending/deleting rows (which is also
relatively expensive in time of execution), eliminating possible problems
you clearly mentioned,  but to 'simply' update existing rows (rather than
append/delete rows). Sure, that assumes that the charges are already known,
'traceable (have some identity) and atomic (cannot eventually be broken into
many smaller ones). That may not be your case. Since the data is
disconnected, the complex validation (are all handlers have a similar total
charge load, etc. ) can be done in your code before your code is explicitly
asking for synchronization of the local data to the database.

Anyhow, the main point would be to have a database design which removes the
need to create/delete rows from tables, if possible, and that will probably
fit better in the standard DotNet model.  Between "keep the DotNet model and
change the db model to fit", and between "keep the db model and re-inventa
data set model", which one is easier ?  :)

Vanderghast, Access MVP

My example is a bit flawed. In reality, you would expect these charges
to exist in the same table, with different customer foreign keys. So
really, it is a matter of updating the foreign key.

The real issue comes when removing items and adding items to a list
causes unexpected behavior. If we had two DataTables, moving items
between those them might not do what we want. We could have one
DataTable and use filtering or views to see as though it were two
tables. But... even here, what happens when you move an item back to
the original list? It will still show as being modified.

I find the only true solution is to avoid binding altogether. Just
track which items were moved (somehow) and update the DataTables after
the user clicks save. Now you're synchronizing in the UI, effectively.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top