Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / Languages / C# / November 2006

Tip: Looking for answers? Try searching our database.

proper programming? (events)

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
giddy - 17 Nov 2006 07:06 GMT
hi ,

ok , i have a programming background but i'm new to C# . i'm also self
taught so :

i have a datagridview that should act differently depending on which
user has signed in

now is it more effecient/correct if i do this:

if(user=="user1") {
   this.dataGridView2.CellBeginEdit += new
System.Windows.Forms.DataGridViewCellCancelEventHandler(this.dataGridView2_CellBeginEdit_User1);
}else {
   this.dataGridView2.CellBeginEdit += new
System.Windows.Forms.DataGridViewCellCancelEventHandler(this.dataGridView2_CellBeginEdit_User2);
}

as opposed to check for which user in ONE cellBegin event??

Thanks
Gideon
Tom Shelton - 17 Nov 2006 08:01 GMT
> hi ,
>
[quoted text clipped - 18 lines]
> Thanks
> Gideon

I'm not sure I like either method.  Checking for the actual user would
seem to make things pretty hard to maintain.  What kinds of things are
you looking to do different?  There is almost certainly a better way to
accomplish what you want...

--
Tom Shelton
giddy - 17 Nov 2006 08:24 GMT
oops. .i'm sorry , by user i meant user for my application , my app
mantains users wth passwords , i'm not talking about windows user
accounts

basically i did'nt want to make it confusing but , there are levels ...
each user is given some privilege and retricted in some way ,  eg .
some users might not be allowed to edit , but only allowed make new
entries , some users would be allowed do the opposite.. etc... .the
celBeginedit is'nt the only event i have to check for this...

i'm just asking if its CORRECT to give it a different delegate to
different funciton depending on what privelages the use has...

becuase checking for it in ONE event might get cumbersome and reduce
efficency??

also is Program.cs file , with "class program  , and the main()" the
place to have complete global variables? that can be accessed by all
forms and dialogs??? (i'm an ex vb! , so i'm asking is program.cs like
a module file?)

Gideon

> I'm not sure I like either method.  Checking for the actual user would
> seem to make things pretty hard to maintain.  What kinds of things are
> you looking to do different?  There is almost certainly a better way to
> accomplish what you want...
Dave Sexton - 17 Nov 2006 11:28 GMT
Hi Gideon,

<snip>

> basically i did'nt want to make it confusing but , there are levels ...
> each user is given some privilege and retricted in some way ,  eg .
> some users might not be allowed to edit , but only allowed make new
> entries , some users would be allowed do the opposite.. etc... .the
> celBeginedit is'nt the only event i have to check for this...

In that case, the code I posted in my original response should be useful to
use as the foundation for a User business object to encapsulate information
about a particular user, and a UserUICapabilities object that encapsulates a
User's permissions.  You may even want to use roles that encapsulate groups of
permissions so that you can write code as such the following:

if (User.Current.IsAdministrator)    // role-check
{
   // do admin things such as allow edit AND decrypt related information
}
else if (User.Current.CanEdit)        // permission-check for non-admins
{
   // allow edit
}

> i'm just asking if its CORRECT to give it a different delegate to
> different funciton depending on what privelages the use has...

For the example you posted, I wouldn't recommend it at all.  As I already
stated, I think that logic should be in the event handler (or better yet, be
abstracted into a business object).

> becuase checking for it in ONE event might get cumbersome and reduce
> efficency??

The same would be true in the method that checks the user name to determine
which delegate to be registered as an event handler.

Try to separate the UI logic from the business logic.  That is, encapsulate
the business logic in separate components that can be utilized by the UI code.
Only provide one place to handle a UI event, and then perform the required
processing in the appropriate business object.  If the process itself will
vary by state that is retrieved from a database, such as user permissions,
then this design approach will make it much easier for you to change things in
the future without having to change the business logic in all of the UI
classes in which it may have been hard-coded.  This is especially true if you
code the logic as in your example, where you wrote:

> if (user == "user1")

What happens if "user1" is renamed to "user_1", or deleted, or their
permissions are changed?

In that case, you'd have to recompile your code to handle the change in the
data.  That's something that should by dynamic, and accounted for ahead of
time so that simple changes in data will not require the entire solution to be
modified and redeployed.

