《MauiProgram.cs》 using Microsoft.Extensions.Logging; using Microsoft.Maui.LifecycleEvents; using CommunityToolkit.Maui; namespace SimpleAudioPlayer { public static class MauiProgram { public static MauiApp CreateMauiApp() { var builder = MauiApp.CreateBuilder(); builder .UseMauiApp() .UseMauiCommunityToolkitMediaElement() .UseMauiCommunityToolkit() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold"); }); #if WINDOWS builder.ConfigureLifecycleEvents(events => { events.AddWindows(windows => windows .OnWindowCreated(window => { //window.SizeChanged += OnSizeChanged; MauiWinUIWindow mauiwin = window as MauiWinUIWindow; if(mauiwin.Title== "PlayList_Window") { //关闭扩展内容 mauiwin.ExtendsContentIntoTitleBar = false; var handle=WinRT.Interop.WindowNative.GetWindowHandle(window); var id=Microsoft.UI.Win32Interop.GetWindowIdFromWindow(handle); var appWindo=Microsoft.UI.Windowing.AppWindow.GetFromWindowId(id); switch(appWindo.Presenter) { case Microsoft.UI.Windowing.OverlappedPresenter overlappedPresenter: overlappedPresenter.SetBorderAndTitleBar(false,false); overlappedPresenter.IsMaximizable = false; overlappedPresenter.IsResizable = false; overlappedPresenter.IsMinimizable = false; break; } } })); }); #endif #if DEBUG builder.Logging.AddDebug(); #endif return builder.Build(); } } } 《App.xaml.cs》 using CommunityToolkit.Maui.Views; using Microsoft.Maui.Controls.PlatformConfiguration; using CommunityToolkit.Maui; using AI_Media; namespace SimpleAudioPlayer { public partial class App : Application { public App() { InitializeComponent(); MainPage = new AppShell(); } #if WINDOWS protected override Window CreateWindow(IActivationState activationState) { var window = base.CreateWindow(activationState); const int newWidth = 500; const int newHeight = 220; window.Width = window.MinimumWidth = window.MaximumWidth = newWidth; window.Height = window.MinimumHeight = window.MaximumHeight = newHeight; window.X = 800; window.Y = 40; window.Destroying += (s, e) => { // Custom logic Application.Current.Quit(); }; return window; } #endif } } 《App.xaml》 《ListPage.xaml.cs》 using AI_Media; using CommunityToolkit.Maui.Core.Extensions; using System.Collections.ObjectModel; namespace SimpleAudioPlayer; public partial class ListPage : ContentPage { private ObservableCollection songdatas = new ObservableCollection(); private AI_Audio audio=AI_Audio.GetInstance(); public ListPage() { InitializeComponent(); } public void InitSongDatas() { foreach (var song in audio.Songlist.Values) { songdatas.Add(SongData.InitBySong(song)); } PlayPage.ItemsSource = songdatas; } private void ContentPage_Loaded(object sender, EventArgs e) { songdatas = new ObservableCollection(); InitSongDatas(); } private void ContentPage_Unloaded(object sender, EventArgs e) { songdatas.Clear(); PlayPage.ItemsSource = songdatas; } } 《Listpage.xaml》 《SongData.cs》 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using AI_Media; namespace SimpleAudioPlayer { class SongData { public string SongName { get; set; } public string SongArtist { get; set; } public string SongPath { get; set; } public StreamImageSource Image { get; set; } public static SongData InitBySong(Song song) { SongData holder = new SongData(); if (song!=null) { holder.SongName = song.SongName; holder.SongArtist = song.SongArtist; holder.SongPath = song.SongPath; holder.Image = song.Image; return holder; } return holder; } } } 《AI_Media.cs》 using TagLib; using System.IO; namespace AI_Media { public class AI_Audio { //begin Singleton model design private static AI_Audio AudioInstance; private static readonly object locker = new object(); private FileOS fileos=FileOS.GetInstance(); private AI_Audio() { } public static AI_Audio GetInstance() { if (AudioInstance == null) { lock (locker) { if (AudioInstance == null) { AudioInstance = new AI_Audio(); } } } return AudioInstance; } //end Singleton model design private Dictionary SongList = new Dictionary(); private List PlayList = new List(); //返回的随机数 private int returnnumber = 0; public int ReturnNumber { get { return returnnumber; } set { returnnumber = value; } } public List Playlist { get { return PlayList; } } public Dictionary Songlist { get { return SongList; } } public void AddSong(string Song_path) { Song song = new Song(); song.InitInstanceByTagLib(Song_path); SongList.Add(song.SongName,song); PlayList.Add(song.SongName); } public void RemoveSong(string Song_path) { Song song = new Song(); song.InitInstanceByTagLib(Song_path); SongList.Remove(song.SongName); } public Song ReturnSong(string Song_path) { Song song = new Song(); song.InitInstanceByTagLib(Song_path); return SongList[song.SongName]; } public void InitAI_Audio() { if(!fileos.IsFileEmpty()) { AddSongByFileOS(fileos.InPut()); } } private void AddSongByFileOS(List list) { foreach(var song in list) { AddSong(song); } } public void SaveSongByFileOs() { foreach (var song in SongList.Values) { fileos.OutPut(song.SongPath); } } public int RandonReturnNumber_PlayList() { Random rd = new Random(); if(Playlist.Count>0) { ReturnNumber = rd.Next(0, Playlist.Count); } return ReturnNumber; } public int SequenceReturnNumber_PlayList() { ReturnNumber++; if (ReturnNumber>Playlist.Count-1) { ReturnNumber = 0; } return ReturnNumber; } } public class Song { private string songname = ""; public string SongName { get { return songname; } set { songname = value; } } private string songArtist = ""; public string SongArtist { get { return songArtist; } set { songArtist = value; } } public string songpath = ""; public string SongPath { get { return songpath; } set { songpath = value; } } private StreamImageSource image=new StreamImageSource(); public StreamImageSource Image { get { return image; } set { image = value; } } public void InitInstanceByTagLib(string Song_Path) { TagLib.File SongFile = TagLib.File.Create(Song_Path); SongName = SongFile.Tag.Title; var name = SongFile.Tag.FirstPerformer; int number = 0; if (name!=null) { number = name.IndexOf(','); } if(number>0) { name = name.Substring(0, number); } SongArtist = name; songpath = Song_Path; //专辑封面 if(SongFile.Tag.Pictures.Length>0) { byte[] pictureBox = SongFile.Tag.Pictures[0].Data.Data; MemoryStream ms = new MemoryStream(pictureBox); var streamImageSource = new StreamImageSource(); streamImageSource.Stream = (token) => Task.FromResult(ms); Image = streamImageSource; } } } public class FileOS { private static FileOS FileOSInstance; private static readonly object locker = new object(); private const string FileName= "SimpleAudioPlayer.txt"; private FileOS() { } public static FileOS GetInstance() { if (FileOSInstance == null) { lock (locker) { if (FileOSInstance == null) { FileOSInstance = new FileOS(); } } } if(!System.IO.File.Exists(FileSystem.AppDataDirectory+FileName)) { System.IO.File.Create(FileSystem.AppDataDirectory + FileName); } return FileOSInstance; } public bool IsFileEmpty() { var holder = new FileInfo(FileSystem.AppDataDirectory + FileName); if(holder.Length > 0) { return false; } else { return true; } } public void OutPut(string message) { StreamWriter writer = new StreamWriter(FileSystem.AppDataDirectory + FileName,true); writer.WriteLine(message); writer.Close(); } public List InPut() { string holder = ""; StreamReader reader=new StreamReader(FileSystem.AppDataDirectory + FileName); holder = reader.ReadToEnd(); reader.Close(); var list = FormatInput(holder); System.IO.File.Delete(FileSystem.AppDataDirectory + FileName); return list; } private List FormatInput(string input) { List result = new List(); string holder = ""; foreach (char line in input) { if(line != '\n') { if(line!='\r') { holder += line; } } else { result.Add(holder); holder = ""; continue; } } return result; } } } 《MainPage.xaml.cs》 using CommunityToolkit.Maui.Core.Primitives; using CommunityToolkit.Maui.Views; using Microsoft.Maui.Controls; using Microsoft.Maui.Controls.PlatformConfiguration; using Microsoft.Maui.LifecycleEvents; using System.ComponentModel; using System.Runtime.CompilerServices; using AI_Media; namespace SimpleAudioPlayer { public partial class MainPage : ContentPage { private int CountPlayMode_Clicked = 0; private int CountPlay_Clicked = -1; private int CountPlayList_Clicked = -1; private Window PlayList_Window; private AI_Audio audio = AI_Audio.GetInstance(); public enum Audio_PlayMode { Repeat=0, Shuffle, Singlerepeat=-1 } private Audio_PlayMode audio_playmode { get { if(CountPlayMode_Clicked == 0) { return Audio_PlayMode.Repeat; } else if(CountPlayMode_Clicked==1) { return Audio_PlayMode.Shuffle; } else if(CountPlayMode_Clicked == -1) { return Audio_PlayMode.Singlerepeat; } return Audio_PlayMode.Repeat; } } public MainPage() { InitializeComponent(); PlayList_Window = new Window(new ListPage()); PlayList_Window.Title = "PlayList_Window"; const int newWidth = 488; const int newHeight = 220; PlayList_Window.Width = PlayList_Window.MinimumWidth = PlayList_Window.MaximumWidth = newWidth; PlayList_Window.Height = PlayList_Window.MinimumHeight = PlayList_Window.MaximumHeight = newHeight; MusicPosition.BindingContext= mediaElement; MusicPosition.SetBinding(Slider.ValueProperty, "Position.TotalMilliseconds"); audio.InitAI_Audio(); } private void Button_Pressed(object sender, EventArgs e) { var button=(ImageButton)sender; ChangeButtonColor(button.ClassId); } private void Button_Released(object sender, EventArgs e) { var button = (ImageButton)sender; ResetButtonColor(button.ClassId); } private void Button_Clicked(object sender, EventArgs e) { if(sender is ImageButton) { var button = (ImageButton)sender; InputMessage(button.ClassId); ChangeButtonColor(button.ClassId); } else if(sender is Slider) { var button= (Slider)sender; InputMessage(button.ClassId); } } private void InputMessage(string message) { if (mediaElement.CurrentState==MediaElementState.None) { if(message=="Play") { LoadSongToMediaElementSource(); } } if(mediaElement.CurrentState != MediaElementState.None) { switch (message) { case "PlayMode": PlayModeState(); break; case "PlayLast": PlayLast_Button(); break; case "Play": PlayState(); break; case "PlayNext": PlayNext_Button(); break; case "VolumeValue": PlayVolumeState(); break; case "PlayList": PlayListState(); break; } } if ( message=="PlayFile") { FileWindow(); } } private async void FileWindow() { try { var result = await FilePicker.PickAsync(PickOptions.Default); if (result != null) { var path = result.FullPath; audio.AddSong(path); } } catch (Exception ex) { // The user canceled or something went wrong } if(mediaElement.CurrentState != MediaElementState.Playing&& mediaElement.CurrentState != MediaElementState.Paused) { LoadSongToMediaElementSource(); } } private void PlayModeState() { CountPlayMode_Clicked++; if (CountPlayMode_Clicked == 0) { PlayMode.Source = ImageSource.FromFile("repeat.png"); } else if(CountPlayMode_Clicked == 1) { PlayMode.Source = ImageSource.FromFile("shuffle.png"); } else if (CountPlayMode_Clicked == 2) { PlayMode.Source = ImageSource.FromFile("singlerepeat.png"); CountPlayMode_Clicked = -1; } SetMediaElementPlayMode(); } private void PlayLast_Button() { //if(audio.Playlist.Count==1) //{ //} //else //{ // LoadSongToMediaElementSource(); //} } private void PlayNext_Button() { //if (audio.Playlist.Count == 1) //{ //} //else //{ // LoadSongToMediaElementSource(); //} } private void PlayState() { CountPlay_Clicked++; if(CountPlay_Clicked == 0) { Play.Source = ImageSource.FromFile("play.png"); PlayMusic(); } else { Play.Source = ImageSource.FromFile("pause.png"); CountPlay_Clicked = -1; PauseMusic(); } } private void PlayVolumeState() { mediaElement.Volume = VolumeValue.Value / 100; } private void PlayListState() { CountPlayList_Clicked++; if( CountPlayList_Clicked == 0) { var mainwindow = this.GetParentWindow(); PlayList_Window.X = mainwindow.X+6; PlayList_Window.Y = mainwindow.Y + 212; Application.Current?.OpenWindow(PlayList_Window); } else { CountPlayList_Clicked = -1; var mainwindow = this.GetParentWindow(); mainwindow.Height /= 2; mainwindow.MaximumHeight = mainwindow.Height; Application.Current?.CloseWindow(PlayList_Window); } } private void ChangeButtonColor(string buttonname) { switch(buttonname) { case "PlayMode": PlayMode.BackgroundColor = Color.FromRgb(9, 244, 253); break; case "PlayLast": PlayLast.BackgroundColor = Color.FromRgb(9, 244, 253); break; case "Play": Play.BackgroundColor = Color.FromRgb(9, 244, 253); break; case "PlayNext": PlayNext.BackgroundColor = Color.FromRgb(9, 244, 253); break; case "PlayList": PlayList.BackgroundColor = Color.FromRgb(9, 244, 253); break; case "PlayFile": PlayFile.BackgroundColor = Color.FromRgb(9, 244, 253); break; } } private void ResetButtonColor(string buttonname) { switch (buttonname) { case "PlayMode": PlayMode.BackgroundColor = Color.FromRgb(255, 255, 255); break; case "PlayLast": PlayLast.BackgroundColor = Color.FromRgb(255, 255, 255); break; case "Play": Play.BackgroundColor = Color.FromRgb(255, 255, 255); break; case "PlayNext": PlayNext.BackgroundColor = Color.FromRgb(255, 255, 255); break; case "PlayList": PlayList.BackgroundColor = Color.FromRgb(255, 255, 255); break; case "PlayFile": PlayFile.BackgroundColor = Color.FromRgb(255, 255, 255); break; } } private void SetMediaElementPlayMode() { switch(audio_playmode) { case Audio_PlayMode.Repeat: mediaElement.ShouldLoopPlayback = false; break; case Audio_PlayMode.Shuffle: mediaElement.ShouldLoopPlayback = false; break; case Audio_PlayMode.Singlerepeat: mediaElement.ShouldLoopPlayback = true; break; } } private void LoadSongToMediaElementSource() { SetMediaElementPlayMode(); if(audio.Songlist.Count>0) { string songname = ""; if(audio_playmode==Audio_PlayMode.Shuffle) { songname = audio.Playlist[audio.RandonReturnNumber_PlayList()]; } else { songname = audio.Playlist[audio.SequenceReturnNumber_PlayList()]; } mediaElement.Source = MediaSource.FromFile(audio.Songlist[songname].songpath); SongName.Text = audio.Songlist[songname].SongName; ArtistName.Text = audio.Songlist[songname].SongArtist; if(audio.Songlist[songname].Image!=null) { Album_Art.Source = audio.Songlist[songname].Image; } else { Album_Art.Source = null; } } } private void PlayMusic() { if (mediaElement.CurrentState == MediaElementState.Stopped ||mediaElement.CurrentState == MediaElementState.Paused) { mediaElement.Play(); string total_duration = mediaElement.Duration.ToString(); if(total_duration!=string.Empty) { Total_Duration_Music.Text = total_duration.Substring(3,5); MusicPosition.Maximum = mediaElement.Duration.TotalMilliseconds; } else { Total_Duration_Music.Text = "Error"; } } } private void PauseMusic() { if(mediaElement.CurrentState == MediaElementState.Playing) { mediaElement.Pause(); } } private void MoveMusicPosition() { mediaElement?.SeekTo(TimeSpan.FromMilliseconds(MusicPosition.Value)); } private async void ContentPage_Unloaded(object? sender, EventArgs e) { // Stop and cleanup MediaElement when we navigate away audio.SaveSongByFileOs(); await Task.Delay(2000); mediaElement.Handler?.DisconnectHandler(); } private void mediaElement_MediaEnded(object sender, EventArgs e) { if (mediaElement.CurrentState == MediaElementState.Stopped) { LoadSongToMediaElementSource(); } } private void mediaElement_MediaOpened(object sender, EventArgs e) { if(mediaElement.CurrentState== MediaElementState.Paused) { if(CountPlay_Clicked == 0) { mediaElement.Play(); } } } private void ContentPage_Loaded(object sender, EventArgs e) { LoadSongToMediaElementSource(); } private void MusicPosition_ValueChanged(object sender, ValueChangedEventArgs e) { MoveMusicPosition(); } } } 《MainPage.cs》