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

C# WPF中修改点数据后如何更新Canvas上的几何Path?

问题解决:修改点数据后Canvas不重新绘制

核心原因

  1. Record类未实现INotifyPropertyChanged:修改X/Y值时,无法通知UI更新绑定关系。
  2. Data类未实现INotifyPropertyChanged:修改Type属性或Records集合内元素变化时,无法触发Binding重新调用Converter生成新的Path数据。
  3. Converter绑定逻辑限制:Path的Data绑定到Data对象,只有当Data对象的属性变化事件触发时,Converter才会重新执行。

解决方案

1. 修改Record类,实现INotifyPropertyChanged

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace WpfAppCharts.Models
{
    public class Record : INotifyPropertyChanged
    {
        private double _x;
        public double X
        {
            get => _x;
            set
            {
                if (_x != value)
                {
                    _x = value;
                    OnPropertyChanged();
                }
            }
        }

        private double _y;
        public double Y
        {
            get => _y;
            set
            {
                if (_y != value)
                {
                    _y = value;
                    OnPropertyChanged();
                }
            }
        }

        public Record(double x, double y)
        {
            X = x;
            Y = y;
        }

        public event PropertyChangedEventHandler? PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string? propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

2. 修改Data类,实现INotifyPropertyChanged并监听Records变化

using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace WpfAppCharts.Models
{
    public class Data : INotifyPropertyChanged
    {
        public enum Types { LINES, SPLINE }

        private string _name = "No name";
        public string Name
        {
            get => _name;
            set
            {
                if (_name != value)
                {
                    _name = value;
                    OnPropertyChanged();
                }
            }
        }

        private int _type = (int)Types.SPLINE;
        public int Type
        {
            get => _type;
            set
            {
                if (_type != value)
                {
                    _type = value;
                    OnPropertyChanged();
                }
            }
        }

        private ObservableCollection<Record> _records;
        public ObservableCollection<Record> Records
        {
            get => _records;
            set
            {
                if (_records != value)
                {
                    UnsubscribeFromRecords(_records);
                    _records = value;
                    SubscribeToRecords(_records);
                    OnPropertyChanged();
                }
            }
        }

        public Data()
        {
            _records = new ObservableCollection<Record>();
            SubscribeToRecords(_records);
        }

        private void SubscribeToRecords(ObservableCollection<Record>? records)
        {
            if (records == null) return;
            foreach (var record in records)
            {
                record.PropertyChanged += Record_PropertyChanged;
            }
            records.CollectionChanged += Records_CollectionChanged;
        }

        private void UnsubscribeFromRecords(ObservableCollection<Record>? records)
        {
            if (records == null) return;
            foreach (var record in records)
            {
                record.PropertyChanged -= Record_PropertyChanged;
            }
            records.CollectionChanged -= Records_CollectionChanged;
        }

        private void Records_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.NewItems != null)
            {
                foreach (Record record in e.NewItems)
                {
                    record.PropertyChanged += Record_PropertyChanged;
                }
            }
            if (e.OldItems != null)
            {
                foreach (Record record in e.OldItems)
                {
                    record.PropertyChanged -= Record_PropertyChanged;
                }
            }
            OnPropertyChanged(nameof(Records));
        }

        private void Record_PropertyChanged(object? sender, PropertyChangedEventArgs e)
        {
            OnPropertyChanged(nameof(Records));
        }

        public event PropertyChangedEventHandler? PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string? propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

3. 优化ViewModel的Datas属性(规范写法)

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using WpfAppCharts.Models;

namespace WpfAppCharts.ViewModels
{
    public class MainWindowViewModel : INotifyPropertyChanged
    {
        private ObservableCollection<Data> _datas;
        public ObservableCollection<Data> Datas
        {
            get => _datas;
            set
            {
                if (_datas != value)
                {
                    _datas = value;
                    OnPropertyChanged();
                }
            }
        }

        public MainWindowViewModel()
        {
            Datas = new ObservableCollection<Data>();

            Datas.Add(new Data());
            Datas[0].Records.Add(new Record(0,     0));
            Datas[0].Records.Add(new Record(20,    0));
            Datas[0].Records.Add(new Record(45,  -47));
            Datas[0].Records.Add(new Record(53,  335));
            Datas[0].Records.Add(new Record(57,   26));
            Datas[0].Records.Add(new Record(62,  387));
            Datas[0].Records.Add(new Record(74,  104));
            Datas[0].Records.Add(new Record(89,    0));
            Datas[0].Records.Add(new Record(95,  100));
            Datas[0].Records.Add(new Record(100,   0));
            Datas[0].Records.Add(new Record(115, 100));
            Datas[0].Records.Add(new Record(120, 200));
            Datas[0].Records.Add(new Record(130, 300));
            Datas[0].Records.Add(new Record(135, 300));
            Datas[0].Records.Add(new Record(140, 200));
            Datas[0].Records.Add(new Record(145,  50));
            Datas[0].Records.Add(new Record(150,  50));
        }

        public event PropertyChangedEventHandler? PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string? propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

效果说明

  • 修改Record的X/Y值时,Record的PropertyChanged事件触发,Data类监听该事件并触发自身Records属性的变化通知,Binding会重新调用Converter生成新的Path Data,Canvas自动重绘。
  • 修改Data的Type属性时,直接触发PropertyChanged,Converter重新执行生成对应类型的路径。
  • 对Records集合进行增删操作时,CollectionChanged事件触发,同样会通知Binding更新Path数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 22:44:49