Business objects can be the first step to providing the abstraction you need
from your UI code to your business logic code so that you don't have to
hard-code user names, permissions and business logic in every event handler in
which it's required.

> also is Program.cs file , with "class program  , and the main()" the
> place to have complete global variables? that can be accessed by all
> forms and dialogs??? (i'm an ex vb! , so i'm asking is program.cs like
> a module file?)

Try to use as little global variables as possible.  Instead, try to think more
OOP.

That said, there are definitely times where a global variable might be of use
outside of any business object, but it's rare (if even appropriate at all).

But I do use the Program class in my projects to aggregate certain singleton
data such as the current user of the application or the current client context
in which all of the Forms in my application will process information across
the entire system, for example:

static class Program
{
   public static User CurrentUser { get { return User.Current; } }
   public static Client CurrentClient { get { return Client.Current; }
}

But realize that the Program class doesn't store the data in this case, it
just creates a common interface for accessing global data.  The data itself is
stored in the appropriate business object.  In some cases, a DataContext
object may be useful if you need to store multiple contexts, simultaneously.

I like using the Program class because it just feels natural to code against
data with application scope like this:

if (Program.CurrentUser.IsAdministrator)
{
   if (Program.CurrentClient.InvoiceRequired)
   {
       Invoice invoice = Invoice.PrepareInvoice(Program.CurrentClient);
   }
}

This is really just a matter of opinion.  Some people, I'm sure, prefer to
access the User and Client objects directly for singleton data.  I just feel
that User.Current isn't as clear as Program.CurrentUser.

Signature

Dave Sexton

Dave Sexton - 17 Nov 2006 08:05 GMT
Hi Gideon,

I prefer to place that logic in the event handler, or if the logic is complex
and dynamic then a business object.  i.e., if the logic in the event handler
may be configured for each user and changed at a later time based on database
properties, for example, then that complexity may warrant the use of a more
complex system as well to prevent code bloat in the event handler method and
to encapsulate the logic so it can be reused in other UI components and
systems.

Here's a simple BO model that you might want to adopt if you have "dynamic"
needs, such as the one I mentioned above:

this.dataGridView2.CellBeginEdit += dataGridView2_CellBeginEdit;

void dataGridView2_CellBeginEdit(object sender, SomeEventArgs e)
{
   // you should ensure that your application assigns the User.Current
   // property before it is queried here, or you can make the property a
   // singleton field and initialize it automatically upon first request
using a
   // type constructor (static).

   User.Current.BeginCellEdit(sender, e);
}

class User
{
   private static User current;
   public static User Current { get { return current; } set { current=
value; } }

   public UserUICapabilities Caps { get { return caps; } }

   private readonly UserUICapabilities caps;
   private readonly int id;

   public User(int id)
   {
       this.id = id;
       caps = new UserUICapabilities(this);
   }

   public void BeginCellEdit(object sender, SomeEventArgs e)
   {
       caps.BeginCellEdit(sender, e);
   }
}

class UserUICapabilities
{
   private readonly User user;
   private bool initialized;    // lazy initialization

   public UserUICapabilities(User user)
   {
       this.user = user;
   }

   void EnsureInitialized()
   {
       if (initialized)
           return;

       // TODO: load user caps from database

       initialized = true;
   }

   public void BeginCellEdit(object sender, SomeEventArgs e)
   {
       EnsureInitialized();

       // Each User object with a distinct "id" will have an
       // instance of a UserCapabilities object that can provide a
       // different implementation here.

       // TODO: begin cell edit based on the "user" field in this class
   }
}

If the BeginCellEdit method needs more information about the UI elements that
it can manipulate, then you can create a data context class.  An instance of
your data context class may be passed to BeginCellEdit instead of the sender
and event args:

class BeginCellEditContext
{
   private DataGridView grid;
   private DataGridView Grid { get { return grid; } }

   private Label label;
   private Label Label { get { return label; } }

