C# WPF中修改点数据后如何更新Canvas上的几何Path?
问题解决:修改点数据后Canvas不重新绘制
核心原因
- Record类未实现INotifyPropertyChanged:修改X/Y值时,无法通知UI更新绑定关系。
- Data类未实现INotifyPropertyChanged:修改Type属性或Records集合内元素变化时,无法触发Binding重新调用Converter生成新的Path数据。
- 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
相关产品推荐
相关产品推荐

