tags:

views:

244

answers:

8

I didn't know what else to title this post, so if you have a better title, feel free to edit.


I have two classes: Form and Field.

Form has a property called Fields that is a List of Field objects.

Form has a property called Prefix.

Field has a method that needs to use the Prefix property of the Form that contains it.

Here is what I am doing now:

class Form
    {
        private List<Field> fields;
        public string Prefix { get; set; }

        public void AddField(Field field)
        {
            field.Form = this;
            fields.Add(field);
        }
    }

    class Field
    {
        public void RenderHtml()
        {
            // render html element with ID attribute
            // prefixed with the parent form's Prefix property
        }
    }

How should I do this?

+6  A: 

I would do this:

class Form
{
    // ...
}

class Field
{
    Form parent;

    public Field(Form parent)
    {
        if (parent == null)
        {
            throw new ArgumentNullException("parent");
        }

        this.parent = parent;
    }

    // now you can reference this.parent to get at its owning form
    // ...
}
bobbymcr
A: 

But to be honest, I like previous answer much :)

Form frm = new Form();
frm.AddField(new Field());    


class Form
        {
            private List<Field> fields;
            public string Prefix { get; set; }
            public string formName;
            public string prefix;

            public void AddField(Field field)
            {
                field.RenderHTML(this.formName,this.prefix);
                fields.Add(field);
            }
        }

        class Field
        {
            public void RenderHTML(string prefix,string id)
            {
                // render html element with ID attribute
                // prefixed with the parent form's Prefix property
            }
        }

OR ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Form frm = new Form();
frm.AddField(new Field(frm.formName,frm.prefix));    


class Form
        {
            private List<Field> fields;
            public string Prefix { get; set; }
            public string formName;
            public string prefix;

            public void AddField(Field field)
            {
                field.RenderHTML(this.formName,this.prefix);
                fields.Add(field);
            }
        }

        class Field
        {
            public void Field(string prefix,string id)
            {
                // render html element with ID attribute
                // prefixed with the parent form's Prefix property
            }
        }
Braveyard
A: 

You could also do this...

  public class Form
  {        
     private Fields fields = new Fields(this);
     public string Prefix { get; set; }       
     public void AddField(Field field)
     {   
      field.Form = this;
      fields.Add(field);
     }
  }

  public class Fields: List<Field>
  {
      public Form Form { get; set; }
      public Fields(Form form)
      { Form = form; }
      public void Add(Field fleld)
      {
          field.Form = Form;
          Add(field);
      }
  }
Charles Bretana
A: 

There's absolutely nothing wrong with your approach. Maybe I would consider to give the Field class a reference to the Prefix property instead of to the this reference, but that's a detail...

Thomas Weller
A: 

you can derive FieldCollection class from Collection, and override base class's InsertItem() method to hook up the parent to the field.

      public class Field 
        { 
              public string Prefix {get;set;}
        }

        public class FieldCollection : System.Collections.ObjectModel.Collection<Field>
        {
              private Form form;

             public FieldCollection(Form f)
             {
                     form = f;
             }


             protected override void InsertItem(int index, Field item)
             {
                     base.InsertItem(index, item);
                     item.Prefix = form.Prefix;
             }
        }

      public class Form
      {
              public string Prefix{get;set;}
              public FieldCollection Fields = new FieldCollection();
      }
Benny
+3  A: 

Pass the prefix to the Field object when you call Render on it. Relying on the Field knowing its parent Form, and that Form having a Prefix property... the amount of dependencies you're setting up is likely to turn into a maintenance nightmare.

If you can't pass the prefix on Field.Render, have a property/set method on the Field to pass in the new Prefix, and write a custom implementation of the setter on the Form to set the Prefix in all of the contained Fields when it's set on the Form.

You could also do some things with events to get a similar dataflow.

kyoryu
A: 

Here is a loosely coupled way of doing this so that the Field has no direct knowledge of the Form and the form sets the prefix by using an event defined on the Field

  public class FieldEventArgs : EventArgs
    {
        public Field Field { get; private set; }
        public FieldEventArgs(Field field)
        {
            Field = field;
        }
    }

    public partial class Field
    {
        public event EventHandler<FieldEventArgs> OnBeforeRender;
        public string Prefix { get;  set; }
         public void Render()
         {
             if (OnBeforeRender != null)
             {
                 OnBeforeRender(this, new FieldEventArgs(this));
                 // render html or do whatever
             }
         }
    }

    public class Form
    {
        private List<Field> Fields;
        public string Prefix { get; set; }

        public void AddField(Field field)
        {
            field.OnBeforeRender += Field_OnBeforeRender;
            Fields.Add(field);
        }

        void Field_OnBeforeRender(object sender, FieldEventArgs e)
        {
            e.Field.Prefix = Prefix;
        }
    }
Abhijeet Patel
A: 

Generally speaking, there are four ways that a child object can obtain the value of a parent object's property, in order of ascending complexity:

  1. Set the value in the child object at construction. Advantage: simple as all get-out. Disadvantages: If the parent property changes, the child gets out of sync; can be a memory hog if you have a lot of child objects, since each one has its own copy of the value.

  2. Maintain a reference to the parent as a property of the child. Advantages: Pretty simple; the property value is current whenever the child asks for it. Disadvantages: Problematic if you disconnect a child from its parent, or assign it to a new one; often a good idea to implement a collection class whose Add and Remove methods manage the parent-child relationship; since child objects retain a reference to the parent object, the parent object can't be disposed until there are no more child objects.

  3. Use an event to dispatch property-changed notifications from the parent to the children. Advantages: Child objects don't need to know anything about the parent's implementation details, or even if there is a parent, Disadvantages: Complicated; can perform poorly if there are a lot of child objects and the parent property changes frequently; initializing the child property can be inelegant; child objects won't get disposed if they don't unsubscribe from the event.

  4. Use composition (e.g. data-binding), so that a third class is responsible for mediating updates between the parent and child. Advantages: Extremely flexible; simple to use, once you understand the composition infrastructure - it's essentially why WPF will one day conquer the earth. Disadvantages: Has all of the disadvantages of approach #3 and then some; generally too complicated to be worth building your own infrastructure if you don't have a really, really good reason (which, generally speaking, you don't); using existing infrastructure (e.g. WinForms or WPF binding objects) requires understanding and implementing a fair amount of plumbing (e.g. INotifyPropertyChanged or, God help you, dependency properties).

Robert Rossney