繁体   English   中英

C#NestedClass扩展属性以在设计模式下刷新/无效控件

[英]C# NestedClass Expanded Property to Refresh/Invalidate Control in Design Mode

我试图重现Font类的Nested Property如何在从Properties窗口更改值时使Invalidate()包含Control,而又不必失去对窗体窗口的关注。 就像您更改Size属性一样,将以匹配的Font Size自动重绘Form窗口。

完整的代码在这篇文章的结尾

  1. 测试NestedClass非常简单,它具有两个Properties,并使用自定义ExpandableObjectConverter

  2. ContainerClass扩展了Control类。 更改NestedClass值时,它将调用Control.Invalidate()方法。 NestedClass属性是通过重写Control.OnPaint()方法绘制的。

加载到设计器中的结果控件: 初始绘图

直接从NestedClass父属性更改值会触发重绘: 从父属性更新有效

但是从嵌套属性更改值不会重绘: 从嵌套属性更新不起作用

如果稍后单击“表单”窗口,则会触发Invalidate()单击“表单”窗口后

字体类不需要在设计窗口中额外单击即可重绘控件。 我们可以通过这样的自定义类实现相同的行为吗?

供参考,我已经研究了:

  1. INotifyPropertyChanged ==>这里的问题是,仅在首次添加项目时,容器控件才订阅PropertyChanged事件。 如果我关闭Form [Design]窗口并重新打开它,该事件将不再被订阅。
  2. RefreshProperties.AllRefreshProperties.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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM