WPF中TextBox数值变更时OxyPlot图表不刷新的问题排查
问题:WPF MVVM模式下OxyPlot图表无法随TextBox输入值刷新
基于MVVM模式开发的WPF应用,包含TextBox、TextBlock和OxyPlot的PlotView控件。TextBox与TextBlock绑定的Finish值可以正常同步,但输入新值后图表无法刷新。已使用INotifyPropertyChanged、ObservableCollection和InvalidatePlot(true),但问题仍存在。
ViewModel代码
public class ViewModel : INotifyPropertyChanged { private PlotModel? plotModel; public PlotModel? PlotModel { get => plotModel; set { plotModel = value; OnPropertyChanged("PlotModel"); } } public LineSeries lineSeries { get; set; } private ObservableCollection<DataPoint>? _BestFitness; public ObservableCollection<DataPoint>? BestFitness { get => _BestFitness; set { _BestFitness = value; OnPropertyChanged(nameof(BestFitness)); } } public ViewModel() { PlotModel = new PlotModel(); plot_curve(); } private double _finish; public double Finish { get => _finish; set { _finish = value; OnPropertyChanged("Finish"); OnPropertyChanged("PlotModel"); PlotModel?.InvalidatePlot(true); } } public void plot_curve() { Model model = new(); PlotModel?.Series.Clear(); lineSeries = new(); MessageBox.Show(Finish.ToString()); BestFitness = new(); for (double x = 0.0; x <= 5.0; x += 0.1) BestFitness.Add(new DataPoint(x, model.curve(x, 2))); BestFitness.Add(new DataPoint(5.1, model.curve(Finish, 2))); lineSeries.ItemsSource = BestFitness; PlotModel?.Series.Add(lineSeries); PlotModel?.InvalidatePlot(true); } public event PropertyChangedEventHandler? PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); }
XAML代码
<oxy:PlotView BorderBrush="Black" x:Name="Plot1" Model="{Binding PlotModel}" Margin="10,10,10,90" BorderThickness="1,1,1,1" Opacity="1.0" Grid.ColumnSpan="3" FontSize="14" Grid.Column="3"> </oxy:PlotView> <TextBox Grid.Column="2" HorizontalAlignment="Left" Margin="10,57,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" Text="{Binding Finish, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/> <TextBlock Grid.Column="2" HorizontalAlignment="Left" Margin="10,77,0,0" Text="{Binding Finish}"/>
解决方案
核心问题
当前代码的关键缺陷是:Finish值变更时,仅触发了PlotModel的属性通知和刷新调用,但没有更新图表绑定的数据源。plot_curve方法只在ViewModel构造时执行一次,后续Finish变化时没有重新计算数据点。
修改步骤
在
Finish的setter中添加数据更新逻辑
修改Finish属性的setter,调用数据更新方法,确保值变化时同步更新图表数据:private double _finish; public double Finish { get => _finish; set { _finish = value; OnPropertyChanged(nameof(Finish)); UpdatePlotData(); // 新增:触发数据更新 } }新增数据更新方法
可以选择两种方式更新数据:- 方式一:仅更新目标数据点(性能更优)
public void UpdatePlotData() { if (BestFitness == null || PlotModel == null || lineSeries == null) return; // 找到x=5.1的目标数据点 var targetPoint = BestFitness.LastOrDefault(p => p.X.Equals(5.1)); if (targetPoint != null) { // DataPoint是值类型,需先移除再添加新值 BestFitness.Remove(targetPoint); } // 添加/更新Finish对应的新数据点 BestFitness.Add(new DataPoint(5.1, new Model().curve(Finish, 2))); PlotModel.InvalidatePlot(true); } - 方式二:重新生成所有数据(逻辑更简单)
public void UpdatePlotData() { if (PlotModel == null) return; Model model = new(); PlotModel.Series.Clear(); lineSeries = new LineSeries(); BestFitness = new ObservableCollection<DataPoint>(); // 重新生成基础数据点 for (double x = 0.0; x <= 5.0; x += 0.1) BestFitness.Add(new DataPoint(x, model.curve(x, 2))); // 添加Finish对应的数据点 BestFitness.Add(new DataPoint(5.1, model.curve(Finish, 2))); lineSeries.ItemsSource = BestFitness; PlotModel.Series.Add(lineSeries); PlotModel.InvalidatePlot(true); }
- 方式一:仅更新目标数据点(性能更优)
优化
OnPropertyChanged参数
将硬编码的属性名改为nameof,避免字符串拼写错误:public PlotModel? PlotModel { get => plotModel; set { plotModel = value; OnPropertyChanged(nameof(PlotModel)); } }
内容的提问来源于stack exchange,提问作者ac3gbsha7
相关产品推荐
相关产品推荐

