tags:

views:

79

answers:

3

I have a MDI application. One of the forms needs to be able to have multiple instances of it open at the same time. Within this app I have a Program class. For each instance of the form I need to place a Program object into each form. This is working, however, everytime data is changed it changes all of the Program objects within all of the multiple instances of the form.

Here is the Program class (very simple class for now):

public class Program
{
string strProgramCode;

public Program()
{ }

public string ProgramCode
{
    get { return strProgramCode; }
    set { strProgramCode = value; }
}

}

Here is the code for the form:

            frmWeeklyIndividualBudgets tfrmWeeklyIndividualBudgets = new frmWeeklyIndividualBudgets();
            tfrmWeeklyIndividualBudgets.Program = this.Program;
            tfrmWeeklyIndividualBudgets.Text = this.Program.ProgramCode.ToString() + " Weekly Budget";
            this.CheckMdiChildren(tfrmWeeklyIndividualBudgets);

Here is the CheckMdiChildren method:

private void CheckMdiChildren(Form form)
{ 

    foreach (Form frm in this.MdiChildren)
    {
        if (frm.GetType() == form.GetType())
        {
            if (frm.GetType().ToString() == "IPAMFinancial_Program_Financial_Breakdown.frmWeeklyIndividualBudgets")
            {
                frmWeeklyIndividualBudgets tfrm = (frmWeeklyIndividualBudgets)frm;
                if (tfrm.Program.ProgramCode == this.Program.ProgramCode)
                {
                    frm.Focus();
                    return;
                }
            }
            else
            {
                frm.Focus();
                return;
            }
        }
    }

    form.MdiParent = this;
    form.Show();
}
+3  A: 

I strongly suspect the problem is that you've got one Program object, which all the forms refer to. (That's certainly what the code looks like.) Give each form a new Program instead, when you create the form.

For example:

frmWeeklyIndividualBudgets tfrmWeeklyIndividualBudgets = 
    new frmWeeklyIndividualBudgets();

// Give the new form a new Program instance
tfrmWeeklyIndividualBudgets.Program = new Program();
tfrmWeeklyIndividualBudgets.Text = this.Program.ProgramCode.ToString() 
    + " Weekly Budget";
this.CheckMdiChildren(tfrmWeeklyIndividualBudgets);

If you want the new form to get a Program based on the existing one, you should implement a Clone method in Program, and do:

tfrmWeeklyIndividualBudgets.Program = this.Program.Clone();
Jon Skeet
So if I perform a Clone off of the parentForm Program then when i change the values, the values wont change within the childForm?
mattgcon
You would need to implement the Clone() method, and presumably it would create a _new_ instance of the Program class and copy the properties from the original to the clone (again, you have to write this so it can do whatever you want).
Coding Gorilla
A: 

In .NET, objects are passed by reference (i.e. references to the object are passed around, while the single object sits in one place, used by all the variables referring to it). This means that when you do this:

tfrmWeeklyIndividualBudgets.Program = this.Program;

You have two "Program" variables using the exact same object.

To avoid this, you'll need to construct a new version of the program object to assign. Sometimes, people create a Clone() method to handle this.

tfrmWeeklyIndividualBudgets.Program = new Program { set properties here };

// Or

tfrmWeeklyIndividualBudgets.Program = this.Program.Clone();
John Fisher
No, objects aren't passed by reference. References are passed by value. Objects aren't passed at all.
Jon Skeet
@Jon Skeet: I guess you could argue terminology, but essentially a pointer is a reference. So, when you pass the pointer to an object (a reference) which allows the user to access the object, you have "passed the object by (using a) reference".
John Fisher
@John: No, you haven't. There's a big difference in terms of the effect of changing parameter values. Please read http://pobox.com/~skeet/csharp/parameters.html where I go into it in rather more detail.
Jon Skeet
@Jon Skeet: It looks like I accidentally tread upon an item you feel strongly about. English being what it is, and me not trying to make the point that you're making, my statement is not innaccurate - just imprecise. Your statement that "objects aren't passed at all" would lead people to believe that you simply can't use objects as parameters. Of course, you don't believe that. But it does illustrate how we could both pick at specific words, totally ignoring the overall intent.
John Fisher
@John: English may often have imprecise words, but computer science is usually pretty clear. And no, you can't use objects as parameters. The value of a parameter is never an object - it's either a reference or a value type value. You may wonder why I'm being so picky about this - and the answer is because I've seen so many people get confused by it. If you explain this correctly and precisely, it may end up a bit wordier but it can help to straighten out people's mental models. If you go for the imprecise (and yes, inaccurate) route, then you get into a world of confusion.
Jon Skeet
So if you've already said that "objects are passed by reference" what do you do when you talk about the `ref` modifier? I've seen plenty of people claim that it makes no difference when applied to reference types - which is entirely wrong, and is based on the fallacy that "objects are passed by reference" by default. If you start off with the accurate model of variables and their values, objects and references, then pass by reference is *much* easier to understand. I'm not being picky for the sake of it - I'm being picky because it *does* make a difference.
Jon Skeet
@Jon: For years before C# came around, "passing by reference" had a meaning that was quite compatible with the usage I intended. C# came along and added "reference parameters" (using the "ref" keyword). If a distinction needs to be made, I believe that's the way to go about it.The problem here is really that "reference" is over-used. We have "ref parameters" which allow the variable passed to the method to be modified, and we have object references which give access to objects.I don't object to high levels of detail, but I do object to writing doctoral theses when a simple answer works.
John Fisher
@John: I suspect it didn't *actually* have that meaning - would you say that Java passes by reference as well, for example? Computer science has a reasonably precise definition of pass-by-reference semantics in terms of Lvalues etc - which C#'s default calling convention does *not* obey. It obeys the pass-by-value semantics precisely (by default). The problem is that the "simple answer" *doesn't* work. It causes problems. As I say, I have seen this lead to huge amounts of confusion in the past - wouldn't you rather avoid confusing people? If so, why not just use the correct terminology?
Jon Skeet
@Jon: I don't program in Java, so I wouldn't know how it works. But, the pre-.NET versions of Visual Basic used "pass by reference" the way I did. Again, I'm not confusing people - the similar wording/overloaded terms confuses people. (I prefer to refer to "ref parameters" as "reference parameters", not "passed by reference", since that had a pre-existing meaning.) Also, I'm of the opinion that this sort of confusion isn't all bad. The people who learn as a result have likely learned much more about the topic than someone who never had to deal with the confusion around this issue.
John Fisher
@Jon: Also, on the topic of confusion. I don't believe that I would have confused anyone. If someone had read my answer and been unclear, we would have done what people have been doing for millenia - discussing things to make sure we understood each other. My statement may have caused confusion in a medium without two-way communication, but that is not how StackOverflow works. Neither is StackOverflow a place where a person reads only one brief answer to develop a comprehensive understanding of C#'s argument-passing semantics.
John Fisher
@John: What makes you think that someone who was confused would *know* they were confused? People read similarly inaccurate (or over-general) statements like "value type values go on the stack" and happily go around with a misunderstanding of memory for years. I've seen it happen time and time again - particularly on this topic. However, I don't think I'm making any progress here - if you insist on using inaccurate terminology which (as I've said) has confused people time and time again in the past, then I can't stop you. At least you should now be aware of it though.
Jon Skeet
@Jon: I don't insist on using inaccurate terminology, but I would like you to acknowledge that I wasn't trying to achieve the level of detail that you are apparently demanding. The next time I discuss this, I will be much more careful (especially if you might be watching).
John Fisher
@John: Well, I will *always* pick up on the claim that C# passes by reference (by default) - because it's such a common cause of confusion. I acknowledge that it's often fine to be imprecise - when the topic of conversation is something else (e.g. how many times something is being called) it's fine to be slightly sloppy: "we're passing this string to the method" or whatever. However, in this case the *topic of conversation itself* is effectively how C# treats references and objects. In that situation, I think it makes sense to be precise.
Jon Skeet
@Jon: Sounds good.
John Fisher
A: 

You should create a ProgramFactory object, and call some type of method on that object to create a new Program object each time you need one. You appear to be reusing the same instance.

GalacticJello