   public BeginCellEditContext(DataGridView grid, Label label)
   {
       this.grid = grid;
       this.label = label;
   }
}

That class may be the only argument to the BeginCellEdit method:

public void BeginCellEdit(BeginCellEditContext context)  { ... }

The method may be called as such:

BeginCellEditContext context = new BeginCellEditContext(theGrid, theLabel);

User.Current.BeginCellEdit(context);

Another option is to use an MVP architecture, but that's going to add even
more complexity.  You'll have to create command objects for every possible
task that the BeginCellEdit method may perform.

The simplest approach that meets all your needs will be the best one; in some
cases that is just a simple event handler routine, so choose wisely :)

Signature

Dave Sexton

> hi ,
>
[quoted text clipped - 18 lines]
> Thanks
> Gideon
PS - 17 Nov 2006 15:08 GMT
> Hi Gideon,
>
[quoted text clipped - 21 lines]
>    User.Current.BeginCellEdit(sender, e);
> }

You make some very good points Dave. When it comes to authorizations it is
also possible to have a heirarchy of view/add/edit/delete. I often split the
responsibilities between how the events are hooked up from what is handled
in the event handler. If a user's authorization is read only then I usually
do not hook up any events and make the control read only. The event handler
is used for when the user has some editing authorizations.

In some respects the OP's delegation to different event handlers at "load"
time is a halfway between using a single event handler that handles
different levels of authorizations, and using a separate business object
that delgates accordingly. He has just shifted the delegation decision to
"before" the event has occured.

PS

