WPF实现一个播放音乐和视频的应用

一、项目准备

  1. ​创建WPF项目​

    • 在Visual Studio中新建WPF App (.NET Framework)项目
    • 命名为"MediaPlayerApp"
  2. ​添加必要的NuGet包​

    Install-Package Microsoft.WindowsAPICodePack-Shell
    Install-Package TagLibSharp

二、界面设计

1. 主窗口XAML (MainWindow.xaml)


    
        
        
            

三、代码实现

1. 主窗口代码 (MainWindow.xaml.cs)

using Microsoft.WindowsAPICodePack.Dialogs;
using System;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading;

namespace MediaPlayerApp
{
    public partial class MainWindow : Window
    {
        private DispatcherTimer timelineSliderTimer;
        private bool isDraggingSlider = false;
        private bool isFullscreen = false;

        public MainWindow()
        {
            InitializeComponent();
            InitializeTimer();
            LoadMediaTypes();
        }

        private void InitializeTimer()
        {
            timelineSliderTimer = new DispatcherTimer();
            timelineSliderTimer.Interval = TimeSpan.FromMilliseconds(100);
            timelineSliderTimer.Tick += TimelineSliderTimer_Tick;
        }

        private void LoadMediaTypes()
        {
            mediaTypeCombo.Items.Add("音频");
            mediaTypeCombo.Items.Add("视频");
            mediaTypeCombo.SelectedIndex = 0;
        }

        private void btnOpen_Click(object sender, RoutedEventArgs e)
        {
            var dialog = new CommonOpenFileDialog
            {
                Title = "选择媒体文件",
                IsFolderPicker = false,
                Multiselect = false
            };

            if (mediaTypeCombo.SelectedIndex == 0) // 音频
            {
                dialog.Filters.Add(new CommonFileDialogFilter("音频文件", "*.mp3;*.wav;*.aac;*.flac"));
            }
            else // 视频
            {
                dialog.Filters.Add(new CommonFileDialogFilter("视频文件", "*.mp4;*.avi;*.mkv;*.wmv"));
            }

            if (dialog.ShowDialog() == CommonFileDialogResult.Ok)
            {
                txtMediaPath.Text = dialog.FileName;
                PlayMedia(dialog.FileName);
            }
        }

        private void PlayMedia(string filePath)
        {
            if (!File.Exists(filePath))
            {
                MessageBox.Show("文件不存在!", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }

            mediaElement.Source = new Uri(filePath);
            mediaElement.Play();

            // 更新时间显示
            UpdateTimeDisplay();

            // 显示/隐藏视频控制区
            if (mediaElement.NaturalVideoHeight > 0)
            {
                videoControls.Visibility = Visibility.Visible;
            }
            else
            {
                videoControls.Visibility = Visibility.Collapsed;
            }
        }

        private void btnPlayPause_Click(object sender, RoutedEventArgs e)
        {
            if (mediaElement.CanPause)
            {
                if (mediaElement.CurrentState == System.Windows.Media.MediaElementState.Paused || 
                    mediaElement.CurrentState == System.Windows.Media.MediaElementState.Stopped)
                {
                    mediaElement.Play();
                    btnPlayPause.Content = "❚❚";
                }
                else
                {
                    mediaElement.Pause();
                    btnPlayPause.Content = "▶";
                }
            }
        }

        private void btnStop_Click(object sender, RoutedEventArgs e)
        {
            mediaElement.Stop();
            btnPlayPause.Content = "▶";
            timelineSlider.Value = 0;
            txtTime.Text = "00:00:00 / 00:00:00";
        }

        private void timelineSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e)
        {
            if (!isDraggingSlider)
            {
                isDraggingSlider = true;
                mediaElement.Position = TimeSpan.FromSeconds(timelineSlider.Value);
                isDraggingSlider = false;
            }
        }

        private void timelineSliderTimer_Tick(object sender, EventArgs e)
        {
            if (!isDraggingSlider)
            {
                timelineSlider.Value = mediaElement.Position.TotalSeconds;
            }
        }

        private void TimelineSliderTimer_Tick(object sender, EventArgs e)
        {
            if (!isDraggingSlider && mediaElement.NaturalDuration.HasTimeSpan)
            {
                timelineSlider.Maximum = mediaElement.NaturalDuration.TimeSpan.TotalSeconds;
                timelineSlider.Value = mediaElement.Position.TotalSeconds;

                UpdateTimeDisplay();
            }
        }

        private void UpdateTimeDisplay()
        {
            if (mediaElement.NaturalDuration.HasTimeSpan)
            {
                txtTime.Text = $"{mediaElement.Position.ToString(@"hh\:mm\:ss")} / {mediaElement.NaturalDuration.TimeSpan.ToString(@"hh\:mm\:ss")}";
            }
            else
            {
                txtTime.Text = "00:00:00 / --:--:--";
            }
        }

        private void volumeSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e)
        {
            mediaElement.Volume = volumeSlider.Value / 100;
        }

        private void mediaElement_MediaOpened(object sender, RoutedEventArgs e)
        {
            timelineSlider.Maximum = mediaElement.NaturalDuration.TimeSpan.TotalSeconds;
            timelineSliderTimer.Start();
            
            // 根据媒体类型设置默认音量
            if (mediaTypeCombo.SelectedIndex == 0) // 音频
            {
                volumeSlider.Value = 70;
            }
            else // 视频
            {
                volumeSlider.Value = 50;
            }
        }

