Elementary question about C# winforms program design

  • Thread starter Thread starter Descartes
  • Start date Start date
D

Descartes

Dear All,

Coming from another development environment, it appears that I bang my
head in the wall on very basic matters, so I hope you can give me a
push in the right direction.

The application that I work on will consist of
- a mainform with a usual menu and toolbar and not much more.
- a number of modal data editing forms with various edit controls, an
OK button and a Cancel button
- an instance of a data class containing some 50 fields of various
types.

My question relates to the fact that C# doesn't accept "global"
variables, so the data class can not be instantiated directly in the
namespace.
Where and how would you instantiate the data class so that the editing
forms can access the data?

Regards
Descartes
 
Coming from another development environment, it appears that I bang my
head in the wall on very basic matters, so I hope you can give me a
push in the right direction.

The application that I work on will consist of
- a mainform with a usual menu and toolbar and not much more.
- a number of modal data editing forms with various edit controls, an
OK button and a Cancel button
- an instance of a data class containing some 50 fields of various
types.

My question relates to the fact that C# doesn't accept "global"
variables, so the data class can not be instantiated directly in the
namespace.
Where and how would you instantiate the data class so that the editing
forms can access the data?

Quite possibly in the main form - if it's holding the concept of "the
instance being edited". Then pass it to each of the individual editing
forms as you construct them.

Jon
 
Jon said:
Quite possibly in the main form - if it's holding the concept of
"the
instance being edited". Then pass it to each of the individual
editing
forms as you construct them.

Wau! That was a fast answer, Jon, thank you.

Let me ride on this a little further.
I was thinkin of declaring the data class in a separate file (let's
call it MyData.cs) because there will be quite a few getters and
setters and interaction rules between the fields. Just to keep it
separate from the forms.
Well, this of course doesn't prevent me from instantiating the MyData
class in the main form. Right?
MyData myData = new MyData;

And then, to pass myData to the editing forms as I construct them I
would write
MyFirstDataEditor FirstDataEditor = new MyFirstDataEditor(myData)
and in that constructor I would populate the controls with data for
editing.
Then to display the form and get the DialogResult, I would write
if FirstDataEditor.ShowDialog == DialogResult.OK
{
//
}
How should I then (depending on the DialogResult) either store or
discard the edited data.
I think this should be handled in the editing form and not in the main
form.

Regards
Descartes
 
On Sep 8, 11:45 am, "Descartes" <descart (AT) welho (DOT) com> wrote:

How should I then (depending on the DialogResult) either store or
discard the edited data.
I think this should be handled in the editing form and not in the main
form.

Potentially. Of course, it partly depends on whether there might be
multiple forms up at the same time, etc. Discarding changes is rarely
easy, and it's not something I have a lot of experience with. It will
also depend on how you're doing the binding . If you make each dialog
only copy the initial values from the data, and then copy values back
on exit (in the OK situation but not Cancel) then that may make life
easier.

Jon
 
Consider using a SingleTon

public sealed class AppSettings
{

// This class is implementing the Simpleton concept

static readonly AppSettings instance = new AppSettings();

// Explicit static constructor to tell C# compiler

// not to mark type as beforefieldinit

public string SQLServerName = string.Empty;

public string SQLDatabase = string.Empty;

string SQLUserName = string.Empty;

string SQLUserPass = string.Empty;

public int CompanyID = 0;

public int UserID = 0;

AppSettings()

{

SQLUserName = "XXXX";

SQLUserPass = "YYYY";

}

public string ConnectionString

{

get

{

StringBuilder sb = new StringBuilder();

sb.Append("Data Source=" + this.SQLServerName + @";");

sb.Append("Initial Catalog=" + this.SQLDatabase + @";");

sb.Append("User ID=" + this.SQLUserName + @";");

sb.Append("Password=" + this.SQLUserPass + @";");

return sb.ToString();

}

}

public static AppSettings Instance

{

get

{

return instance;

}

}

}



