属性改变时如何刷新GDI+创建的UserControl

How to refresh UserControl which create by GDI+ when property changes

首先,我的英语不好。 所以如果有语法错误,还请谅解..

我参考了here.

我用 2 个项目创建了一个简单的解决方案。第一个项目(class 库)包含一个通过 GDI+ 绘制 Tank 的自定义控件。第二个项目(windows 表格)是一个测试应用程序。

我想使用 Tank 作为控件,可以显示通过调用 Value 属性 设置的实时值。实现这个我有很多问题。大部分都解决了,但是有个问题

在第二个项目中,如果我开始 Form1 在 Form1 添加 Timer 并设置随机生成的值 属性 以在 timer_tick() 中显示实时值后,我必须在 Form1_Paint 中调用 tank1.Refresh() ().

有两张图片显示了这个问题。 在每一张照片中, 左边是与右边一样以相同方式创建(工作方式相同)的控件,在 Form1_Paint().

中未调用 .Refresh()

picture1

picture2

有没有更好的方法,比如只在 timer_tick() 中调用 Invalidate() 而不是在 Form_Paint() 中调用 tank.Refresh? 我看过一些解释 .Invalidate()、.Refresh()、.Update() 或推荐使用事件的问答,但我不知道哪种方式更好。

为什么当我在 Form1_Paint() 中调用 Invalidate() 时 tank1 没有重新绘制?

我希望有人能理解初学者的痛苦....

这是代码

public class Tank : UserControl
{
    public Tank();

    public float MAX { get; set; }
    public float MIN { get; set; }
    public float Value { get; set; }

    protected override void Dispose(bool disposing);
    protected override void OnPaint(PaintEventArgs e);
}

public partial class Form1 : Form
{
    Random R = new Random();

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Paint(object sender, PaintEventArgs e)
    {
        tank1.Refresh();
        //waterStorageBasin1.Refresh();
    }
    private void button1_Click(object sender, EventArgs e)
    {
        timer1.Start();
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
        tank1.Value = (float)(R.NextDouble() * 10);
        waterStorageBasin1.Value = (float)(R.NextDouble() * 10);

        label1.Text = Math.Round(tank1.Value, 2).ToString();
        label2.Text = Math.Round(waterStorageBasin1.Value, 2).ToString();
        //I want this way
        //Invalidate();
    }
}

Hans Passant 回答说 this.Invalidate() 会更好。
@HansPassant 感谢您的帮助!

    public float Value
    {
        get
        {
            return _tankLevel_Value;
        }
        set
        {
            _tankLevel_Value = value;
            this.Invalidate();
        }
    }