rick
rick

Reputation: 577

How to use a Property which depends the value of another property?

There is a Custom Property which depends on the value of other System Property to be initialized properly in WinForms.

Let me give you an example. Let's create a class WhateverButton: Button with a Custom Property called MyExampleProperty and system Control Property let's use this.Height, which came from the Size of the Control.

public class WhateverButton : Button
{
   // member
   private int m_myExampleProperty;

   // constructor
   public WhateverButton() {
      m_myExampleProperty = 1;
   }
    
    // Property
    public int MyExampleProperty
    {
      get => m_myExampleProperty;
      set
      {
        m_myExampleProperty= value > (this.Height / 2F) ? 1 : value;
      }
    }

    // Every time the Size change, update the property
    protected override void OnSizeChanged (EventArgs e)
    {
      base.OnSizeChanged (e);

      m_myExampleProperty  = m_myExampleProperty > this.Height / 2F ? 1: m_myExampleProperty;

    }

}

Add the WhateverButton in the Form (with a size greater than default). WinForms generates the element (button, label, textbox and etc) by alphabetical order such as:

      this.buttonWhatever.Location = new System.Drawing.Point (413, 57); // L
      this.buttonWhatever.Margin = new System.Windows.Forms.Padding (3, 4, 3, 4); // M
      this.buttonWhatever.MyExampleProperty= 30; // M
      ... // Others Properties
      this.buttonWhatever.Name = "myElement"; // N
      this.buttonWhatever.Size = new System.Drawing.Size (50, 80); // S
      this.buttonWhatever.Text = "My Element"; // T

After changing the Property MyExampleProperty value by Form UI, it seems it works, but after saving the form (Ctrl+S) the property returns to 1.

Debugging is possible to figure it out that every time the Form is saved all the elements are created again by that order. When the time of the MyExampleProperty arrives the Size property is not created yet, which will assume the default Height and Width and of course, the value of the property will be wrong. If I just rename the MyExampleProperty to any other name that will be placed after the Size property in this example, it will work. Maybe I am missing something that I have no idea to search.

Upvotes: 0

Views: 2011

Answers (1)

Sweeper
Sweeper

Reputation: 273540

The problem with your property is that if the control is not the right height at the time of setting the property, the value passed to the setter is lost forever.

Therefore, in the setter, you should always assign value to the backing field, and check the height in the getter:

public int MyExampleProperty
{
  get => m_myExampleProperty > (this.Height / 2F) ? 1 : m_myExampleProperty;
  set
  {
    m_myExampleProperty = value;
  }
}

This way, you don't even need to handle the SizeChanged event!

Or even better, write this as two properties:

public int MyExampleProperty { get; set; }
public int MyExamplePropertyThatChangesWithSize => 
    MyExampleProperty > (this.Height / 2F) ? 1 : MyExampleProperty;

...because properties where you don't get the value that you just set is quite unexpected and can be confusing.

Upvotes: 1

Related Questions