ChaoXingAutoClass
【WinUI】基于 XFEstudio 的 XFEWinUIApplication 模板重建的 WinUI 3 课程工作台。二维码和账号密码登录、课程 GridView、章节、播放进度、学习笔记及日志均使用原生 WinUI 控件。网页播放器运行在独立后台进程中,界面不显示课程网站。
关注
0
Fork
0
Star
0
using XFEExtension.NetCore.WinUIHelper.Interface.Services;
using XFEExtension.NetCore.WinUIHelper.Utilities;
using XFEExtension.NetCore.WinUIHelper.Utilities.Helper;
using XFEExtension.NetCore.XFEConsole;
using ChaoXingAutoClass.Profiles.CrossVersionProfiles;
using ChaoXingAutoClass.Profiles.CacheProfiles;
using ChaoXingAutoClass.Utilities;
using ChaoXingAutoClass.Implements.Services;
using ChaoXingAutoClass.Interface.Services;
namespace ChaoXingAutoClass
{
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
public partial class App : Application
{
/// <summary>
/// 主页窗口
/// </summary>
public static MainWindow MainWindow { get; private set; } = null!;
public static ILearningService Learning { get; } = new LearningService();
private bool _closing;
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
XFEConsole.UseXFEConsoleLog();
XFEConsole.Log.LogPath = $@"{AppPath.LogDictionary}\{DateTime.Now:yyyy-M-d_HH-mm-ss}.log";
Console.WriteLine("正在启动应用程序...");
this.InitializeComponent();
AppThemeHelper.Theme = SystemProfile.Theme;
ServiceManager.RegisterGlobalService(Learning);
PageManager.RegisterPage(typeof(AppShellPage));
PageManager.RegisterPage(typeof(MainPage));
PageManager.RegisterPage(typeof(LogViewPage));
PageManager.RegisterPage(typeof(SettingPage));
PageManager.RegisterPage(typeof(CoursePage));
UnhandledException += App_UnhandledException;
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
}
private static void CurrentDomain_UnhandledException(object sender, System.UnhandledExceptionEventArgs e)
{
if (e.ExceptionObject is not Exception ex) return;
Console.WriteLine($"[ERROR]应用程序发生错误:{ex.Message}");
Console.WriteLine($"[TRACE]{ex.StackTrace}");
if (ServiceManager.GetService<IMessageService>() is not { } messageService) return;
messageService.ShowMessage(ex.Message, "发生错误", InfoBarSeverity.Error);
}
private static void App_UnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e)
{
Console.WriteLine($"[ERROR]应用程序发生错误:{e.Message}");
Console.WriteLine($"[TRACE]{e.Exception.StackTrace}");
if (ServiceManager.GetService<IMessageService>() is not { } messageService) return;
messageService.ShowMessage(e.Message, "发生错误", InfoBarSeverity.Error);
e.Handled = true;
}
/// <summary>
/// Invoked when the application is launched.
/// </summary>
/// <param name="args">Details about the launch request and process.</param>
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
MainWindow = new();
MainWindow.AppWindow.Closing += async (_, e) =>
{
if (_closing) return;
e.Cancel = true;
_closing = true;
await Learning.DisposeAsync();
SystemProfile.SaveProfile();
CacheProfile.SaveProfile();
MainWindow.Close();
};
MainWindow.Content = new AppShellPage();
MainWindow.Activate();
AppThemeHelper.MainWindow = MainWindow;
Console.WriteLine("应用程序已启动");
var arguments = Environment.GetCommandLineArgs();
var liveIndex = Array.IndexOf(arguments, "--live-course");
var parallelIndex = Array.IndexOf(arguments, "--live-parallel");
var homeworkIndex = Array.IndexOf(arguments, "--live-homework-course");
if (homeworkIndex >= 0 && arguments.ElementAtOrDefault(homeworkIndex + 1) is { } homeworkCourse)
MainWindow.DispatcherQueue.TryEnqueue(async () =>
{
try
{
var course = (await Learning.RefreshCoursesAsync(CancellationToken.None)).Single(c => c.Title == homeworkCourse);
AppShellPage.Current!.ViewModel.NavigationViewService.NavigateTo<CoursePage>(course);
await CoursePage.Current!.Initialization;
var nameIndex = Array.IndexOf(arguments, "--homework-title");
var name = nameIndex >= 0 ? arguments.ElementAtOrDefault(nameIndex + 1) : null;
var selected = name is null ? null : Learning.GetJob(course)!.Homeworks.Where(h => h.Title == name).Select(h => h.Id).ToHashSet();
if (selected is { Count: 0 }) throw new InvalidOperationException("未找到指定作业。");
await Learning.StartCourseAsync(course, 0, null, true, CancellationToken.None, homeworkIds: selected);
}
catch (Exception error) { Console.WriteLine("[ERROR]" + error); }
});
if (parallelIndex >= 0 && arguments.ElementAtOrDefault(parallelIndex + 1) is { } courseNames)
MainWindow.DispatcherQueue.TryEnqueue(async () =>
{
try
{
var courses = await Learning.RefreshCoursesAsync(CancellationToken.None);
var prefixesIndex = Array.IndexOf(arguments, "--chapter-prefixes");
var prefixes = (prefixesIndex >= 0 ? arguments.ElementAtOrDefault(prefixesIndex + 1) : null)?.Split('|');
var limitIndex = Array.IndexOf(arguments, "--chapter-limit");
var limit = limitIndex >= 0 && int.TryParse(arguments.ElementAtOrDefault(limitIndex + 1), out var n) ? n : 1;
var runs = new List<Task>(); var titles = courseNames.Split('|');
for (var i = 0; i < titles.Length; i++)
{
var course = courses.Single(c => c.Title == titles[i]);
await Learning.OpenCourseAsync(course, CancellationToken.None);
var chapters = Learning.GetJob(course)!.Chapters;
var prefix = prefixes?.ElementAtOrDefault(i);
var start = string.IsNullOrEmpty(prefix) ? 0 : chapters.ToList().FindIndex(c => c.Title.StartsWith(prefix + " ", StringComparison.Ordinal) || c.Title == prefix);
if (start < 0) throw new InvalidOperationException("未找到指定起始章节。");
runs.Add(Learning.StartCourseAsync(course, start, limit, false, CancellationToken.None, includeHomework: false));
}
await Task.WhenAll(runs);
}
catch (Exception error) { Console.WriteLine("[ERROR]" + error); }
});
if (liveIndex >= 0 && arguments.ElementAtOrDefault(liveIndex + 1) is { } title)
MainWindow.DispatcherQueue.TryEnqueue(async () =>
{
try
{
var courses = await Learning.RefreshCoursesAsync(CancellationToken.None);
var course = courses.Single(c => c.Title == title);
AppShellPage.Current!.ViewModel.NavigationViewService.NavigateTo<CoursePage>(course);
await CoursePage.Current!.Initialization;
var startIndex = Array.IndexOf(arguments, "--start-chapter");
if (startIndex >= 0 && arguments.ElementAtOrDefault(startIndex + 1) is { } prefix)
{
var chapterIndex = CoursePage.Current.ViewModel.Chapters.ToList().FindIndex(chapter => chapter.Title.StartsWith(prefix + " ", StringComparison.Ordinal) || chapter.Title == prefix);
if (chapterIndex < 0) throw new InvalidOperationException("未找到指定起始章节。");
CoursePage.Current.ViewModel.SelectedIndex = chapterIndex;
}
CoursePage.Current.ViewModel.ChapterLimit = int.TryParse(arguments.ElementAtOrDefault(liveIndex + 2), out var count) ? count : 3;
CoursePage.Current.ViewModel.ContinueAll = false;
await CoursePage.Current.ViewModel.StartCommand.ExecuteAsync(null);
}
catch (Exception error) { Console.WriteLine("[ERROR]" + error); }
});
}
}
}
using XFEExtension.NetCore.WinUIHelper.Interface.Services;
using XFEExtension.NetCore.WinUIHelper.Utilities;
using XFEExtension.NetCore.WinUIHelper.Utilities.Helper;
using XFEExtension.NetCore.XFEConsole;
using ChaoXingAutoClass.Profiles.CrossVersionProfiles;
using ChaoXingAutoClass.Profiles.CacheProfiles;
using ChaoXingAutoClass.Utilities;
using ChaoXingAutoClass.Implements.Services;
using ChaoXingAutoClass.Interface.Services;
namespace ChaoXingAutoClass
{
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
public partial class App : Application
{
/// <summary>
/// 主页窗口
/// </summary>
public static MainWindow MainWindow { get; private set; } = null!;
public static ILearningService Learning { get; } = new LearningService();
private bool _closing;
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
XFEConsole.UseXFEConsoleLog();
XFEConsole.Log.LogPath = $@"{AppPath.LogDictionary}\{DateTime.Now:yyyy-M-d_HH-mm-ss}.log";
Console.WriteLine("正在启动应用程序...");
this.InitializeComponent();
AppThemeHelper.Theme = SystemProfile.Theme;
ServiceManager.RegisterGlobalService(Learning);
PageManager.RegisterPage(typeof(AppShellPage));
PageManager.RegisterPage(typeof(MainPage));
PageManager.RegisterPage(typeof(LogViewPage));
PageManager.RegisterPage(typeof(SettingPage));
PageManager.RegisterPage(typeof(CoursePage));
UnhandledException += App_UnhandledException;
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
}
private static void CurrentDomain_UnhandledException(object sender, System.UnhandledExceptionEventArgs e)
{
if (e.ExceptionObject is not Exception ex) return;
Console.WriteLine($"[ERROR]应用程序发生错误:{ex.Message}");
Console.WriteLine($"[TRACE]{ex.StackTrace}");
if (ServiceManager.GetService<IMessageService>() is not { } messageService) return;
messageService.ShowMessage(ex.Message, "发生错误", InfoBarSeverity.Error);
}
private static void App_UnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e)
{
Console.WriteLine($"[ERROR]应用程序发生错误:{e.Message}");
Console.WriteLine($"[TRACE]{e.Exception.StackTrace}");
if (ServiceManager.GetService<IMessageService>() is not { } messageService) return;
messageService.ShowMessage(e.Message, "发生错误", InfoBarSeverity.Error);
e.Handled = true;
}
/// <summary>
/// Invoked when the application is launched.
/// </summary>
/// <param name="args">Details about the launch request and process.</param>
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
MainWindow = new();
MainWindow.AppWindow.Closing += async (_, e) =>
{
if (_closing) return;
e.Cancel = true;
_closing = true;
await Learning.DisposeAsync();
SystemProfile.SaveProfile();
CacheProfile.SaveProfile();
MainWindow.Close();
};
MainWindow.Content = new AppShellPage();
MainWindow.Activate();
AppThemeHelper.MainWindow = MainWindow;
Console.WriteLine("应用程序已启动");
var arguments = Environment.GetCommandLineArgs();
var liveIndex = Array.IndexOf(arguments, "--live-course");
var parallelIndex = Array.IndexOf(arguments, "--live-parallel");
var homeworkIndex = Array.IndexOf(arguments, "--live-homework-course");
if (homeworkIndex >= 0 && arguments.ElementAtOrDefault(homeworkIndex + 1) is { } homeworkCourse)
MainWindow.DispatcherQueue.TryEnqueue(async () =>
{
try
{
var course = (await Learning.RefreshCoursesAsync(CancellationToken.None)).Single(c => c.Title == homeworkCourse);
AppShellPage.Current!.ViewModel.NavigationViewService.NavigateTo<CoursePage>(course);
await CoursePage.Current!.Initialization;
var nameIndex = Array.IndexOf(arguments, "--homework-title");
var name = nameIndex >= 0 ? arguments.ElementAtOrDefault(nameIndex + 1) : null;
var selected = name is null ? null : Learning.GetJob(course)!.Homeworks.Where(h => h.Title == name).Select(h => h.Id).ToHashSet();
if (selected is { Count: 0 }) throw new InvalidOperationException("未找到指定作业。");
await Learning.StartCourseAsync(course, 0, null, true, CancellationToken.None, homeworkIds: selected);
}
catch (Exception error) { Console.WriteLine("[ERROR]" + error); }
});
if (parallelIndex >= 0 && arguments.ElementAtOrDefault(parallelIndex + 1) is { } courseNames)
MainWindow.DispatcherQueue.TryEnqueue(async () =>
{
try
{
var courses = await Learning.RefreshCoursesAsync(CancellationToken.None);
var prefixesIndex = Array.IndexOf(arguments, "--chapter-prefixes");
var prefixes = (prefixesIndex >= 0 ? arguments.ElementAtOrDefault(prefixesIndex + 1) : null)?.Split('|');
var limitIndex = Array.IndexOf(arguments, "--chapter-limit");
var limit = limitIndex >= 0 && int.TryParse(arguments.ElementAtOrDefault(limitIndex + 1), out var n) ? n : 1;
var runs = new List<Task>(); var titles = courseNames.Split('|');
for (var i = 0; i < titles.Length; i++)
{
var course = courses.Single(c => c.Title == titles[i]);
await Learning.OpenCourseAsync(course, CancellationToken.None);
var chapters = Learning.GetJob(course)!.Chapters;
var prefix = prefixes?.ElementAtOrDefault(i);
var start = string.IsNullOrEmpty(prefix) ? 0 : chapters.ToList().FindIndex(c => c.Title.StartsWith(prefix + " ", StringComparison.Ordinal) || c.Title == prefix);
if (start < 0) throw new InvalidOperationException("未找到指定起始章节。");
runs.Add(Learning.StartCourseAsync(course, start, limit, false, CancellationToken.None, includeHomework: false));
}
await Task.WhenAll(runs);
}
catch (Exception error) { Console.WriteLine("[ERROR]" + error); }
});
if (liveIndex >= 0 && arguments.ElementAtOrDefault(liveIndex + 1) is { } title)
MainWindow.DispatcherQueue.TryEnqueue(async () =>
{
try
{
var courses = await Learning.RefreshCoursesAsync(CancellationToken.None);
var course = courses.Single(c => c.Title == title);
AppShellPage.Current!.ViewModel.NavigationViewService.NavigateTo<CoursePage>(course);
await CoursePage.Current!.Initialization;
var startIndex = Array.IndexOf(arguments, "--start-chapter");
if (startIndex >= 0 && arguments.ElementAtOrDefault(startIndex + 1) is { } prefix)
{
var chapterIndex = CoursePage.Current.ViewModel.Chapters.ToList().FindIndex(chapter => chapter.Title.StartsWith(prefix + " ", StringComparison.Ordinal) || chapter.Title == prefix);
if (chapterIndex < 0) throw new InvalidOperationException("未找到指定起始章节。");
CoursePage.Current.ViewModel.SelectedIndex = chapterIndex;
}
CoursePage.Current.ViewModel.ChapterLimit = int.TryParse(arguments.ElementAtOrDefault(liveIndex + 2), out var count) ? count : 3;
CoursePage.Current.ViewModel.ContinueAll = false;
await CoursePage.Current.ViewModel.StartCommand.ExecuteAsync(null);
}
catch (Exception error) { Console.WriteLine("[ERROR]" + error); }
});
}
}
}