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

为何定时器无法动态显示文件大小?附WPF代码求改进建议

定时器不工作的核心问题及解决办法

1. 跨线程UI更新限制

如果用的是System.Timers.Timer,它的Elapsed事件是在后台线程触发的,而WPF的UI元素只能在创建它的主线程(Dispatcher线程)更新,直接操作fileSize TextBlock会触发线程异常,表现出来就是定时器“没生效”。

解决办法:
在Timer_Elapsed事件里通过Dispatcher.Invoke切换到UI线程更新:

private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
    if (_targetFileInfo != null)
    {
        _targetFileInfo.Refresh(); // 刷新文件信息,避免读取缓存值
        Dispatcher.Invoke(() => 
        {
            fileSize.Text = $"当前文件大小: {_targetFileInfo.Length / 1024.0 / 1024:F2} MB";
        });
    }
}

2. 定时器配置与生命周期问题

  • 别把定时器声明为局部变量,要作为窗口类的字段,防止被垃圾回收
  • 确保设置了Interval = 500(对应0.5秒),并且调用了Start()方法

示例正确的定时器初始化:

private System.Timers.Timer _updateTimer;
private FileInfo _targetFileInfo;

private void CreateTimer(FileInfo fileInfo)
{
    _targetFileInfo = fileInfo;
    _updateTimer = new System.Timers.Timer(500);
    _updateTimer.Elapsed += Timer_Elapsed;
    _updateTimer.AutoReset = true; // 自动重复触发事件
    _updateTimer.Start();
}

3. 文件信息未刷新

每次获取文件大小前必须调用fileInfo.Refresh(),否则FileInfo会缓存初始大小,导致显示的数值一直不变。


代码优化通用建议

1. 多线程写入的线程安全

25个任务同时写同一个文件,必须加锁保护写入操作,避免内容错乱或IO异常:

private static readonly object _writeLock = new object();

public static void WriteToFile(string filePath, byte[] content)
{
    lock (_writeLock)
    {
        using (var fs = new FileStream(filePath, FileMode.Append, FileAccess.Write, FileShare.None))
        {
            fs.Write(content, 0, content.Length);
        }
    }
}

2. 改用WPF原生DispatcherTimer

比起System.Timers.Timer,DispatcherTimer的事件直接在UI线程触发,无需手动切换线程,更适合WPF的UI更新场景:

private DispatcherTimer _dispatcherTimer;
private FileInfo _targetFileInfo;

private void CreateTimer(FileInfo fileInfo)
{
    _targetFileInfo = fileInfo;
    _dispatcherTimer = new DispatcherTimer();
    _dispatcherTimer.Interval = TimeSpan.FromMilliseconds(500);
    _dispatcherTimer.Tick += DispatcherTimer_Tick;
    _dispatcherTimer.Start();
}

private void DispatcherTimer_Tick(object sender, EventArgs e)
{
    _targetFileInfo.Refresh();
    fileSize.Text = $"当前文件大小: {_targetFileInfo.Length / 1024.0 / 1024:F2} MB";
}

3. 资源释放与内存泄漏预防

窗口关闭时停止并释放定时器,避免内存泄漏:

protected override void OnClosed(EventArgs e)
{
    base.OnClosed(e);
    _updateTimer?.Stop();
    _updateTimer?.Dispose();
    // 若是DispatcherTimer:
    _dispatcherTimer?.Stop();
}

4. 任务的可取消性

如果需要中途停止写入,用CancellationTokenSource管理任务取消,避免强制终止导致文件损坏:

private CancellationTokenSource _cts;

private async void btnGo_Click(object sender, RoutedEventArgs e)
{
    _cts = new CancellationTokenSource();
    var tasks = new List<Task>();
    for (int i = 0; i < 25; i++)
    {
        tasks.Add(Task.Run(() => WriteLoop(_targetFileInfo, _cts.Token), _cts.Token));
    }
    await Task.WhenAll(tasks);
}

private void btnStop_Click(object sender, RoutedEventArgs e)
{
    _cts?.Cancel();
}

private void WriteLoop(FileInfo fileInfo, CancellationToken token)
{
    while (fileInfo.Length < targetSize && !token.IsCancellationRequested)
    {
        var randomContent = GenerateRandomContent();
        FileIO.WriteToFile(fileInfo.FullName, randomContent);
        fileInfo.Refresh();
    }
}

5. 代码结构规范

  • 保持UI层和业务逻辑分离,文件操作逻辑全部封装在FileIO类中
  • 字段用下划线开头的驼峰式命名(如_targetFileInfo),方法和属性用帕斯卡式命名
  • 拆分UI事件中的复杂逻辑,避免大段代码堆积在事件处理方法里

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 15:25:49