        private void mediaElement_MediaEnded(object sender, RoutedEventArgs e)
        {
            btnPlayPause.Content = "▶";
            timelineSlider.Value = 0;
            txtTime.Text = "00:00:00 / 00:00:00";
        }

        private void fullscreenToggle_Click(object sender, RoutedEventArgs e)
        {
            if (isFullscreen)
            {
                this.WindowState = WindowState.Normal;
                this.WindowStyle = WindowStyle.SingleBorderWindow;
                fullscreenToggle.Content = "全屏";
            }
            else
            {
                this.WindowState = WindowState.Maximized;
                this.WindowStyle = WindowStyle.None;
                fullscreenToggle.Content = "退出";
            }
            isFullscreen = !isFullscreen;
        }

        private void mediaElement_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            // 视频大小自适应
            if (mediaElement.NaturalVideoHeight > 0)
            {
                double aspectRatio = mediaElement.NaturalVideoWidth / (double)mediaElement.NaturalVideoHeight;
                mediaElement.Width = this.ActualWidth - 20; // 减去边距
                mediaElement.Height = mediaElement.Width / aspectRatio;
            }
        }
    }
}

2. 添加必要的引用

在项目中添加以下引用:

  • PresentationCore
  • WindowsBase
  • Microsoft.WindowsAPICodePack.Shell
  • TagLibSharp (用于获取媒体元数据)

四、功能扩展

1. 添加播放列表功能

 
  


 
  
// 在MainWindow.xaml.cs中添加
private void AddToPlaylist_Click(object sender, RoutedEventArgs e)
{
    var dialog = new CommonOpenFileDialog
    {
        Title = "选择媒体文件",
        IsFolderPicker = false,
        Multiselect = true
    };

    if (mediaTypeCombo.SelectedIndex == 0) // 音频
    {
        dialog.Filters.Add(new CommonFileDialogFilter("音频文件", "*.mp3;*.wav;*.aac;*.flac"));
    }
    else // 视频
    {
        dialog.Filters.Add(new CommonFileDialogFilter("视频文件", "*.mp4;*.avi;*.mkv;*.wmv"));
    }

    if (dialog.ShowDialog() == CommonFileDialogResult.Ok)
    {
        foreach (var file in dialog.FileNames)
        {
            playlist.Items.Add(file);
        }
    }
}

private void playlist_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (playlist.SelectedItem != null)
    {
        PlayMedia(playlist.SelectedItem.ToString());
    }
}

2. 添加媒体元数据显示

 
  


    
    
        
        
    
 
  
// 在PlayMedia方法中添加
try
{
    var file = TagLib.File.Create(filePath);
    albumArt.Source = GetAlbumArt(file);
    txtTitle.Text = file.Tag.Title ?? Path.GetFileNameWithoutExtension(filePath);
    txtArtist.Text = file.Tag.Performers.Length > 0 ? file.Tag.Performers[0] : "未知艺术家";
}
catch
{
    // 如果无法读取元数据,使用默认值
    albumArt.Source = null;
    txtTitle.Text = Path.GetFileNameWithoutExtension(filePath);
    txtArtist.Text = "未知艺术家";
}

// 添加获取专辑封面的方法
private ImageSource GetAlbumArt(TagLib.File file)
{
    if (file.Tag.Pictures.Length > 0)
    {
        var ms = new MemoryStream(file.Tag.Pictures[0].Data.Data);
        return BitmapFrame.Create(ms);
    }
    return null;
}

五、样式美化

1. 添加资源字典 (Styles.xaml)

 
  

    
    

    
    

    
    

    
    

2. 在App.xaml中引用

 
  

    
        
    

六、高级功能

1. 添加均衡器

 
  


    
        
        
        
    
 
  
// 在MainWindow.xaml.cs中添加
private void InitializeEqualizer()
{
    // 这里需要使用音频处理库如NAudio来实现实际的均衡器效果
    // 示例代码仅显示UI
}

// 在构造函数中调用
InitializeEqualizer();

2. 添加播放速度控制

 
  


    
    
    
 
  
// 在MainWindow.xaml.cs中添加
private void playbackSpeed_ValueChanged(object sender, RoutedPropertyChangedEventArgs e)
{
    // 注意:MediaElement不支持直接改变播放速度
    // 可以使用MediaElement的Rate属性(仅部分系统支持)
    try
    {
        mediaElement.SpeedRatio = playbackSpeed.Value;
    }
    catch
    {
        MessageBox.Show("您的系统不支持播放速度调整", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
    }
}

七、打包发布

1. 创建安装程序

使用Visual Studio Installer Projects扩展创建安装包:

  1. 安装扩展:Visual Studio Installer Projects
  2. 新建项目:Setup Project
  3. 添加主程序文件和依赖项
  4. 配置快捷方式和文件关联

2. 发布为单文件

使用.NET Core的发布功能:

 
  
dotnet publish -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true

八、总结

这个WPF媒体播放器实现了以下功能:

  1. 播放本地音频和视频文件
  2. 播放控制(播放/暂停/停止)
  3. 进度条和时间显示
  4. 音量控制
  5. 播放列表管理
  6. 媒体元数据显示
  7. 全屏模式
  8. 美观的UI界面

可以根据需要进一步扩展功能,如:

  • 网络流媒体支持
  • 字幕加载
  • 播放历史记录
  • 云同步播放列表
  • 更高级的音频处理(均衡器、音效)

这个项目适合作为学习WPF和多媒体开发的良好起点,同时也可以作为实际应用的基础版本。

你可能感兴趣的:(WPF,wpf,音视频,C#)