jeudi 1 septembre 2016

How can I initialize only properties that have a value?

I have a class CustomControl which inherits from System.Windows.Forms.Control. I will also create a new class named GraphicsData which will have all the graphical information about my CustomControl (I need this because it's easier to serialize the data for saving it in a DB, json, etc.)

The CustomControl object will get the GraphicsData at the initialization(in the constructor) and I want it to get all the properties that have a value in GraphicsData (sometimes I don't want to initialize all of the properties from GraphicsData and I want them to remain the default from System.Windows.Forms.Control class).

The problem is that most of the proprierties are not nullable and I cannot check if they are null so I can't do a simple:

customControl.BackColor = graphicsData.BackColor.HasValue ? graphicsData.BackColor.Value : BackColor;

I can of course work this around if I create my own Nullable class but this got really ugly and hard to understand the code. Also, it is very hard to add a new property when needed.

Now, what I did and I think this is a much cleaner way is the following:

GraphicsData class:

public class GraphicsData : INotifyPropertyChanged
{
    private readonly List<string> _initializedProperties = new List<string>();
    public List<string> InitializedProperties { get { return _initializedProperties; } }

    public event PropertyChangedEventHandler PropertyChanged;

    private Size _size;
    private Point _location;
    private AnchorStyles _anchor;
    private Color _backColor;
    private Image _backgroundImage;
    private Cursor _cursor;
    private Font _font;
    private Color _foreColor;
    private bool _enabled;
    private bool _visible;

    public Size Size
    {
        get { return _size; }
        set
        {
            _size = value;
            OnPropertyChanged("Size");
        }
    }

    public Point Location
    {
        get { return _location; }
        set
        {
            _location = value;
            OnPropertyChanged("Location");
        }
    }

    public AnchorStyles Anchor
    {
        get { return _anchor; }
        set
        {
            _anchor = value;
            OnPropertyChanged("Anchor");
        }
    }

    public Color BackColor
    {
        get { return _backColor; }
        set
        {
            _backColor = value;
            OnPropertyChanged("BackColor");
        }
    }

    public Image BackgroundImage
    {
        get { return _backgroundImage; }
        set
        {
            _backgroundImage = value;
            OnPropertyChanged("BackgroundImage");
        }
    }

    public Cursor Cursor
    {
        get { return _cursor; }
        set
        {
            _cursor = value;
            OnPropertyChanged("Cursor");
        }
    }

    public Font Font
    {
        get { return _font; }
        set
        {
            _font = value;
            OnPropertyChanged("Font");
        }
    }

    public Color ForeColor
    {
        get { return _foreColor; }
        set
        {
            _foreColor = value;
            OnPropertyChanged("ForeColor");
        }
    }

    public bool Enabled
    {
        get { return _enabled; }
        set
        {
            _enabled = value;
            OnPropertyChanged("Enabled");
        }
    }

    public bool Visible
    {
        get { return _visible; }
        set
        {
            _visible = value;
            OnPropertyChanged("Visible");
        }
    }

    protected void OnPropertyChanged(string propertyName)
    {
        if (!_initializedProperties.Contains(propertyName))
            _initializedProperties.Add(propertyName);

        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

And in my custom control I have a method:

public void LoadGraphics()
    {
        var initializedProperties = graphics.InitializedProperties;
        foreach (string propertyName in initializedProperties)
        {
            var value = graphics.GetType()
                                .GetProperty(propertyName)
                                .GetValue(graphics, null);
            _customControl.GetType()
                          .GetProperty(propertyName)
                          .SetValue(_customControl, value, null);
        }
    }

Basically, I created a List named InitializedProperties and in the properties "set" I add the property in the list. After that, using reflection in my CustomControl, I can load all the initialized properties.

I implemented the INotifyPropertyChanged because I also want to change the customControl properties each time a property is changed in GraphicsData.

Is this the proper way to do what I want ? I don't think the reflection code is that readable and I am concerned about the performance.





Aucun commentaire:

Enregistrer un commentaire