How to Automatically Update UI When Data Changes

  • Thread starter Thread starter Charles Law
  • Start date Start date
Hi Carlos
- A polling mechanism every n seconds

Although not my preferred choice originally, RMT has given me some food for
thought, so I can see me going down this route.

Thanks.

Charles
 
Well in my case, the implementation details are more complicated, yes - as
an example of implementation detail, which I think is specific to my kind of
application:

(1) Prioritise Thread Requests
(2) Ensure low priority requests don't block high priority ones
(3) Error handling in the thread
(4) Listeners registering only for the events they are interested in
(5) Different types of coherency check
(6) Ensure coherency check "chunks", rather than checks an entire structure
at once
(7) Tree structure - reason about a tree from the flat structure a RDBMS
returns
(8) Enforce pattern on UI components


But in the simplest case - wanting to keep a record set coherent, it isn't
so hard.


Some general principles:

(1) A cache object to store the state you want to persist
(2) A worker thread
(3) A way for the thread to talk to the cache (Invoking methods on an
interface), so
(4) An interface for the Cache object to implement so it can receive
messages from (3)
(5) An abstract class from which your UI components can derive
(6) A list of listeners in your Cache Object, i.e. list of references to (5)
(7) A base "Operation" class, which encapsulates any operation you perform
on the data.
(8) Derived classes to actually perform the operations (ie. add, delete,
update, etc.)
(9) Methods on your data cache that construct objects from (8) and queue
them at (2)

Finally, data will flow around the system:

Either:

User interacts with UI component
UI component executes a Cache method (ie. "InsertRecord ( aaaabbbb )" )
Cache Object constructs request and adds to worker thread queue

or

Worker thread is in idle time, constructs a coherency check and adds it to
it's own queue

and then.....

Worker Thread iterates it's queue, executing each request in turn
Request Invokes a method on Cache interface (marshall across threads)
Cache resolves changes
Cache fires event on all of it's listeners
UI component changes it's state according to the event fired.
 
You have obviously taken a comprehensive approach to developing this
pattern. Have you found that it is efficient in terms of cpu time? How many
rows do you return on an average round-trip? Do you have any metric for the
reaction time of the UI to changes in the data?

Charles
 
Yes, I've done a lot of research on this, because my first attempt was a
miserable failure (well it worked, but it hardly produced maintainable code,
so version 2.0 is more comprehensive).

I can have well over 1000,000 rows in my database and performance outside of
the pattern (ie. on the server side with the DMBS) therefore depends on
system admin things like maintenance of indexes and hardware. This is
particularly true for me, because I'm doing a lot of work with binary
blobs - and a tree structure (ie. every row in the table has some
ancestor/descendant/sibling relationship with other records).

Inside of the pattern itself, most operations are more or less
simultaneous - ie. well within the timeframe the user might expect. For
operations that take a long time (seconds, a minute, two minutes), I have a
timer on my main form that is started when the cache handles the
Operation_Started invocation from the thread and stopped when the cache
handles the Operation_Ended invocation from the thread. After one or two
seconds, I display a progress bar. In my experience users don't mind an
operation that takes a while to complete, as long as they can see more or
less how long they have to go fetch a coffee.

Remember that from UI through Cache into Worker Thread and back to UI is
remarkably quick, ie. milliseconds - the time consuming part is database
access - and you can throw hardware at that problem to improve it. Also
because I'm using a worker thread, the UI will remain responsive.

I'm also using DataReaders/Writers, stored procedures for all data access
and the most important structure in .NET (in my opinion), the Dictionary -
so rather than having to hunt through a list of rows to find the one I'm
interested in, I can simply look the record up using a primary key. It's
worth the maintenance for the speedup you get.
 
Thanks for all the excellent pointers. This gives me a lot to be going on
with. I will start small, to experiment, and build up, I think.

As you say, you are on V2 now, because V1 was a "miserable failure": was
there anything in particular that you learned to avoid, that in V1 made it
so bad?

Charles
 
Charles,

Most database engines support triggers. They are a special type
of stored procedure that runs when you modify data in a database. I would
add a table to the database which contains 2 fields table name and revision
number. I would create a trigger to update the revision number whenever
something is changed. In a timer check the revision number and reload the
data if necessary.

http://msdn.microsoft.com/library/d...n-us/vdbref/html/dvconworkingwithtriggers.asp

Ken
 
Hi Ken

Thanks for the suggestion. I understand the principal of what you are saying
but, to me, it seems akin to using files as semaphores. I am not totally
comfortable with this technique as it is generally a workaround, or even a
kludge. For the moment, I am going to pursue RMT's idea, in the absence of a
native solution (not limited to VS2005 and SqlServer).

Regards

Charles
 
Charles Law said:
Here's one that should probably have the sub-heading "I'm sure I asked this
once before, but ...".

Two users are both looking at the same data, from a database. One user
changes the data and commits it. How does the other user get the updated
view without polling for changes? Is there some sort of callback mechanism
that can be set up on the dataset or connection?

TIA

Charles

I don't really know much about your architecture, but you could use UDP
multicast messaging. Assuming you have a server that is performing the
updates, once the update is complete, the server could publish a notification
over a multicast address that the data has changed. Clients would obviously
need to join the multicast group.

Depending on how much sophistication you need, the solution can be as simple
or complex as you like. One thing to note is multicast traffic must be
enabled on your network routers, but there is plenty of documentation around
on how it can be done.

HTH
Dan
 
Hi Dan

That sounds like a neat idea. Is it something you have used yourself? How
did it work out?

Charles
 
Charles,

We are currently doing exactly what you desire. We found our solution
using Genine Channels (www.genuinechannels.com). They have a built in
broadcast engine. Essentially all you do is register MBR's, listener
objects embedded into your business object, into this engine. They
have examples on their site.

Cheers,
Rob Panosh
Advanced Software Designs
 
Yes, definately. I learned that the UI should be completely separated from
anything that changes state. A lot of sample code you see shows "on button
press event, modify the record in the database". This is totally wrong.
The more you do state change stuff in your UI components, the more of a mess
you will eventually get into trying to keep them coherent. The correct way
to think about it is:

UI event the user would like to do something that changes the state (modify
a record for example
<some object that caches the state> asks a thread to change the state
The thread changes the state
The thread notifies the cache the state has changed
The cache notifies the UI the state has changed



rather than:



Private Sub ToolBar1_ButtonClick(ByVal sender As System.Object, ByVal e As
System.Windows.Forms.ToolBarButtonClickEventArgs) Handles
ToolBar1.ButtonClick

If e.Button Is TheTriggerHappyButton Then

WhoooohooooWildlyChangeStuffInTheDatabase()

End If

End Sub
 
I can see exactly how that is going to work for some of the screens I have,
since there is a summary at the top, and a data entry card at the bottom. If
I change the data behind the Enter button on the card, the summary will not
reflect the change unless I change that as well. Far better to have the
summary 'notified' of the change by the thread that updates the database.

It always helps to talk these things through with someone ;-)

Cheers.

Charles
 
Back
Top