欢迎光临
我们一直在努力

第二章 WPF 数据实时显示 之INotifyPropertyChanged

WPF 数据实时显示 之INotifyPropertyChanged

针对 WPF 中基于 INotifyPropertyChanged 的数据实时显示,我会聚焦这个核心接口,提供更细致、可直接落地的实现方案,包含单值实时更新和集合数据实时更新两种常见场景(后者是新手容易踩坑的点)。

核心原理回顾

INotifyPropertyChanged 是 WPF 数据绑定的核心接口,它的作用是:当数据模型的属性值发生变化时,主动通知绑定的 UI 控件更新显示。结合后台线程生成实时数据时,无需手动调用 Dispatcher(WPF 4.5+ 已内置线程安全处理),是最符合 MVVM 设计思想的实现方式。

新建项目参考上一章

一、完整实现(单值实时显示)

这是最基础的场景(如实时显示温度、速度、计数器等),代码结构清晰,适合新手入门。

步骤 1:创建数据模型(实现 INotifyPropertyChanged)

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

namespace WpfRealTimeDisplay
{
/// <summary>
/// 实时数据模型(封装需要显示的实时数据)
/// </summary>
public class RealTimeDataModel : INotifyPropertyChanged
{
// 示例:实时数值(如传感器读数、计数器)
private double _realTimeValue;
// 示例:更新时间戳
private string _updateTime;

/// <summary>
/// 实时数值
/// </summary>
public double RealTimeValue
{
get => _realTimeValue;
set
{
// 只有值变化时才触发通知,避免无效更新
if (!_realTimeValue.Equals(value))
{
_realTimeValue = value;
OnPropertyChanged("RealTimeValue"); // 自动获取属性名(CallerMemberName特性)
}
}
}

/// <summary>
/// 更新时间戳
/// </summary>
public string UpdateTime
{
get => _updateTime;
set
{
if (_updateTime != value)
{
_updateTime = value;
OnPropertyChanged("UpdateTime");
}
}
}

// 启动按钮是否可点击
private bool _StartIsEnable = true;

/// <summary>
/// 实时数值
/// </summary>
public bool StartIsEnable
{
get => _StartIsEnable;
set
{
// 只有值变化时才触发通知,避免无效更新
if (!_StartIsEnable.Equals(value))
{
_StartIsEnable = value;
OnPropertyChanged("StartIsEnable"); // 自动获取属性名(CallerMemberName特性)
}
}
}
// 停止按钮是否可点击
private bool _StopIsEnable = false;

/// <summary>
/// 实时数值
/// </summary>
public bool StopIsEnable
{
get => _StopIsEnable;
set
{
// 只有值变化时才触发通知,避免无效更新
if (!_StopIsEnable.Equals(value))
{
_StopIsEnable = value;
OnPropertyChanged("StopIsEnable"); // 自动获取属性名(CallerMemberName特性)
}
}
}

#region INotifyPropertyChanged 实现
// 属性变更事件:WPF绑定系统会监听这个事件来更新UI
public event PropertyChangedEventHandler PropertyChanged;

/// <summary>
/// 触发属性变更通知
/// </summary>
/// <param name="propertyName">属性名(默认自动获取)</param>
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
// 空值保护,避免事件未订阅时的空引用异常
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
}

步骤 2:设计 UI(MainWindow.xaml)

将 UI 控件绑定到数据模型的属性,无需写任何 UI 更新逻辑:

<Window x:Class="_002WPF_INotifyPropertyChanged.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:_002WPF_INotifyPropertyChanged"
mc:Ignorable="d"

Title="实时数据显示(INotifyPropertyChanged)"
Height="350"
Width="450">
<Grid Margin="20">
<StackPanel VerticalAlignment="Center"
HorizontalAlignment="Center">

<!– 显示实时数值 –>
<TextBlock FontSize="32"
FontWeight="Bold"
HorizontalAlignment="Center">

<Run Text="当前值:" />
<Run Text="{Binding RealTimeValue, StringFormat=F2}" /> <!– 保留2位小数 –>
</TextBlock>

<!– 显示更新时间 –>
<TextBlock FontSize="16"
HorizontalAlignment="Center"
Margin="0 20 0 0">

<Run Text="最后更新:" />
<Run Text="{Binding UpdateTime}" />
</TextBlock>

<!– 控制按钮 –>
<StackPanel Orientation="Horizontal"
Margin="0 30 0 0">

<Button Content="开始更新"
Width="100"
Height="40"
Click="StartUpdate_Click"
IsEnabled="{Binding StartIsEnable}"/>

<Button Content="停止更新"
Width="100"
Height="40"
Click="StopUpdate_Click"
IsEnabled="{Binding StopIsEnable}" />

</StackPanel>
</StackPanel>
</Grid>
</Window>

步骤 3:后台线程逻辑(MainWindow.xaml.cs)

后台线程生成实时数据,直接更新数据模型的属性,绑定会自动同步到 UI:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using WpfRealTimeDisplay;

namespace _002WPF_INotifyPropertyChanged
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
// 后台线程
private Thread _updateThread;
// 线程控制标识(优雅启停)
private bool _isUpdating = false;
// 数据模型实例(从UI的DataContext获取)
private RealTimeDataModel _dataModel;

public MainWindow()
{
InitializeComponent();
// 获取DataContext中的数据模型
_dataModel = new RealTimeDataModel();
this.DataContext = _dataModel;
_dataModel.StopIsEnable = false;
_dataModel.StartIsEnable = true;
// 窗口关闭时停止线程,避免内存泄漏
Closing += (s, e) =>
{
_dataModel.StopIsEnable = false;
_dataModel.StartIsEnable = true;
_isUpdating = false;
};
}

/// <summary>
/// 开始更新按钮点击事件
/// </summary>
private void StartUpdate_Click(object sender, RoutedEventArgs e)
{
_isUpdating = true;
_dataModel.StartIsEnable = false;
_dataModel.StopIsEnable = true;

// 创建后台线程(IsBackground=true:窗口关闭时自动终止)
_updateThread = new Thread(UpdateRealTimeData)
{
IsBackground = true,
Name = "RealTimeDataThread"
};
_updateThread.Start();
}

/// <summary>
/// 停止更新按钮点击事件
/// </summary>
private void StopUpdate_Click(object sender, RoutedEventArgs e)
{
_isUpdating = false;
_dataModel.StopIsEnable = false;
_dataModel.StartIsEnable = true;
}

/// <summary>
/// 后台线程:模拟实时数据生成
/// </summary>
private void UpdateRealTimeData()
{
Random random = new Random();
while (_isUpdating)
{
// 1. 模拟实时数据(如传感器、网络接口获取的数据)
double newValue = random.NextDouble() * 100; // 0~100的随机数

// 2. 直接更新数据模型的属性(无需Dispatcher,绑定自动处理线程安全)
_dataModel.RealTimeValue = newValue;
_dataModel.UpdateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"); // 精确到毫秒

// 3. 模拟数据采集间隔(100ms更新一次)
Thread.Sleep(100);
}
}
}
}

二、关键注意事项

  • 线程安全

    • 单值更新:直接修改 INotifyPropertyChanged 属性即可,WPF 自动处理线程安全。
  • 性能优化

    • 高频更新(如 10ms / 次):使用 Dispatcher.BeginInvoke 异步更新,避免 UI 卡顿。
  • 优雅停止线程

    • 始终使用 bool 标识(如 _isUpdating)控制线程循环,避免使用 Thread.Abort()(已过时且不安全)。
    • 后台线程必须设置 IsBackground = true,确保窗口关闭时线程自动终止。
  • 总结

  • INotifyPropertyChanged 是 WPF 实时数据显示的核心,通过属性变更通知实现 UI 与数据的自动同步,无需手动操作 UI 控件。
  • 单值实时更新:直接在后台线程修改模型属性,绑定自动处理线程安全。
  • 后台线程必须通过布尔标识优雅启停,并设置为后台线程避免内存泄漏。
  • 已上传DEMO,供大家学习参考。

    赞(0)
    未经允许不得转载:171主机测评 » 第二章 WPF 数据实时显示 之INotifyPropertyChanged
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址