[英]C# NestedClass Expanded Property to Refresh/Invalidate Control in Design Mode
我试图重现Font类的Nested Property如何在从Properties窗口更改值时使Invalidate()
包含Control,而又不必失去对窗体窗口的关注。 就像您更改Size属性一样,将以匹配的Font Size自动重绘Form窗口。
完整的代码在这篇文章的结尾
测试NestedClass
非常简单,它具有两个Properties,并使用自定义ExpandableObjectConverter
。
ContainerClass
扩展了Control类。 更改NestedClass
值时,它将调用Control.Invalidate()
方法。 NestedClass
属性是通过重写Control.OnPaint()
方法绘制的。
加载到设计器中的结果控件: 初始绘图
直接从NestedClass
父属性更改值会触发重绘: 从父属性更新有效
但是从嵌套属性更改值不会重绘: 从嵌套属性更新不起作用
如果稍后单击“表单”窗口,则会触发Invalidate()
: 单击“表单”窗口后
字体类不需要在设计窗口中额外单击即可重绘控件。 我们可以通过这样的自定义类实现相同的行为吗?
供参考,我已经研究了:
INotifyPropertyChanged
==>这里的问题是,仅在首次添加项目时,容器控件才订阅PropertyChanged事件。 如果我关闭Form [Design]窗口并重新打开它,该事件将不再被订阅。 RefreshProperties.All
或RefreshProperties.Repaint
似乎没有任何作用。 如果所有其他方法都失败了,显然单击表单设计器窗口将解决此问题,但是让我感到困惑的是,内置的.NET类可以做到这一点,而自定义类则不能。 任何建议,不胜感激。
编码 :
//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);
}
}
有趣的是,经过一天没有运气的搜索,最后发布了我的问题,突然我发现另一个线程说的是与答案非常相同的问题->带有答案的主题
只是重申一下,显然INotifyPropertyChanged
仍然是我的问题的答案。 不同之处在于,我之前是在ContainerClass
构造函数上订阅该事件的。 就像是 :
public ContainerClass()
{
NestedClassInstance.PropertyChanged += delegate { this.Invalidate(); };
}
尽管显然需要做的是在NestedClass
设置器主体上订阅或重新订阅该事件。 就像是 :
public class ContainerClass : Control
{
private NestedClass _nestedClassInstance = new NestedClassInstance();
public NestedClass NestedClassInstance
{
get => _nestedClassInstance;
set
{
if (_nestedClassInstance != null)
_nestedClassInstance.PropertyChanged -= delegate { this.Invalidate(); };
_nestedClassInstance = value;
_nestedClassINstance.PropertyChanged += delegate { this.Invalidate(); };
}
}
}
你有它。 另一个编码旅程的结尾。
编辑:实际上,我仍然在考虑这是否是实际的解决方案,因为如果我们引用的是Font类元数据,则它不一定会对属性更改事件使用INotifyProperty
或任何其他种类的EventHandler。 但是无论如何,这是可行的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.