> class User
> {
[quoted text clipped - 112 lines]
>> Thanks
>> Gideon
Dave Sexton - 17 Nov 2006 15:25 GMT
Hi,

> You make some very good points Dave. When it comes to authorizations it is
> also possible to have a heirarchy of view/add/edit/delete. I often split the
> responsibilities between how the events are hooked up from what is handled
> in the event handler. If a user's authorization is read only then I usually
> do not hook up any events and make the control read only. The event handler
> is used for when the user has some editing authorizations.

Agreed.  It definitely makes sense to disable or even remove a control based
on the current user, but in some cases it's just not that simple.  I assumed
that this is one of those not-so-simple cases since the OP didn't mention if
certain users would be restricted from editing all data or just certain cells.

> In some respects the OP's delegation to different event handlers at "load"
> time is a halfway between using a single event handler that handles
> different levels of authorizations, and using a separate business object
> that delgates accordingly. He has just shifted the delegation decision to
> "before" the event has occured.

Yes, and I don't think that's a reasonable option.

The event is going to occur no matter what, so adding that logic to choose
which handler is invoked is not a clear separation of UI logic and business
logic unless another class handled the delegation for the UI component, but
that would be extra work with no apparent value.  What do you think?

Signature

Dave Sexton

PS - 17 Nov 2006 18:52 GMT
<snipped />

>> In some respects the OP's delegation to different event handlers at
>> "load" time is a halfway between using a single event handler that
[quoted text clipped - 9 lines]
> component, but that would be extra work with no apparent value.  What do
> you think?

I am always in two minds over the "separation" aspect. On simple forms I
find that the code behind provides sufficient separation. I generally have a
setup region, a display region and an event handling region. There is very
little that can be shifted to another object because so much involves an
interaction between a UI object and a business object. e.g.

this.deleteEmployeeButton.Enabled = user.Role.IsAdminUser;

Moving this to a seperate object is "extra work with no apparent value". In
fact the new object ends up looking like your code behind file did. It is
just a facade that adds no value.

At a certain point a form goes beyond these simple UI object / business
object interactions. Decisions about UI state become more complicated. UI
controls need to react to the events raised by the use of other UI controls.
UI controls may be disabled if the user does not have authorization, if the
business object is read only, if a particular tab is not selected etc. This
is when I use a separate object. The code behind remains simple and the form
once again returns to simple UI control / object interaction, e.g.
this.deleteEmployeeButton.Enabled = myObject.EmployeeDeletionAllowed;

PS
Dave Sexton - 17 Nov 2006 19:46 GMT
Hi,

<snip>

> I am always in two minds over the "separation" aspect. On simple forms I
> find that the code behind provides sufficient separation. I generally have a
[quoted text clipped - 7 lines]
> fact the new object ends up looking like your code behind file did. It is
> just a facade that adds no value.

In this simple case, I would agree.  The standard MVC architecture used in
WinForms is common and simple to understand.

Here, you're performing an action that could easily be done using the standard
property-binding mechanism.  Once binding is no longer a possibility, I
believe that complexity may warrant abstraction.

> At a certain point a form goes beyond these simple UI object / business
> object interactions. Decisions about UI state become more complicated. UI
[quoted text clipped - 4 lines]
> once again returns to simple UI control / object interaction, e.g.
> this.deleteEmployeeButton.Enabled = myObject.EmployeeDeletionAllowed;

I agree, but in this example you still only need to set an Enabled property.
That could be done using simple property-binding.

My example allowed for complex business logic on the UI components through a
"capabilities" class.  It is not an appropriate design if the OP only needs
the simplicity in your examples, but I tried to make that clear in my original
response.  Since the OP didn't state the requirements in detail, I assumed
that they may be complex enough where giving an answer such as, "put it in the
event handler" might have been too basic.

I think we agree here, though, that the standard MVC architecture in WinForms
may still be appropriate in certain circumstances.

Do we also agree that coding the logic to choose an appropriate event handler
instead of having a single event handler, in the OP's particular case, is a
bad idea?  (that was actually my original question to you :)

Signature

Dave Sexton

PS - 17 Nov 2006 21:39 GMT
> Hi,
>
[quoted text clipped - 18 lines]
> standard property-binding mechanism.  Once binding is no longer a
> possibility, I believe that complexity may warrant abstraction.

A good guideline to use.

>> At a certain point a form goes beyond these simple UI object / business
>> object interactions. Decisions about UI state become more complicated. UI
[quoted text clipped - 8 lines]
> I agree, but in this example you still only need to set an Enabled
> property. That could be done using simple property-binding.

Yes, but the logic required to work out if the button should be enabled is
something that should be encapsulated outside of the code behind in it's own
object. I guess I use the Mediator pattern.

"Define an object that encapsulates how a set of objects interact. Mediator
promotes loose coupling by keeping objects from referring to each other
explicitly, and it lets you vary their interaction independently"

> My example allowed for complex business logic on the UI components through
> a "capabilities" class.  It is not an appropriate design if the OP only
[quoted text clipped - 9 lines]
> handler instead of having a single event handler, in the OP's particular
> case, is a bad idea?  (that was actually my original question to you :)

I would have to agree with you on that. If the OP wants to use separate
methods then he should call them from the single event handler.

Good discussion,

Regards,

PS
Dave Sexton - 17 Nov 2006 22:28 GMT
Hi,

<snip>

>>> At a certain point a form goes beyond these simple UI object / business
>>> object interactions. Decisions about UI state become more complicated. UI
[quoted text clipped - 16 lines]
> promotes loose coupling by keeping objects from referring to each other
> explicitly, and it lets you vary their interaction independently"

Yes, we're on the same page here as well.

The mediator pattern is interesting.  Here's some more information I found on
the subject in the context of an article on the Message Broker Pattern [link
after sig]:

"Mediator [Gamma95]. The Mediator pattern separates objects so that they are
only aware of the mediator but not each other. The Broker deals with similar
concerns, but it can only be used in the context of enterprise applications."

So your example does seem like the mediator pattern.  And if the actual type
of "myObject" was the "UserUICapabilities" class from my original response,
that would make even more sense.  It would just need a property named,
"EmployeeDeletionAllowed".  Since it was created by a User object, it would
act as the mediator between the User and the UI.

<snip>

Thanks for the discussion.

Signature

Dave Sexton

"Message Broker Pattern"
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag/html/arch
messagebroker.asp

giddy - 18 Nov 2006 11:46 GMT
Hi Dave ,

i didnt see your post before posting my second reply! i hit the reply
button , went to have lunch! and wrote my post only in response to Toms
post! lol and i did'nt have time to replay back! sorry....

yes , your approach makes whole lot of sense , i did'nt even give a
thought to making seperate classes! infact i've decided to seperate a
lot more .. .thanks

although the complexity at which i'm working is not much. Each user has
about 5 levels of privileges..... basically i thought it would be more
effecient to register an event with the right delegate in the first
place(when the form loads) so i would'nt have to go checking INSIDE the
function (when the event fires) , for what privilege the user has!
anyway i think the object method is more effecient! and a lot more
cleaner... .

thanks again!

Gideon

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.