I'm trying to reproduce how Font class Nested Property is able to Invalidate() it's containing Control when the values are changed from the Properties window, without a need to lost focus on the form window.
Like if you change the Size property, the Form window will be automatically redrawn with a matching Font Size.
The complete code is at the end of this post
The test
NestedClassis very simple which has two Properties and uses a customExpandableObjectConverter.The
ContainerClassextends Control class. It invokesControl.Invalidate()method when theNestedClassvalue is changed. Properties of theNestedClassare drawn by overridingControl.OnPaint()method.
Resulting Control when loaded to the Designer : Initial Draw
Changing the values directly from the NestedClass parent property triggers the redraw : Updating from the parent property works
But changing the values from the nested property, does not redraw : Updating from the nested properties doesn't work
If later the Form window is clicked, Invalidate() is triggered : After Form window clicked
Font class does not require extra click in the design window in order to redraw the control. Can we achieve this same behavior with a custom class like this?
For reference I've already looked into :
INotifyPropertyChanged==> Problem here is that the PropertyChanged event is only subscribed by the container Control when the item is first added. If I close the Form[Design] window and reopens it, the event will not be subscribed again.RefreshProperties.AllorRefreshProperties.Repaintdoes not seems to do anything.
If all else fails, obviously clicking on the form designer window will solve the problem, but it bugs me that a built-in .NET class can do this, but a custom class cannot. Any suggestions are greatly appreciated.
The Code :
//The Nested Class
[TypeConverter(typeof(NestedClassTypeConverter))]
public class NestedClass
{
[NotifyParentProperty(true)]
public string CountryName { get; set; } = "Japan";
[NotifyParentProperty(true)]
public string Capital { get; set; } = "Tokyo";
}
//The Container Class
public class ContainerClass : Control
{
private NestedClass _country = new NestedClass();
[Category("_Data")]
public NestedClass Country
{
get => _country;
set
{
_country = value;
this.Invalidate();
}
}
protected override Size DefaultSize => new Size(100, 100);
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
using (Brush b = new SolidBrush(Color.Black))
{
e.Graphics.DrawString(Country.CountryName, this.Font, b, new PointF(10, 10));
e.Graphics.DrawString(Country.Capital, this.Font, b, new PointF(10, 50));
}
}
}
//TypeConverter for that fancy Expandable properties
public class NestedClassTypeConverter : ExpandableObjectConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string)
{
string[] v = ((string)value).Split(',');
return new NestedClass
{
CountryName = v[0],
Capital = v[1]
};
}
return base.ConvertFrom(context, culture, value);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(NestedClass))
{
return true;
}
return base.CanConvertTo(context, destinationType);
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (destinationType == typeof(string))
{
return ((NestedClass)value).CountryName + "," + ((NestedClass)value).Capital;
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
It's funny that after a day of searching without any luck, and finally posted my question, suddenly I found another thread which speaks the very same issue with answer --> Thread with the answer
Just to reiterate, apparently
INotifyPropertyChangedis still the answer to my problem. The difference is that I was subscribing to the event on theContainerClassconstructor before. Something like :While apparently what needs to done is to subscribe or resubscribe to that event on the
NestedClasssetter body. Something like :There you have it. End of another coding journey.
EDIT : Actually I'm still thinking whether this is the actual solution or not, since if we're referring to Font class metadata, it does not necessarily uses
INotifyPropertyor any other sort of EventHandler for a property changed event. But anyway, this does the trick.