Anywhere in the code you can then refer to it using code like

Console.WriteLine(MyNameSpace.AppLibrary.AppSettings.Instance.ConnectionString)

or

MyNameSpace.AppLibrary.AppSettings.Instance.UserID = 1;

Hope this helps

Dan








On Sep 8, 11:45 am, "Descartes" <descart (AT) welho (DOT) com> wrote:

How should I then (depending on the DialogResult) either store or
discard the edited data.
I think this should be handled in the editing form and not in the main
form.

Potentially. Of course, it partly depends on whether there might be
multiple forms up at the same time, etc. Discarding changes is rarely
easy, and it's not something I have a lot of experience with. It will
also depend on how you're doing the binding . If you make each dialog
only copy the initial values from the data, and then copy values back
on exit (in the OK situation but not Cancel) then that may make life
easier.

Jon
 
Jon said:
On Sep 8, 11:45 am, "Descartes" <descart (AT) welho (DOT) com>
wrote:



Potentially. Of course, it partly depends on whether there might be
multiple forms up at the same time, etc. Discarding changes is
rarely
easy, and it's not something I have a lot of experience with. It
will
also depend on how you're doing the binding . If you make each
dialog
only copy the initial values from the data, and then copy values
back
on exit (in the OK situation but not Cancel) then that may make life
easier.

Jon,

Hmmm. I'm still feeling unsure of how to proceed.

Originally the requirement was to have a "undo" system, at least 20
levels deep, but with the interrelations and dependencies of the data
fields and the difficulties to roll back in this scenario, I managed
to negotiate the solution with modal edit forms, so that, if the user
got distracted or otherwise messed up during editing s/he could just
simply press Cancel in the current view and revert to the state before
that particular edit form was opened.

So, all edit forms are modal and thus only one can be open at a time.

The binding (as I figure it now) would be simply copying relevant
fields from the myData object to edit controls on the edit form and
then on DialogResult.OK copy the content of the controls back to the
myData object (through setters that implements the interdependancy
rules).

The main form should not have to have (IMO) any knowledge about the
MyData structure nor about the edit controls in the edit forms.

I guess my only problem boils down to getting the edit forms to store
modified data if DialogResult is OK.

I tried the following and it compiles without errors and even seems to
work:
In each edit form I write a method DoShow which does the following:
public void DoShow(MyData myData)
{
textBox1.Text = myData.Description;
if (this.ShowDialog() == DialogResult.OK)
{
myData.Description = textBox1.Text;
}
}
(this test just includes one string field of myData)
and it is called from the main form in a menu item click handler:
frmDataEditor DataEditor = new frmDataEditor();
DataEditor.DoShow(myData);

In this way the main form doesn't have to have any knowledge about the
data nor the edit form and the data processing is entirely between the
edit form and the data structure.

Because my experience with C# is practically null, I want to ask you:
Do you see any pitfalls in this solution?
Or is there a better way to achieve the goal?

Regards
Descartes
 
Dan said:
Consider using a SingleTon

Anywhere in the code you can then refer to it using code like
Console.WriteLine(MyNameSpace.AppLibrary.AppSettings.Instance.ConnectionString)
or
MyNameSpace.AppLibrary.AppSettings.Instance.UserID = 1;

Dan,

Thank you for your input!
I had something like that in my mind at some point, although I had no
idea of how to implement it. Now I know thanks to you (just need to
chew it in pieces).

Currently the spec for my project states only one instance of MyData,
so yes, your approach would be good for now, but there's a bell
ringing and telling me that the next level of evolution might include
several instances. Sorry I didn't mention this originally.

Best regards
Descartes
 
On Sep 8, 4:38 pm, "Descartes" <descart (AT) welho (DOT) com> wrote:

Currently the spec for my project states only one instance of MyData,
so yes, your approach would be good for now, but there's a bell
ringing and telling me that the next level of evolution might include
several instances. Sorry I didn't mention this originally.

