You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于Monster对象属性动态设置Label的Paint事件颜色?

问题描述

需要根据Monster对象的属性值,在WinForms的Label控件Paint事件中设置绘制椭圆的颜色。现有代码如下:

Monster类定义

public class Monster {
    public int Stat1 {get; set;}
    public int Stat2 {get; set;}
    public int Stat3 {get; set;}
}

现有窗体类代码

namespace Game
{
    public partial class MonsterModel : Form
    {
        public PokedexModel(string pokemon, List<PokeAPI> p)
        {
            InitializeComponent();
        }
        private async void PopulateData(string name)
        {
            Monster m = new Monster();
            m = LoadStats(name);
        }
    }
}

期望的Paint事件逻辑

希望在label1_Paint中根据m.Stat1的值判断椭圆颜色,类似如下逻辑(原代码存在语法和资源泄漏问题):

private void label1_Paint(object sender, PaintEventArgs e)
{
    if (m.Stat1 < 100)
    SolidBrush solidBrush = new SolidBrush(Color.FromArgb(255, 255, 0, 0));
    e.Graphics.FillEllipse(solidBrush, 0, 0, 30, 30);
}

自己想到两种实现方案,但不确定是否有更优解:

方案1:窗体级别实例化Monster对象

namespace Game
{
    public partial class MonsterModel : Form
    {
        Monster m = new Monster();
        public PokedexModel(string pokemon, List<PokeAPI> p)
        {
            InitializeComponent();
        }
        private async void PopulateData(string name)
        {
            m = LoadStats(name);
        }
    }
}

方案2:动态绑定Paint事件

private async void PopulateData(string name)
{
    m = LoadStats(name);
    if (m.Stat1 < 100) {
        label1.Paint += (sender, e) =>
        {
            SolidBrush solidBrush = new SolidBrush(Color.FromArgb(255, 255, 0, 0));
            e.Graphics.FillEllipse(solidBrush, 0, 0, 30, 30);
        };
        label1.Invalidate();
    }
}

方案分析与更优实现

现有方案的不足

  • 方案1:虽然解决了Monster对象的访问问题,但未处理UI刷新逻辑——更新Monster属性后需要手动调用label.Invalidate()触发重绘,否则UI不会更新;另外原Paint事件代码存在语法错误(if语句未加{})和GDI+资源泄漏(未释放Brush)。
  • 方案2:动态绑定Paint事件会导致多次绑定(每次调用PopulateData都会添加新的事件处理器),造成重复绘制,引发性能问题;同时绘制逻辑分散在数据加载方法中,代码耦合度高,维护困难。

更优实现方案

以下实现兼顾代码可维护性、资源管理和UI自动更新:

1. 优化Monster类(可选,实现属性变化通知)

通过INotifyPropertyChanged接口实现属性变化时自动通知UI刷新:

public class Monster : INotifyPropertyChanged
{
    private int _stat1;
    public int Stat1 
    { 
        get => _stat1; 
        set 
        {
            if (_stat1 != value)
            {
                _stat1 = value;
                OnPropertyChanged(nameof(Stat1));
            }
        }
    }

    private int _stat2;
    public int Stat2
    {
        get => _stat2;
        set
        {
            if (_stat2 != value)
            {
                _stat2 = value;
                OnPropertyChanged(nameof(Stat2));
            }
        }
    }

    private int _stat3;
    public int Stat3
    {
        get => _stat3;
        set
        {
            if (_stat3 != value)
            {
                _stat3 = value;
                OnPropertyChanged(nameof(Stat3));
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

2. 优化窗体类代码

namespace Game
{
    public partial class MonsterModel : Form
    {
        private Monster _currentMonster;

        // 修正原代码构造函数名与类名不一致的笔误
        public MonsterModel(string pokemon, List<PokeAPI> p)
        {
            InitializeComponent();
            _currentMonster = new Monster();
            // 绑定属性变化事件,自动刷新对应Label
            _currentMonster.PropertyChanged += CurrentMonster_PropertyChanged;
        }

        private void CurrentMonster_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            switch(e.PropertyName)
            {
                case nameof(Monster.Stat1):
                    label1.Invalidate();
                    break;
                case nameof(Monster.Stat2):
                    label2.Invalidate();
                    break;
                case nameof(Monster.Stat3):
                    label3.Invalidate();
                    break;
            }
        }

        private async void PopulateData(string name)
        {
            // 异步加载数据需使用await(假设LoadStats是异步方法)
            var newMonster = await LoadStats(name);
            // 更新属性,自动触发UI刷新
            _currentMonster.Stat1 = newMonster.Stat1;
            _currentMonster.Stat2 = newMonster.Stat2;
            _currentMonster.Stat3 = newMonster.Stat3;

            // 若未实现INotifyPropertyChanged,可手动刷新所有Label:
            // label1.Invalidate();
            // label2.Invalidate();
            // label3.Invalidate();
        }

        private void label1_Paint(object sender, PaintEventArgs e)
        {
            using (var brush = GetStatBrush(_currentMonster.Stat1))
            {
                e.Graphics.FillEllipse(brush, 0, 0, 30, 30);
            }
        }

        private void label2_Paint(object sender, PaintEventArgs e)
        {
            using (var brush = GetStatBrush(_currentMonster.Stat2))
            {
                e.Graphics.FillEllipse(brush, 0, 0, 30, 30);
            }
        }

        private void label3_Paint(object sender, PaintEventArgs e)
        {
            using (var brush = GetStatBrush(_currentMonster.Stat3))
            {
                e.Graphics.FillEllipse(brush, 0, 0, 30, 30);
            }
        }

        // 提取颜色判断逻辑,复用代码,便于维护
        private SolidBrush GetStatBrush(int statValue)
        {
            if (statValue < 100)
            {
                return new SolidBrush(Color.FromArgb(255, 255, 0, 0));
            }
            else if (statValue < 200)
            {
                return new SolidBrush(Color.FromArgb(255, 0, 255, 0));
            }
            else
            {
                return new SolidBrush(Color.FromArgb(255, 0, 0, 255));
            }
        }
    }
}

方案优势

  • 逻辑集中:绘制逻辑统一在Paint事件和GetStatBrush方法中,代码复用性高,便于后续修改颜色规则。
  • 资源安全:使用using语句管理GDI+资源(Brush),避免内存泄漏。
  • 自动刷新:通过INotifyPropertyChanged实现属性变化时自动刷新对应Label,无需手动调用Invalidate(也支持手动刷新的降级方案)。
  • 避免重复绑定:固定绑定Paint事件,每次绘制都基于当前最新的Monster属性值,不会出现重复绘制问题。
  • 修正笔误:修复了原代码中构造函数名与类名不一致的错误。

内容的提问来源于stack exchange,提问作者CJW

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 12:25:58