GUI Design

  • Thread starter Thread starter Rob
  • Start date Start date
R

Rob

Hi All,

I just wanted to get some of your opinions on the approach I am using
for a small windows forms app I am writing in VB.NET.

First of all I have kept all of my data classes seperated from my GUI
classes - no user interaction is required within any data class. To
interact with the data classes I will create a new instance of a form
class. For example I would create a new frmMyDataClass which would
contain it's own instance of MyDataClass. The form has the means to
change all of the relevant public properties within MyDataClass.

Whenever a property of the Data class is modified it will raise an
event. For example if I set me.MyDataClass.Name = "newName" then the
data class will raise a NameChanged event using MyDataClassEventArgs
that is bubbled back to the calling form. The event is a custom event
so it contains a reference to the instance of MyDataClass that was
changed.

This then allows my form class to be notified whenever the data that
it represents has changed and update the form accordingly. This will
ensure I don't ever forget to visually update whatever changes have
been made.

Is this a silly approach? Should I just do something more like:-
me.MyDataClass.Name = "newName"
me.text = me.MYDataClass.Name

.... and make sure that I don't forget to do the visual update?

Thanks,
Rob
 
nothing silly about your design. I would suggest one thing... perhaps you
are already doing this... it isn't clear.

Make sure that your data classes are not tied to your form classes. The
form object should use a factory to create the data object. Once the data
object is created, the form object should register its own delegates into
your data object. That way, the data object is NOT aware of the fact that
it is sending an interrupt to the form. It is simply sending a notification
to someone who wants to know when something changes.

I am curious about something, though. How does a "using" object request a
change to the underlying data? You said that the data object is
encapsulated within a form. If this is the case, wouldn't the using object
ask the FORM to change the Data? If so, then you don't need the delegates
at all. If not, then where are the data objects stored so that they can be
directly referenced from a using object?

--
--- Nick Malik [Microsoft]
MCSD, CFPS, Certified Scrummaster
http://blogs.msdn.com/nickmalik

Disclaimer: Opinions expressed in this forum are my own, and not
representative of my employer.
I do not answer questions on behalf of my employer. I'm just a
programmer helping programmers.
 
Hi Nick, thanks for the reply. A sample bit of code may make it easier
for you to see what I am doing... I've just thrown this together but you
should get the idea.

<-- UNTESTED -->

public class frmMyDataClass {
...
Private _DataClass as DataClass
...
public sub new()
...
_dataclass = new dataclass("c:\mydataclass.xml")
end sub

public readonly property DataClass as DataClass
get
return _dataclass
end get
end sub

private sub RefreshDataClassName(ByVal title as String)
'Update the form title
me.text = title

'Update the treeview node
me.mytreeviewnode = title

'Update the textbox value (also used to change the
'value of _DataClass.Name)
me.txtDataClassName = title
end sub
...
'This sub is for a textbox control on the form
'and is fired when the value is changed
private sub txtDataClassName_TextChanged(ByVal sender _
As Object, ByVal e As System.EventArgs) Handles _
txtT2PDName.TextChanged

me.DataClass.Name = txtDataClassName.value

end sub

...
protected overridable sub _DataClass_NameChanged(ByVal sender as Object,
Byval e as DataClassEventArgs)
RefreshDataClassName(e.DataClass.Name)
end sub
...

end class 'frmMyDataClass

public class MyDataClass

public event NameChanged as Eventhandler

private _name as string

public property Name as String
get
return _name
end get
set (value as string)
if _name <> value then
_name = value
OnNameChanged(me, new MyDataClassEventArgs(me))
end if
end set

public sub new(byval filename as string)
'get details from file here....
...
me.Name = strFromFile
end sub

protected overridable sub OnNameChanged( _
byval sender as object, byval e as MyDataClassEventArgs)
Raiseevent NameChanged(me,e)
end sub

end class 'MyDataClass

<--UNTESTED-->

Ok, sorry the codes a bit of a mess but you should get the gist of
things. Basically all of the different places in the GUI that need to
be refreshed will be refreshed by the RefreshDataClassName sub which is
called whenever something changes the value of the DataClass.

Is there any advantage to doing it this way or should I just make a call
to the RefreshDataClassName sub everytime the value is changed and don't
worry about raising the events.

I'm also a little concerned about using the textbox this way. It works
fine but I don't like that it is almost recursive. Ie.
1) You change the value in the textbox
2) this updates dataclass.name b/c they are not equal
3) the NameChanged event is fired
4) the RefreshDataClassName sub is called which changes the value in the
textbox (see step 1)
5) this tries to update dataclass.name again but they are already equal
because of the check I put in the property so it stops here.

Anyway, this is my first attempt at .Net so you'll have to excuse my
newbieness.

Thanks
Rob
 
OK, so you are embedding the data object in the form. This seems odd to me.
If a bit of calling code wants to update the data object, there is no way to
do so except by going through a form. A data object cannot exist without
being tied to a form, and a data-aware form cannot share data objects with
another form.

This coupling between forms and data objects is not a good thing
architecturally. In fact, it is really bad.

Best advice I can give at this stage: You want to have a controller object
in there somewhere that provides indirection. Make the controller a
singleton. Give it all powers of creation. E.G. no form or data object can
be created except by a method on the controller.

If a form wants access to a data object, it will ask the controller for it.
If the data object exists, the controller can return it. Otherwise, it can
create it (where creation implies query or preloading from a file, etc).
That way, any form can get access to any number of data objects, and forms
do not need to know if the object already exists or how to create it.

Also, when the form asks for a data object, either the controller can
register the form to receive the update events, or the form itself can
register the events. Right now, the data object has the code to register
the events, which implies that the data object is aware, at some level, of
the object that wants to be informed of the event. (Doesn't show in your
code, but once you get the bugs out, it will).

The controller and the data objects act as your middle layer. The forms are
your front end. The DAL under your data objects acts as your data layer.
This gives you a clean multi-tier design using the Model-View-Controller
pattern.

In other words... your original question is about how to best rearrange the
deck chairs on the Titanic... and I ducked the question completely to point
out the pesky iceberg.

As far as the apparent recursiveness: if a user updates a form, and the form
wants to update the data object, the form should set a flag so that when it
gets the event for a change to the data object, it knows to ignore it. Your
current check for changes is sufficient, or you can use a private field in
the form object.

--
--- Nick Malik [Microsoft]
MCSD, CFPS, Certified Scrummaster
http://blogs.msdn.com/nickmalik

Disclaimer: Opinions expressed in this forum are my own, and not
representative of my employer.
I do not answer questions on behalf of my employer. I'm just a
programmer helping programmers.
--
 
Thanks Nick,

I've done a quick search for Model-View-Controller and there's plenty
more info out there for me to digest. I think I have a lot to learn in
regards to design patterns. Time to invest some money in a good book
methinks and review my design (and yes - I have seen the links to
suggested books on your blog site).

Thanks again for the help
Cheers,
Rob
 
Back
Top