In addition the singleton pattern makes testing harder, and is
generally a nasty pattern for *almost* everything. There are
exceptions, of course, but in general I prefer to stay away from
singletons.

Jon
 
On Sep 8, 4:38 pm, "Descartes" <descart (AT) welho (DOT) com> wrote:

Currently the spec for my project states only one instance of MyData,
so yes, your approach would be good for now, but there's a bell
ringing and telling me that the next level of evolution might include
several instances. Sorry I didn't mention this originally.

In addition the singleton pattern makes testing harder, and is
generally a nasty pattern for *almost* everything. There are
exceptions, of course, but in general I prefer to stay away from
singletons.

Jon
 
Hmmm. I'm still feeling unsure of how to proceed.

Originally the requirement was to have a "undo" system, at least 20
levels deep, but with the interrelations and dependencies of the data
fields and the difficulties to roll back in this scenario, I managed
to negotiate the solution with modal edit forms, so that, if the user
got distracted or otherwise messed up during editing s/he could just
simply press Cancel in the current view and revert to the state before
that particular edit form was opened.

So, all edit forms are modal and thus only one can be open at a time.

That makes life a lot easier then, at least for the moment.
The binding (as I figure it now) would be simply copying relevant
fields from the myData object to edit controls on the edit form and
then on DialogResult.OK copy the content of the controls back to the
myData object (through setters that implements the interdependancy
rules).
Yup.

The main form should not have to have (IMO) any knowledge about the
MyData structure nor about the edit controls in the edit forms.

That makes sense.
I guess my only problem boils down to getting the edit forms to store
modified data if DialogResult is OK.

I tried the following and it compiles without errors and even seems to
work:
In each edit form I write a method DoShow which does the following:
        public void DoShow(MyData myData)
        {
            textBox1.Text = myData.Description;
            if (this.ShowDialog() == DialogResult.OK)
            {
                myData.Description = textBox1.Text;
            }
        }
(this test just includes one string field of myData)

I would personally make the "copying back" logically part of the OK
button, i.e. as part of its event handler. Or possibly on one of the
Closing/Closed events.

I'd make the "copying forward" part of the construtor - when you
create the form, pass in the MyData and copy it then.
and it is called from the main form in a menu item click handler:
            frmDataEditor DataEditor = new frmDataEditor();
            DataEditor.DoShow(myData);

With my suggested change, this becomes (with proper disposal
handling):

using (Form dialog = new frmDataEditor(myData))
{
dialog.ShowDialog();
}
In this way the main form doesn't have to have any knowledge about the
data nor the edit form and the data processing is entirely between the
edit form and the data structure.

Because my experience with C# is practically null, I want to ask you:
Do you see any pitfalls in this solution?
Or is there a better way to achieve the goal?

The above suggestions are reasonably small matters, but it basically
looks okay. I'd change the name of the type away from "frmDataEditor"
though :)

Jon
 
Jon said:
I would personally make the "copying back" logically part of the OK
button, i.e. as part of its event handler. Or possibly on one of the
Closing/Closed events.

Jon,

Yes, I agree. I was somehow fixed on checking modalresult.
Also because I just recognized that the spec is totally missing
validation of entered data, and I think I better be proactive and
implement at least some validation before allowing the form to be
closed with the OK button. In the help I saw that at least the Closing
event provides an easy way to prevent closure. I will check these
events further.
I'd make the "copying forward" part of the construtor - when you
create the form, pass in the MyData and copy it then.


With my suggested change, this becomes (with proper disposal
handling):

using (Form dialog = new frmDataEditor(myData))
{
dialog.ShowDialog();
}

Thanks for the suggestion. I wasn't aware of the second usage of
"using". That's neat.
The above suggestions are reasonably small matters, but it basically
looks okay. I'd change the name of the type away from
"frmDataEditor"
though :)

OK. I'll try to be creative! ;-)


Thanks Jon, you have been a great help!

Best regards
Descartes
 
Back
Top