C# NestedClass 在设计模式下扩展了 属性 到 Refresh/Invalidate 控件
C# NestedClass Expanded Property to Refresh/Invalidate Control in Design Mode
我正在尝试重现字体 class 嵌套 属性 如何能够 Invalidate()
当值从属性 window 更改时它包含控件,而不需要失去对表格 window 的关注。
就像如果您更改大小 属性,表单 window 将自动重绘为匹配的字体大小。
完整代码在文末post
测试NestedClass
非常简单,它有两个属性并使用自定义ExpandableObjectConverter
。
ContainerClass
扩展了控件 class。它在 NestedClass
值更改时调用 Control.Invalidate()
方法。 NestedClass
的属性是通过覆盖 Control.OnPaint()
方法绘制的。
加载到设计器时生成的控件:Initial Draw
直接从 NestedClass
父 属性 更改值会触发重绘:Updating from the parent property works
但是从嵌套 属性 更改值不会重绘:Updating from the nested properties doesn't work
如果稍后单击表单 window,将触发 Invalidate()
:After Form window clicked
字体 class 不需要在设计中额外单击 window 即可重绘控件。我们可以用这样的自定义 class 实现同样的行为吗?
作为参考,我已经研究过:
INotifyPropertyChanged
==> 这里的问题是 属性Changed 事件仅在首次添加项目时由容器控件订阅。如果我关闭 Form[Design] window 并重新打开它,将不会再次订阅该事件。
RefreshProperties.All
或 RefreshProperties.Repaint
似乎没有做任何事情。
如果一切都失败了,显然单击表单设计器 window 将解决问题,但令我烦恼的是内置的 .NET class 可以做到这一点,但是自定义 class 不能。非常感谢任何建议。
代码:
//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
setter 主体上订阅或重新订阅该事件。像 :
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 class 元数据,它不一定使用 INotifyProperty
或任何其他类型的 EventHandler 作为 属性 改变了事件。但无论如何,这确实有效。
我正在尝试重现字体 class 嵌套 属性 如何能够 Invalidate()
当值从属性 window 更改时它包含控件,而不需要失去对表格 window 的关注。
就像如果您更改大小 属性,表单 window 将自动重绘为匹配的字体大小。
完整代码在文末post
测试
NestedClass
非常简单,它有两个属性并使用自定义ExpandableObjectConverter
。ContainerClass
扩展了控件 class。它在NestedClass
值更改时调用Control.Invalidate()
方法。NestedClass
的属性是通过覆盖Control.OnPaint()
方法绘制的。
加载到设计器时生成的控件:Initial Draw
直接从 NestedClass
父 属性 更改值会触发重绘:Updating from the parent property works
但是从嵌套 属性 更改值不会重绘:Updating from the nested properties doesn't work
如果稍后单击表单 window,将触发 Invalidate()
:After Form window clicked
字体 class 不需要在设计中额外单击 window 即可重绘控件。我们可以用这样的自定义 class 实现同样的行为吗?
作为参考,我已经研究过:
INotifyPropertyChanged
==> 这里的问题是 属性Changed 事件仅在首次添加项目时由容器控件订阅。如果我关闭 Form[Design] window 并重新打开它,将不会再次订阅该事件。RefreshProperties.All
或RefreshProperties.Repaint
似乎没有做任何事情。
如果一切都失败了,显然单击表单设计器 window 将解决问题,但令我烦恼的是内置的 .NET class 可以做到这一点,但是自定义 class 不能。非常感谢任何建议。
代码:
//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
setter 主体上订阅或重新订阅该事件。像 :
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 class 元数据,它不一定使用 INotifyProperty
或任何其他类型的 EventHandler 作为 属性 改变了事件。但无论如何,这确实有效。