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

在C#中自定义Windows Media Player:实现毫秒级显示与新版外观

解决Visual Studio C#中Windows Media Player毫秒级时间获取与自定义显示问题

核心思路

默认的AxWindowsMediaPlayer控件UI固定,仅支持秒级显示,因此需要:

  1. 使用功能更完整的WMP COM库获取毫秒级时间数据
  2. 自定义UI组件替代默认播放栏,实现毫秒格式的时间显示

具体实现步骤

1. 添加Windows Media Player COM引用

不要依赖工具箱中的旧版AxWindowsMediaPlayer控件,直接添加COM引用以获得完整的WMP API访问权限:

  • 右键项目 → 选择「添加」→「引用」
  • 切换到「COM」标签页,找到并勾选「Windows Media Player」
  • 确认后项目会自动生成Interop.WMPLib.dll引用

2. 获取毫秒级时间数据

WMPLib中的WindowsMediaPlayer类提供了精确到毫秒的时间属性:

  • 当前播放位置:player.Controls.currentPosition(double类型,单位为秒,小数部分即为毫秒,例如123.456表示123秒456毫秒)
  • 媒体总时长:player.currentMedia.duration(同样为double类型,带毫秒精度)

3. 实时更新时间显示

通过定时器定时读取时间数据并格式化显示,同时监听播放状态控制定时器启停:

完整代码示例

using WMPLib;
using System;
using System.Windows.Forms;

namespace WMPMillisecondPlayer
{
    public partial class MainForm : Form
    {
        private WindowsMediaPlayer _player;
        private Timer _timeUpdateTimer;

        public MainForm()
        {
            InitializeComponent();
            InitializePlayer();
            InitializeTimer();
        }

        private void InitializePlayer()
        {
            _player = new WindowsMediaPlayer();
            // 可通过OpenFileDialog让用户选择媒体文件
            // _player.URL = "your-media-file-path.mp3";
            _player.PlayStateChange += OnPlayStateChange;
        }

        private void InitializeTimer()
        {
            _timeUpdateTimer = new Timer
            {
                Interval = 100 // 每100毫秒更新一次,平衡精度与性能
            };
            _timeUpdateTimer.Tick += OnTimeUpdateTick;
        }

        private void OnPlayStateChange(int newState)
        {
            switch ((WMPPlayState)newState)
            {
                case WMPPlayState.wmppsPlaying:
                    _timeUpdateTimer.Start();
                    break;
                case WMPPlayState.wmppsPaused:
                case WMPPlayState.wmppsStopped:
                case WMPPlayState.wmppsClosed:
                    _timeUpdateTimer.Stop();
                    break;
            }
        }

        private void OnTimeUpdateTick(object sender, EventArgs e)
        {
            if (_player.currentMedia == null) return;

            double currentPos = _player.Controls.currentPosition;
            double totalDuration = _player.currentMedia.duration;

            // 格式化为 mm:ss.fff 格式(分:秒.毫秒)
            lblCurrentTime.Text = TimeSpan.FromSeconds(currentPos).ToString(@"mm\:ss\.fff");
            lblTotalTime.Text = TimeSpan.FromSeconds(totalDuration).ToString(@"mm\:ss\.fff");

            // 同步进度条(如果需要)
            progressBar.Maximum = (int)(totalDuration * 1000);
            progressBar.Value = Math.Min((int)(currentPos * 1000), progressBar.Maximum);
        }

        // 播放按钮点击事件
        private void btnPlay_Click(object sender, EventArgs e)
        {
            _player.Controls.play();
        }

        // 暂停按钮点击事件
        private void btnPause_Click(object sender, EventArgs e)
        {
            _player.Controls.pause();
        }

        // 选择媒体文件按钮事件
        private void btnSelectFile_Click(object sender, EventArgs e)
        {
            using (var openFileDialog = new OpenFileDialog())
            {
                openFileDialog.Filter = "媒体文件|*.mp3;*.wav;*.mp4;*.avi";
                if (openFileDialog.ShowDialog() == DialogResult.OK)
                {
                    _player.URL = openFileDialog.FileName;
                }
            }
        }
    }
}

4. 自定义UI布局

  • 隐藏默认的WMP控件(如果使用了的话),改用Label显示格式化后的时间、ProgressBar作为进度条、自定义按钮实现播放/暂停/停止控制
  • 可以通过WinForms的布局工具(如TableLayoutPanel、FlowLayoutPanel)实现类似新版WMP的界面样式

注意事项

  • 处理媒体未加载的情况:在读取currentMedia前需判空,避免空引用异常
  • 定时器间隔:100毫秒的更新频率足够满足毫秒级显示需求,过短的间隔会增加CPU占用
  • 时间格式化:使用TimeSpan.ToString(@"mm\:ss\.fff")时,需通过转义字符保留冒号和点的字面意义

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 19:47:43