From 8c3bbff9adf33cca23a6b974fc1d19cd560b225e Mon Sep 17 00:00:00 2001 From: Dynesshely Date: Sat, 9 Sep 2023 20:10:50 +0800 Subject: [PATCH 01/35] =?UTF-8?q?=F0=9F=93=9D=20Chore(.csproj):=20Updated?= =?UTF-8?q?=20dotnet=20to=207,=20references.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ClassScheduler.Runner/ClassScheduler.Runner.csproj | 2 +- ClassScheduler.WPF/ClassScheduler.WPF.csproj | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ClassScheduler.Runner/ClassScheduler.Runner.csproj b/ClassScheduler.Runner/ClassScheduler.Runner.csproj index 217e22a..0a11da4 100644 --- a/ClassScheduler.Runner/ClassScheduler.Runner.csproj +++ b/ClassScheduler.Runner/ClassScheduler.Runner.csproj @@ -2,7 +2,7 @@ WinExe - net6.0-windows + net7.0-windows enable true diff --git a/ClassScheduler.WPF/ClassScheduler.WPF.csproj b/ClassScheduler.WPF/ClassScheduler.WPF.csproj index 2931c01..6d0d6e8 100644 --- a/ClassScheduler.WPF/ClassScheduler.WPF.csproj +++ b/ClassScheduler.WPF/ClassScheduler.WPF.csproj @@ -2,7 +2,7 @@ Library - net6.0-windows + net7.0-windows enable true null @@ -11,7 +11,7 @@ - + From f36ad465c86b326dc981835fb62726f45b8ec16e Mon Sep 17 00:00:00 2001 From: Dynesshely Date: Sat, 9 Sep 2023 20:34:20 +0800 Subject: [PATCH 02/35] =?UTF-8?q?=F0=9F=92=BE=20Feat:=20Init=20data=20and?= =?UTF-8?q?=20models.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ClassScheduler.WPF/Data/Classes.cs | 46 +++++++++++++++++++ ClassScheduler.WPF/Models/ClassModel.cs | 19 ++++++++ ClassScheduler.WPF/Models/TeacherModel.cs | 10 ++++ ClassScheduler.WPF/Models/Types/RepeatType.cs | 13 ++++++ 4 files changed, 88 insertions(+) create mode 100644 ClassScheduler.WPF/Data/Classes.cs create mode 100644 ClassScheduler.WPF/Models/ClassModel.cs create mode 100644 ClassScheduler.WPF/Models/TeacherModel.cs create mode 100644 ClassScheduler.WPF/Models/Types/RepeatType.cs diff --git a/ClassScheduler.WPF/Data/Classes.cs b/ClassScheduler.WPF/Data/Classes.cs new file mode 100644 index 0000000..f41fe84 --- /dev/null +++ b/ClassScheduler.WPF/Data/Classes.cs @@ -0,0 +1,46 @@ +using ClassScheduler.WPF.Models; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.Json; + +namespace ClassScheduler.WPF.Data; + +public class Classes +{ + public string? Name { get; set; } + + public List ClassesList { get; set; } = new(); +} + +public static class ClassesExtensions +{ + public static void Save( + this Classes classes, + string path, + Action? optionsProcessor = null) + { + var options = new JsonSerializerOptions() + { + IncludeFields = true, + WriteIndented = true, + }; + optionsProcessor?.Invoke(options); + + var json = JsonSerializer.Serialize(classes); + File.WriteAllText(path, json); + } + + public static Classes? Load( + this string path, + Action? optionsProcessor = null) + { + var options = new JsonSerializerOptions(); + optionsProcessor?.Invoke(options); + + var json = File.ReadAllText(path); + var classes = JsonSerializer.Deserialize(json); + + return classes; + } +} diff --git a/ClassScheduler.WPF/Models/ClassModel.cs b/ClassScheduler.WPF/Models/ClassModel.cs new file mode 100644 index 0000000..0fa72f7 --- /dev/null +++ b/ClassScheduler.WPF/Models/ClassModel.cs @@ -0,0 +1,19 @@ +using System; +using ClassScheduler.WPF.Models.Types; + +namespace ClassScheduler.WPF.Models; + +public class ClassModel +{ + public string? Name { get; set; } + + public TeacherModel? Teacher { get; set; } + + public TimeSpan? Duration { get; set; } + + public DateTime? BeginTime { get; set; } + + public DateTime? EndTime { get; set; } + + public RepeatType RepeatType { get; set; } = RepeatType.NoRepeat; +} diff --git a/ClassScheduler.WPF/Models/TeacherModel.cs b/ClassScheduler.WPF/Models/TeacherModel.cs new file mode 100644 index 0000000..441fbbe --- /dev/null +++ b/ClassScheduler.WPF/Models/TeacherModel.cs @@ -0,0 +1,10 @@ +namespace ClassScheduler.WPF.Models; + +public class TeacherModel +{ + public string? Name { get; set; } + + public string? Description { get; set; } + + public string? TeachRange { get; set; } +} diff --git a/ClassScheduler.WPF/Models/Types/RepeatType.cs b/ClassScheduler.WPF/Models/Types/RepeatType.cs new file mode 100644 index 0000000..0133b99 --- /dev/null +++ b/ClassScheduler.WPF/Models/Types/RepeatType.cs @@ -0,0 +1,13 @@ +namespace ClassScheduler.WPF.Models.Types; + +public enum RepeatType +{ + NoRepeat = 0, + EverySecond = 1, + EveryMinute = 2, + EveryHour = 3, + EveryDay = 4, + EveryWeek = 5, + EveryMonth = 6, + EveryYear = 7, +} From 149fea6354542878b5b12ec7d13cfa1ac0bd3eed Mon Sep 17 00:00:00 2001 From: Dynesshely Date: Sat, 9 Sep 2023 20:36:11 +0800 Subject: [PATCH 03/35] =?UTF-8?q?=F0=9F=93=9D=20Chore(KitX):=20Removed=20s?= =?UTF-8?q?truct=20json=20files,=20waiting=20new=20KitX=20SDK=20(Crequency?= =?UTF-8?q?/KitX#228).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ClassScheduler.WPF/LoaderStruct.json | 14 -------- ClassScheduler.WPF/PluginStruct.json | 50 ---------------------------- 2 files changed, 64 deletions(-) delete mode 100644 ClassScheduler.WPF/LoaderStruct.json delete mode 100644 ClassScheduler.WPF/PluginStruct.json diff --git a/ClassScheduler.WPF/LoaderStruct.json b/ClassScheduler.WPF/LoaderStruct.json deleted file mode 100644 index e1844fd..0000000 --- a/ClassScheduler.WPF/LoaderStruct.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "SelfLoad": false, - "LoaderName": "KitX.Loader.WPF.Core", - "LoaderVersion": "v1.0.0", - "LoaderLanguage": "CSharp", - "LoaderFramework": "WPF.Core", - "LoaderRunType": 2, - "SupportOS": [ - 10 - ], - "Tags": { - "LoaderStartupArguments": "" - } -} diff --git a/ClassScheduler.WPF/PluginStruct.json b/ClassScheduler.WPF/PluginStruct.json deleted file mode 100644 index 04ed9cd..0000000 --- a/ClassScheduler.WPF/PluginStruct.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "Name": "DeskTopPlayer", - "Version": "v1.0.0", - "DisplayName": { - "zh-cn": "桌面课表", - "en-us": "Desktop Chart and Player" - }, - "AuthorName": "StarInk", - "PublisherName": "Crequency", - "AuthorLink": "https://github.com/StardustSeemsInk", - "PublisherLink": "https://www.catrol.cn", - "SimpleDescription": { - "zh-cn": "\u7B80\u5355\u63CF\u8FF0", - "en-us": "SimpleDescription" - }, - "ComplexDescription": { - "zh-cn": "\u590D\u6742\u63CF\u8FF0", - "en-us": "ComplexDescription" - }, - "TotalDescriptionInMarkdown": { - "zh-cn": "Markdown \u8BED\u6CD5\u5B8C\u6574\u63CF\u8FF0", - "en-us": "TotalDescriptionInMarkdown" - }, - "IconInBase64": "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", - "PublishDate": "2022-12-02T13:07:20.2964575+08:00", - "LastUpdateDate": "2022-12-02T13:07:20.3127733+08:00", - "IsMarketVersion": false, - "Tags": {}, - "Functions": [ - { - "Name": "FunctionName", - "DisplayNames": { - "zh-cn": "\u529F\u80FD\u663E\u793A\u540D\u79F0", - "en-us": "DisplayNames" - }, - "Parameters": { - "ParameterName": { - "zh-cn": "\u53C2\u6570\u663E\u793A\u540D\u79F0", - "en-us": "Parameter Display Name" - } - }, - "ParametersType": [ - "string" - ], - "HasAppendParameters": false, - "ReturnValueType": "void" - } - ], - "RootStartupFileName": "ClassScheduler.WPF.dll" -} \ No newline at end of file From 268c22bb4e32da59bb8c46a6abe2a4b3fbac9a0e Mon Sep 17 00:00:00 2001 From: Dynesshely Date: Sat, 9 Sep 2023 20:47:35 +0800 Subject: [PATCH 04/35] =?UTF-8?q?=F0=9F=93=9D=20Chore:=20Import=20`Common.?= =?UTF-8?q?BasicHelper`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ClassScheduler.WPF/ClassScheduler.WPF.csproj | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ClassScheduler.WPF/ClassScheduler.WPF.csproj b/ClassScheduler.WPF/ClassScheduler.WPF.csproj index 6d0d6e8..f238403 100644 --- a/ClassScheduler.WPF/ClassScheduler.WPF.csproj +++ b/ClassScheduler.WPF/ClassScheduler.WPF.csproj @@ -11,6 +11,7 @@ + @@ -21,10 +22,6 @@ - - - - Always From 0f94c2742555936424a9c79e171dea5a739e1d35 Mon Sep 17 00:00:00 2001 From: Dynesshely Date: Sat, 9 Sep 2023 20:49:37 +0800 Subject: [PATCH 05/35] =?UTF-8?q?=F0=9F=92=BE=20Feat:=20Clean,=20including?= =?UTF-8?q?=20@StardustSeemsInk=20's=20works=20on=20KitX=20connection=20(I?= =?UTF-8?q?'m=20wondering=20better=20way=20for=20KitX=20function=20auto=20?= =?UTF-8?q?fetch).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ClassScheduler.Runner/App.xaml.cs | 20 +-- ClassScheduler.WPF/Controller.cs | 194 +------------------------- ClassScheduler.WPF/Data/GlobalData.cs | 8 ++ ClassScheduler.WPF/Global.cs | 6 - 4 files changed, 19 insertions(+), 209 deletions(-) create mode 100644 ClassScheduler.WPF/Data/GlobalData.cs delete mode 100644 ClassScheduler.WPF/Global.cs diff --git a/ClassScheduler.Runner/App.xaml.cs b/ClassScheduler.Runner/App.xaml.cs index 96b460d..1410ff1 100644 --- a/ClassScheduler.Runner/App.xaml.cs +++ b/ClassScheduler.Runner/App.xaml.cs @@ -6,16 +6,8 @@ namespace ClassScheduler.Runner; -/// -/// Interaction logic for App.xaml -/// public partial class App : Application { - /// - /// 启动事件 - /// - /// 事件发送者 - /// 启动参数 private void Application_Startup(object sender, StartupEventArgs e) { try @@ -24,8 +16,12 @@ private void Application_Startup(object sender, StartupEventArgs e) } catch (Exception o) { - MessageBox.Show(o.Message, "Loader Error", - MessageBoxButton.OK, MessageBoxImage.Error); + MessageBox.Show( + o.Message, + "Loader Error", + MessageBoxButton.OK, + MessageBoxImage.Error + ); Console.WriteLine(o.Message); @@ -33,10 +29,6 @@ private void Application_Startup(object sender, StartupEventArgs e) } } - /// - /// 加载插件 - /// - /// 插件路径 private static void LoadPlugin(string path) { if (File.Exists(path)) diff --git a/ClassScheduler.WPF/Controller.cs b/ClassScheduler.WPF/Controller.cs index f7363e8..53c6fab 100644 --- a/ClassScheduler.WPF/Controller.cs +++ b/ClassScheduler.WPF/Controller.cs @@ -1,4 +1,5 @@ -using KitX.Contract.CSharp; +using ClassScheduler.WPF.Data; +using KitX.Contract.CSharp; using KitX.Web.Rules; using System; using System.Collections.Generic; @@ -30,200 +31,16 @@ public void End() mainwin.WinExit(); } - #region 声明函数 - private Function ssv = new() - { - Name = "SetSoundVolume", - DisplayNames = new Dictionary() - { - { "zh-cn", "设置音量" }, - { "en-us", "Set Sound Volume" } - }, - Parameters = new Dictionary>() - { - { - "volume", - new Dictionary() - { - { "zh-cn", "音量" }, - { "en-us", "Volume" } - } - } - }, - ParametersType = new List() - { - "double" - }, - HasAppendParameters = false, - ReturnValueType = "void" - }; - - private Function cm = new() - { - Name = "ChangeMedia", - DisplayNames = new Dictionary() - { - { "zh-cn", "更换播放内容" }, - { "en-us", "Change Media" } - }, - Parameters = new Dictionary>() - { - { - "path", - new Dictionary() - { - { "zh-cn", "文件路径" }, - { "en-us", "FilePath" } - } - } - }, - ParametersType = new List() - { - "string" - }, - HasAppendParameters = false, - ReturnValueType = "void" - }; - - private Function gsv = new() - { - Name = "GetSoundVolume", - DisplayNames = new Dictionary() - { - { "zh-cn", "获取音量数据" }, - { "en-us", "Get Sound Volume" } - }, - HasAppendParameters = false, - ReturnValueType = "double" - }; - - private Function gmp = new() - { - Name = "GetMediaPath", - DisplayNames = new Dictionary() - { - { "zh-cn", "获取当前播放的媒体文件的路径" }, - { "en-us", "Get the Path of the Current Media File" } - }, - HasAppendParameters = false, - ReturnValueType = "string" - }; - #endregion - - public List GetFunctions() - { - - - return new List() - { - new Function() - { - Name = "HelloWorld", - DisplayNames = new Dictionary() - { - { "zh-cn", "你好, 世界!" }, - { "en-us", "Hello, World!" } - }, - Parameters = new Dictionary>() - { - { - "par1", - new Dictionary() - { - { "zh-cn", "参数1" }, - { "en-us", "Parameter1" } - } - } - }, - ParametersType = new List() - { - "void" - }, - HasAppendParameters = false, - ReturnValueType = "void" - }, - - ssv, - - cm, - - gsv, - - gmp - - }; - } - - //private void AnalyzeCmd(Command cmd, Function kxpfunc, int commandType, string methodName) - //{ - - // Command callBackCommand = cmd; - // if (cmd.Request == kxpfunc.Name) - // { - // if (commandType == 2) - // { - // Type type = mainwin.GetType(); - // Object obj = Activator.CreateInstance(type); - // object[] parameters = new object[] { cmd.RequestArgs }; - // var method = type.GetMethod(methodName, new Type[] { }); - // var a = method.Invoke(obj, parameters); - // callBackCommand.Type = CommandType.CallBack; - // callBackCommand.Sender = cmd.Target; - // callBackCommand.Target = cmd.Sender; - // callBackCommand.Body = (byte[])a; - // } - // } - //} + public List GetFunctions() => new(); public void Execute(Command cmd) { - //AnalyzeCmd(cmd, ssv, 0, "KXPChangeVolume") ; - //AnalyzeCmd(cmd, cm, 0, "KXPChangeMedia") ; - //AnalyzeCmd(cmd, gsv, 2, "KXPGetSoundVolume") ; - //AnalyzeCmd(cmd, gmp, 2, "KXPGetMediaPath") ; - if (cmd.Request == ssv.Name) - { - double volume; - double.TryParse(cmd.RequestArgs[0], out volume); - mainwin.KXPChangeVolume(volume); - return; - }; - - if (cmd.Request == cm.Name) - { - mainwin.KXPChangeMedia(cmd.RequestArgs[0]); - return; - }; - - if (cmd.Request == gsv.Name) - { - double sv = mainwin.KXPGetSoundVolume(); - Command callBackCommand = cmd; - callBackCommand.Type = CommandType.CallBack; - callBackCommand.Sender = cmd.Target; - callBackCommand.Target = cmd.Sender; - callBackCommand.Body = BitConverter.GetBytes(sv); - mainwin.sendCommandAction(callBackCommand); - - }; - - if (cmd.Request == gmp.Name) - { - string? mp = mainwin.KXPGetMediaPath(); - Command callBackCommand = cmd; - callBackCommand.Type = CommandType.CallBack; - callBackCommand.Sender = cmd.Target; - callBackCommand.Target = cmd.Sender; - callBackCommand.Body = System.Text.Encoding.Default.GetBytes(mp); - mainwin.sendCommandAction(callBackCommand); - - }; } public void SetRootPath(string path) { - Global.RootPath = path; + GlobalData.RootPath = path; Events.Invoke(nameof(Events.OnSetRootPath)); } @@ -232,7 +49,6 @@ public void SetRootPath(string path) public void SetWorkPath(string path) { - MessageBox.Show($"SetWorkPath({path})"); + GlobalData.WorkPath = path; } - } diff --git a/ClassScheduler.WPF/Data/GlobalData.cs b/ClassScheduler.WPF/Data/GlobalData.cs new file mode 100644 index 0000000..81806cf --- /dev/null +++ b/ClassScheduler.WPF/Data/GlobalData.cs @@ -0,0 +1,8 @@ +namespace ClassScheduler.WPF.Data; + +public class GlobalData +{ + public static string? RootPath { get; set; } + + public static string? WorkPath { get; set; } +} diff --git a/ClassScheduler.WPF/Global.cs b/ClassScheduler.WPF/Global.cs deleted file mode 100644 index b6a3ea8..0000000 --- a/ClassScheduler.WPF/Global.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace ClassScheduler.WPF; - -public class Global -{ - public static string? RootPath { get; set; } -} From 1af535315955d2b0322879a0f74ae1934297bb77 Mon Sep 17 00:00:00 2001 From: Dynesshely Date: Sat, 9 Sep 2023 21:43:16 +0800 Subject: [PATCH 06/35] =?UTF-8?q?=F0=9F=92=BE=20Feat:=20Organized.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ClassScheduler.WPF/ClassScheduler.WPF.csproj | 1 + ClassScheduler.WPF/Controller.cs | 1 - ClassScheduler.WPF/Identity.cs | 74 ++++++++ ClassScheduler.WPF/Instances.cs | 21 +++ ClassScheduler.WPF/MainWindow.xaml.cs | 185 +------------------ ClassScheduler.WPF/Tools.cs | 81 -------- ClassScheduler.WPF/Utils/User32.cs | 85 +++++++++ 7 files changed, 191 insertions(+), 257 deletions(-) create mode 100644 ClassScheduler.WPF/Identity.cs create mode 100644 ClassScheduler.WPF/Instances.cs delete mode 100644 ClassScheduler.WPF/Tools.cs create mode 100644 ClassScheduler.WPF/Utils/User32.cs diff --git a/ClassScheduler.WPF/ClassScheduler.WPF.csproj b/ClassScheduler.WPF/ClassScheduler.WPF.csproj index f238403..0cf11db 100644 --- a/ClassScheduler.WPF/ClassScheduler.WPF.csproj +++ b/ClassScheduler.WPF/ClassScheduler.WPF.csproj @@ -8,6 +8,7 @@ null StarInk Assets\icon.ico + true diff --git a/ClassScheduler.WPF/Controller.cs b/ClassScheduler.WPF/Controller.cs index 53c6fab..fdf504d 100644 --- a/ClassScheduler.WPF/Controller.cs +++ b/ClassScheduler.WPF/Controller.cs @@ -3,7 +3,6 @@ using KitX.Web.Rules; using System; using System.Collections.Generic; -using System.Windows; namespace ClassScheduler.WPF; diff --git a/ClassScheduler.WPF/Identity.cs b/ClassScheduler.WPF/Identity.cs new file mode 100644 index 0000000..d2dba39 --- /dev/null +++ b/ClassScheduler.WPF/Identity.cs @@ -0,0 +1,74 @@ +using KitX.Contract.CSharp; +using System.Collections.Generic; +using System; + +namespace ClassScheduler.WPF; + +public class Identity : IIdentityInterface +{ + public Identity() + { + Instances.Init(); + } + + public string GetName() => "ClassScheduler"; + + public string GetVersion() => "0.3.1"; + + public Dictionary GetDisplayName() => new() + { + { "zh-cn", "潦草的课表日程" }, + { "zh-cnt", "顯示名稱" }, + { "en-us", "ClassScheduler" }, + { "ja-jp", "番組名" } + }; + + public string GetAuthorName() => "StarInk"; + + public string GetPublisherName() => "船出"; + + public string GetAuthorLink() => "作者链接"; + + public string GetPublisherLink() => "发行者链接"; + + public Dictionary GetSimpleDescription() => new() + { + { "zh-cn", "一个简单的桌面课表" }, + { "zh-cnt", "簡單描述" }, + { "en-us", "Simple Description" }, + { "ja-jp", "簡単な説明" } + }; + + public Dictionary GetComplexDescription() => new() + { + { "zh-cn", "复杂描述" }, + { "zh-cnt", "複雜描述" }, + { "en-us", "Complex Description" }, + { "ja-jp", "複雑な説明" } + }; + + public Dictionary GetTotalDescriptionInMarkdown() => new() + { + { "zh-cn", "完整描述" }, + { "zh-cnt", "完整描述" }, + { "en-us", "Total Description" }, + { "ja-jp", "完全な説明" } + }; + + public string GetIconInBase64() => "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"; + + public DateTime GetPublishDate() => DateTime.Parse("2022-12-26"); + + public DateTime GetLastUpdateDate() => DateTime.Parse("2023-07-16"); + + public IController GetController() => Instances.Controller ?? + throw new NullReferenceException( + $"`{nameof(Instances)}.{nameof(Controller)}` is null." + ); + + public bool IsMarketVersion() => false; + + public IMarketPluginContract GetMarketPluginContract() => null; + + public string GetRootStartupFileName() => "ClassScheduler.WPF.dll"; +} diff --git a/ClassScheduler.WPF/Instances.cs b/ClassScheduler.WPF/Instances.cs new file mode 100644 index 0000000..bf8bb67 --- /dev/null +++ b/ClassScheduler.WPF/Instances.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ClassScheduler.WPF; + +internal static class Instances +{ + internal static void Init() + { + MainWindow = new(); + + Controller = new(MainWindow); + } + + internal static MainWindow? MainWindow { get; set; } + + internal static Controller? Controller { get; set; } +} diff --git a/ClassScheduler.WPF/MainWindow.xaml.cs b/ClassScheduler.WPF/MainWindow.xaml.cs index 0480adc..5568e5d 100644 --- a/ClassScheduler.WPF/MainWindow.xaml.cs +++ b/ClassScheduler.WPF/MainWindow.xaml.cs @@ -1,4 +1,6 @@ -using KitX.Contract.CSharp; +using ClassScheduler.WPF.Data; +using ClassScheduler.WPF.Utils; +using KitX.Contract.CSharp; using KitX.Web.Rules; using Microsoft.Win32; using System; @@ -10,10 +12,7 @@ namespace ClassScheduler.WPF; -/// -/// MainWindow.xaml 的交互逻辑 -/// -public partial class MainWindow : Window, IIdentityInterface +public partial class MainWindow : Window { private readonly Controller controller; @@ -43,7 +42,7 @@ public MainWindow() { Icon = new BitmapImage( new( - $"{Global.RootPath}/Assets/icon.ico", + $"{GlobalData.RootPath}/Assets/icon.ico", UriKind.Absolute ) ); @@ -60,9 +59,9 @@ private static int DaysDiff(DateTime start, DateTime end) private static string MakeChart(DateTime dateTime) { // 按星期选择课表 - if (Global.RootPath != null) + if (GlobalData.RootPath != null) { - string path = Global.RootPath + @"\Assets\ChartData.txt"; + string path = GlobalData.RootPath + @"\Assets\ChartData.txt"; string[] allCharts = System.IO.File.ReadAllLines(path); return allCharts[Convert.ToInt32(dateTime.DayOfWeek) + 1]; } @@ -73,9 +72,9 @@ private static string MakeChart(DateTime dateTime) private void ShowDesk() { - if (Global.RootPath is not null) + if (GlobalData.RootPath is not null) { - var path = Global.RootPath + @"\Assets\ChartData.txt"; + var path = GlobalData.RootPath + @"\Assets\ChartData.txt"; var allCharts = System.IO.File.ReadAllLines(path); var GKyear = Convert.ToInt32(allCharts[8]); // 高考年份 @@ -97,7 +96,7 @@ private void ShowDesk() deskWindow.ChangeCharts(MakeChart(DateTime.Today)); deskWindow.Show(); - Tools.SetDeskTop(deskWindow); + User32.SetDeskTop(deskWindow); } else { @@ -257,168 +256,4 @@ public void WinExit() Application.Current.Shutdown(); Environment.Exit(0); } - - #region IIdentityInterface 接口 - - /// - /// 获取插件名称 - /// - /// 插件名称 - public string GetName() => "DesktopPlayer"; - - /// - /// 获取插件版本 - /// - /// 插件版本 - public string GetVersion() => "0.3.1"; - - /// - /// 获取显示名称 - /// - /// 显示名称 - public Dictionary GetDisplayName() => new() - { - { "zh-cn", "潦草的动态桌面" }, - { "zh-cnt", "顯示名稱" }, - { "en-us", "Display Name" }, - { "ja-jp", "番組名" } - }; - - /// - /// 获取作者名称 - /// - /// 作者名称 - public string GetAuthorName() => "StarInk"; - - /// - /// 获取发行者名称 - /// - /// 发行者名称 - public string GetPublisherName() => "船出"; - - /// - /// 获取作者链接 - /// - /// 作者链接 - public string GetAuthorLink() => "作者链接"; - - /// - /// 获取发行者链接 - /// - /// 发行者链接 - public string GetPublisherLink() => "发行者链接"; - - /// - /// 获取简单描述 - /// - /// 简单描述 - public Dictionary GetSimpleDescription() => new() - { - { "zh-cn", "一个在桌面层的视频播放器" }, - { "zh-cnt", "簡單描述" }, - { "en-us", "Simple Description" }, - { "ja-jp", "簡単な説明" } - }; - - /// - /// 获取复杂描述 - /// - /// 复杂描述 - public Dictionary GetComplexDescription() => new() - { - { "zh-cn", "复杂描述" }, - { "zh-cnt", "複雜描述" }, - { "en-us", "Complex Description" }, - { "ja-jp", "複雑な説明" } - }; - - /// - /// 获取 MarkDown 语法的完整介绍 - /// - /// 完整介绍 - public Dictionary GetTotalDescriptionInMarkdown() => new() - { - { "zh-cn", "完整描述" }, - { "zh-cnt", "完整描述" }, - { "en-us", "Total Description" }, - { "ja-jp", "完全な説明" } - }; - - /// - /// 获取 Base64 编码的图标 - /// - /// Base64 编码的图标 - public string GetIconInBase64() => "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"; - - /// - /// 获取发行日期 - /// - /// 发行日期 - public DateTime GetPublishDate() => DateTime.Now; - - /// - /// 获取最近更新日期 - /// - /// 最近更新日期 - public DateTime GetLastUpdateDate() => DateTime.Now; - - /// - /// 获取控制器 - /// - /// 控制器 - public IController GetController() => controller; - - /// - /// 指示是否是市场版本 - /// - /// 是否是市场版本 - public bool IsMarketVersion() => false; - - /// - /// 获取市场版本插件协议 - /// - /// 市场版本插件协议 - public IMarketPluginContract GetMarketPluginContract() => null; - - /// - /// 获取根启动文件名称 - /// - /// 根启动文件名称 - public string GetRootStartupFileName() => "ClassScheduler.WPF.dll"; - - #endregion - - #region kxp方法调用 - public void KXPChangeVolume(double volume) - { - volumeSlider.Value = volume; - // 音量调节 - if (deskWindow is null) return; - - deskWindow.MediaPlayer.Volume = (double)volumeSlider.Value; - } - - public void KXPChangeMedia(string path) - { - // 选择视频并播放 - if (!Directory.Exists(path)) - { - MessageBox.Show($"error:FILE\"({path})\"NOT EXIST"); - return; - }; - - if (deskWindow is null) return; - - mediaPath = path; - deskWindow.MediaPlay(path); - - deskWindow.MediaPlayer.Volume = (double)volumeSlider.Value; - } - - public double KXPGetSoundVolume() => volumeSlider.Value; - - public string? KXPGetMediaPath() => mediaPath; - - #endregion - } diff --git a/ClassScheduler.WPF/Tools.cs b/ClassScheduler.WPF/Tools.cs deleted file mode 100644 index a5c1ad0..0000000 --- a/ClassScheduler.WPF/Tools.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using System.Windows; - -namespace ClassScheduler.WPF; - -class Tools -{ - [DllImport("user32.dll")] - public static extern bool ShowWindow(IntPtr hwnd, int nCmdShow); - - [DllImport("user32.dll", CharSet = CharSet.Unicode)] - public static extern IntPtr FindWindow(string className, string? winName); - - [DllImport("user32.dll")] - public static extern bool EnumWindows(EnumWindowsProc proc, IntPtr lParam); - public delegate bool EnumWindowsProc(IntPtr hwnd, IntPtr lParam); - - [DllImport("user32.dll")] - public static extern IntPtr SetParent(IntPtr hwnd, IntPtr parentHwnd); - - [DllImport("user32.dll", CharSet = CharSet.Unicode)] - public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string className, string? winName); - - [DllImport("user32.dll")] - public static extern IntPtr SendMessageTimeout(IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam, uint fuFlage, uint timeout, IntPtr result); - - public static void SetDeskTop(Window wpfWindow) - { - var programIntPtr = FindWindow("Progman", null); - - Console.WriteLine(programIntPtr); - - // 窗口句柄有效 - if (programIntPtr != IntPtr.Zero) - { - var result = IntPtr.Zero; - - SendMessageTimeout( - programIntPtr, - 0x052C, - IntPtr.Zero, - IntPtr.Zero, - 0x0000, - 1000, - IntPtr.Zero - ); - - // 遍历顶级窗口 - EnumWindows((hwnd, lParam) => - { - // 找到包含 SHELLDLL_DefView 这个窗口句柄的 WorkerW - if (FindWindowEx( - hwnd, - IntPtr.Zero, - "SHELLDLL_DefView", - null - ) != IntPtr.Zero) - { - // 找到当前 WorkerW 窗口的,后一个 WorkerW 窗口。 - var tempHwnd = FindWindowEx( - IntPtr.Zero, - hwnd, - "WorkerW", - null - ); - - // 隐藏这个窗口 - ShowWindow(tempHwnd, 0); - } - return true; - }, IntPtr.Zero); - } - - SetParent( - new System.Windows.Interop.WindowInteropHelper(wpfWindow).Handle, - programIntPtr - ); - - } -} diff --git a/ClassScheduler.WPF/Utils/User32.cs b/ClassScheduler.WPF/Utils/User32.cs new file mode 100644 index 0000000..3d7b61c --- /dev/null +++ b/ClassScheduler.WPF/Utils/User32.cs @@ -0,0 +1,85 @@ +using System; +using System.Runtime.InteropServices; +using System.Windows; + +namespace ClassScheduler.WPF.Utils; + +public partial class User32 +{ + private const string user32dllPath = "user32.dll"; + + [LibraryImport(user32dllPath)] + [return: MarshalAs(UnmanagedType.Bool)] + public static partial bool ShowWindow(nint hwnd, int nCmdShow); + + [LibraryImport(user32dllPath, StringMarshalling = StringMarshalling.Utf16)] + public static partial nint FindWindow(string className, string? winName); + + [LibraryImport(user32dllPath)] + [return: MarshalAs(UnmanagedType.Bool)] + public static partial bool EnumWindows(EnumWindowsProc proc, nint lParam); + public delegate bool EnumWindowsProc(nint hwnd, nint lParam); + + [LibraryImport(user32dllPath)] + internal static partial nint SetParent(nint hwnd, nint parentHwnd); + + [LibraryImport(user32dllPath, StringMarshalling = StringMarshalling.Utf16)] + public static partial nint FindWindowEx(nint hwndParent, nint hwndChildAfter, string className, string? winName); + + [LibraryImport(user32dllPath)] + internal static partial nint SendMessageTimeout(nint hwnd, uint msg, nint wParam, nint lParam, uint fuFlage, uint timeout, nint result); + + public static void SetDeskTop(Window wpfWindow) + { + var programIntPtr = FindWindow("Progman", null); + + Console.WriteLine(programIntPtr); + + // 窗口句柄有效 + if (programIntPtr != nint.Zero) + { + var result = nint.Zero; + + SendMessageTimeout( + programIntPtr, + 0x052C, + nint.Zero, + nint.Zero, + 0x0000, + 1000, + nint.Zero + ); + + // 遍历顶级窗口 + EnumWindows((hwnd, lParam) => + { + // 找到包含 SHELLDLL_DefView 这个窗口句柄的 WorkerW + if (FindWindowEx( + hwnd, + nint.Zero, + "SHELLDLL_DefView", + null + ) != nint.Zero) + { + // 找到当前 WorkerW 窗口的,后一个 WorkerW 窗口。 + var tempHwnd = FindWindowEx( + nint.Zero, + hwnd, + "WorkerW", + null + ); + + // 隐藏这个窗口 + ShowWindow(tempHwnd, 0); + } + return true; + }, nint.Zero); + } + + SetParent( + new System.Windows.Interop.WindowInteropHelper(wpfWindow).Handle, + programIntPtr + ); + + } +} From 02fc78ec362b5c6430be656f0a47f9b39c8c31b1 Mon Sep 17 00:00:00 2001 From: Dynesshely Date: Sun, 10 Sep 2023 12:40:40 +0800 Subject: [PATCH 07/35] =?UTF-8?q?=F0=9F=92=BE=20Feat:=20Optimized.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: StarInk <114210472+StardustSeemsInk@users.noreply.github.com> --- .../ClassScheduler.Runner.csproj | 1 + ClassScheduler.WPF/ClassScheduler.WPF.csproj | 1 + ClassScheduler.WPF/Controller.cs | 15 +- ClassScheduler.WPF/DeskWindow.xaml | 88 ------ ClassScheduler.WPF/DeskWindow.xaml.cs | 63 ----- ClassScheduler.WPF/Instances.cs | 10 +- ClassScheduler.WPF/MainWindow.xaml | 82 ------ ClassScheduler.WPF/MainWindow.xaml.cs | 259 ------------------ ClassScheduler.WPF/Utils/User32.cs | 103 +++---- ClassScheduler.WPF/Views/MainWindow.xaml | 14 + ClassScheduler.WPF/Views/MainWindow.xaml.cs | 42 +++ ClassScheduler.WPF/Views/ScheduleWindow.xaml | 91 ++++++ .../Views/ScheduleWindow.xaml.cs | 40 +++ ClassScheduler.sln | 12 +- 14 files changed, 265 insertions(+), 556 deletions(-) delete mode 100644 ClassScheduler.WPF/DeskWindow.xaml delete mode 100644 ClassScheduler.WPF/DeskWindow.xaml.cs delete mode 100644 ClassScheduler.WPF/MainWindow.xaml delete mode 100644 ClassScheduler.WPF/MainWindow.xaml.cs create mode 100644 ClassScheduler.WPF/Views/MainWindow.xaml create mode 100644 ClassScheduler.WPF/Views/MainWindow.xaml.cs create mode 100644 ClassScheduler.WPF/Views/ScheduleWindow.xaml create mode 100644 ClassScheduler.WPF/Views/ScheduleWindow.xaml.cs diff --git a/ClassScheduler.Runner/ClassScheduler.Runner.csproj b/ClassScheduler.Runner/ClassScheduler.Runner.csproj index 0a11da4..bb708fd 100644 --- a/ClassScheduler.Runner/ClassScheduler.Runner.csproj +++ b/ClassScheduler.Runner/ClassScheduler.Runner.csproj @@ -5,6 +5,7 @@ net7.0-windows enable true + AnyCPU;x64 diff --git a/ClassScheduler.WPF/ClassScheduler.WPF.csproj b/ClassScheduler.WPF/ClassScheduler.WPF.csproj index 0cf11db..0d0a905 100644 --- a/ClassScheduler.WPF/ClassScheduler.WPF.csproj +++ b/ClassScheduler.WPF/ClassScheduler.WPF.csproj @@ -9,6 +9,7 @@ StarInk Assets\icon.ico true + AnyCPU;x64 diff --git a/ClassScheduler.WPF/Controller.cs b/ClassScheduler.WPF/Controller.cs index fdf504d..9f26726 100644 --- a/ClassScheduler.WPF/Controller.cs +++ b/ClassScheduler.WPF/Controller.cs @@ -8,26 +8,21 @@ namespace ClassScheduler.WPF; public class Controller : IController { - private readonly MainWindow mainwin; - - public Controller(MainWindow mainwin) - { - this.mainwin = mainwin; - } + private Action? sendCommandAction; public void Start() { - mainwin.Show(); + Instances.MainWindow?.Show(); } public void Pause() { - mainwin.WinPause(); + Instances.MainWindow?.Pause(); } public void End() { - mainwin.WinExit(); + Instances.MainWindow?.Exit(); } public List GetFunctions() => new(); @@ -44,7 +39,7 @@ public void SetRootPath(string path) Events.Invoke(nameof(Events.OnSetRootPath)); } - public void SetSendCommandAction(Action action) => mainwin.sendCommandAction = action; + public void SetSendCommandAction(Action action) => sendCommandAction = action; public void SetWorkPath(string path) { diff --git a/ClassScheduler.WPF/DeskWindow.xaml b/ClassScheduler.WPF/DeskWindow.xaml deleted file mode 100644 index 104e9fe..0000000 --- a/ClassScheduler.WPF/DeskWindow.xaml +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - 天 - - - 233 - - - 20:44 - - - 课表 - - - 语 - - - - diff --git a/ClassScheduler.WPF/DeskWindow.xaml.cs b/ClassScheduler.WPF/DeskWindow.xaml.cs deleted file mode 100644 index f64ba93..0000000 --- a/ClassScheduler.WPF/DeskWindow.xaml.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using System.Timers; -using System.Windows; - -namespace ClassScheduler.WPF; - -/// -/// DeskWindow.xaml 的交互逻辑 -/// - -public partial class DeskWindow : Window -{ - private Timer? timer; - - public DeskWindow() - { - InitializeComponent(); - - Loaded += new RoutedEventHandler(DTW_Loaded); - - Clock.Text = DateTime.Now.ToString("t"); - } - - private void DTW_Loaded(object sender, RoutedEventArgs e) - { - //设置定时器 - timer = new() - { - Interval = 60 * 1000, //时间间隔为60秒 - AutoReset = true, - }; - timer.Elapsed += (_, _) => Clock.Text = DateTime.Now.ToString("t"); - - //开启定时器 - timer.Start(); - } - - public void ChangeDays(string text) => LeftDays.Text = text; - - public void ChangeCharts(string text) - { - var a = text.Length; - var retext = ""; - - for (var i = 0; i < a; ++i) - { - var s = $"{text[i]}\n"; - retext += s; - } - - Charts.Text = retext; - } - - public void MediaPlay(string videoPath) - { - MediaPlayer.Source = new(videoPath); - - MediaPlayer.Play(); - } - - private void MediaPlayer_MediaEnded(object sender, RoutedEventArgs e) - => MediaPlayer.Position -= MediaPlayer.Position; -} diff --git a/ClassScheduler.WPF/Instances.cs b/ClassScheduler.WPF/Instances.cs index bf8bb67..b6ea4e2 100644 --- a/ClassScheduler.WPF/Instances.cs +++ b/ClassScheduler.WPF/Instances.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using ClassScheduler.WPF.Views; namespace ClassScheduler.WPF; @@ -12,10 +8,12 @@ internal static void Init() { MainWindow = new(); - Controller = new(MainWindow); + Controller = new(); } internal static MainWindow? MainWindow { get; set; } + internal static ScheduleWindow? DeskWindow { get; set; } + internal static Controller? Controller { get; set; } } diff --git a/ClassScheduler.WPF/MainWindow.xaml b/ClassScheduler.WPF/MainWindow.xaml deleted file mode 100644 index efdc63a..0000000 --- a/ClassScheduler.WPF/MainWindow.xaml +++ /dev/null @@ -1,82 +0,0 @@ - - - - 自定义今日课表… - - - - - - - - - diff --git a/ClassScheduler.WPF/MainWindow.xaml.cs b/ClassScheduler.WPF/MainWindow.xaml.cs deleted file mode 100644 index 5568e5d..0000000 --- a/ClassScheduler.WPF/MainWindow.xaml.cs +++ /dev/null @@ -1,259 +0,0 @@ -using ClassScheduler.WPF.Data; -using ClassScheduler.WPF.Utils; -using KitX.Contract.CSharp; -using KitX.Web.Rules; -using Microsoft.Win32; -using System; -using System.Collections.Generic; -using System.IO; -using System.Windows; -using System.Windows.Media; -using System.Windows.Media.Imaging; - -namespace ClassScheduler.WPF; - -public partial class MainWindow : Window -{ - private readonly Controller controller; - - public DeskWindow? deskWindow = null; - - public string? mediaPath; - - internal Action? sendCommandAction; - - public MainWindow() - { - InitializeComponent(); - - controller = new(this); - - var args = Environment.GetCommandLineArgs(); - - if (args.Length > 1) - { - var video_path = args[1]; - - ShowDesk(); - ShowParaVideo(video_path); - } - - Events.OnSetRootPath += () => - { - Icon = new BitmapImage( - new( - $"{GlobalData.RootPath}/Assets/icon.ico", - UriKind.Absolute - ) - ); - }; - } - - private static int DaysDiff(DateTime start, DateTime end) - { - // 计算时间间隔 - TimeSpan sp = end.Subtract(start); - return sp.Days; - } - - private static string MakeChart(DateTime dateTime) - { - // 按星期选择课表 - if (GlobalData.RootPath != null) - { - string path = GlobalData.RootPath + @"\Assets\ChartData.txt"; - string[] allCharts = System.IO.File.ReadAllLines(path); - return allCharts[Convert.ToInt32(dateTime.DayOfWeek) + 1]; - } - else return string.Empty; - } - - private void ShowDeskBg_Click(object sender, RoutedEventArgs e) => ShowDesk(); - - private void ShowDesk() - { - if (GlobalData.RootPath is not null) - { - var path = GlobalData.RootPath + @"\Assets\ChartData.txt"; - var allCharts = System.IO.File.ReadAllLines(path); - var GKyear = Convert.ToInt32(allCharts[8]); // 高考年份 - - var leftDays = DaysDiff( - DateTime.Today, - new DateTime(GKyear, 6, 7) - ); - - if (deskWindow is null) - { - // 创建 DeskWindow 窗口 - deskWindow = new() - { - // 设置总宽/长度 - Width = SystemParameters.PrimaryScreenWidth, - Height = SystemParameters.PrimaryScreenHeight - }; - deskWindow.ChangeDays(leftDays.ToString()); - deskWindow.ChangeCharts(MakeChart(DateTime.Today)); - deskWindow.Show(); - - User32.SetDeskTop(deskWindow); - } - else - { - deskWindow.ChangeDays(leftDays.ToString()); - deskWindow.ChangeCharts(MakeChart(DateTime.Today)); - } - } - } - - private void ReWriteCharts_Click(object sender, RoutedEventArgs e) - { - // 重写课表 - if (deskWindow is null) return; - - deskWindow.ChangeCharts(chartsInput.Text); - } - - private int color_counts = 0; - - private SolidColorBrush ColorTextNow = Brushes.White; - - private void ChangeFColorBg_Click(object sender, RoutedEventArgs e) - { - // 更换字体颜色 - if (deskWindow is null) return; - - switch (color_counts) - { - case 0: - ColorTextNow = new SolidColorBrush( - (Color)ColorConverter.ConvertFromString("#66CCFF") - ); - color_counts++; - break; - case 1: - ColorTextNow = new SolidColorBrush( - (Color)ColorConverter.ConvertFromString("yellow") - ); - color_counts++; - break; - case 2: - ColorTextNow = new SolidColorBrush( - (Color)ColorConverter.ConvertFromString("red") - ); - color_counts++; - break; - case 3: - ColorTextNow = new SolidColorBrush( - (Color)ColorConverter.ConvertFromString("black") - ); - color_counts++; - break; - default: - ColorTextNow = new SolidColorBrush( - (Color)ColorConverter.ConvertFromString("white") - ); - color_counts = 0; - break; - } - - deskWindow.LeftDaysTitle.Foreground = ColorTextNow; - deskWindow.ChartsTitle.Foreground = ColorTextNow; - deskWindow.Charts.Foreground = ColorTextNow; - deskWindow.TextDay.Foreground = ColorTextNow; - } - - private void ChooseVideoBg_Click(object sender, RoutedEventArgs e) - { - // 选择视频并播放 - var dialog = new OpenFileDialog - { - Filter = "Video File(*.avi;*.mp4;*.mkv;*.wav;*.rmvb)|*.avi;*.mp4;*.mkv;*.wav;*.rmvb|All File(*.*)|*.*" - }; - - if (!dialog.ShowDialog().GetValueOrDefault()) - { - return; - } - - if (deskWindow is null) - { - return; - } - - mediaPath = dialog.FileName; - deskWindow.MediaPlay(mediaPath); - - deskWindow.MediaPlayer.Volume = (double)volumeSlider.Value; - } - - private void ShowParaVideo(string video_path) - { - if (deskWindow is null) return; - - volumeSlider.Value = 0; - - deskWindow.MediaPlay(video_path); - - deskWindow.MediaPlayer.Volume = (double)volumeSlider.Value; - - ColorTextNow = new SolidColorBrush( - (Color)ColorConverter.ConvertFromString("#66CCFF") - ); - - deskWindow.LeftDaysTitle.Foreground = ColorTextNow; - deskWindow.ChartsTitle.Foreground = ColorTextNow; - deskWindow.Charts.Foreground = ColorTextNow; - deskWindow.TextDay.Foreground = ColorTextNow; - } - - private void ChangeVolume(object sender, RoutedPropertyChangedEventArgs args) - { - // 音量调节 - if (deskWindow is null) return; - - deskWindow.MediaPlayer.Volume = (double)volumeSlider.Value; - } - - private void StopDeskBg_Click(object sender, RoutedEventArgs e) - { - // 关闭deskwindow、deskhild - if (deskWindow is not null) - { - deskWindow.Close(); - - deskWindow = null; - } - - //if (deskChild != null) - //{ - // deskChild.Close(); - // deskChild = null; - //} - } - - private void Window_Closed(object sender, System.EventArgs e) - { - Application.Current.Shutdown(); - - Environment.Exit(0); - } - - public void WinPause() - { - // 关闭deskwindow - if (deskWindow is not null) - { - deskWindow.Close(); - deskWindow = null; - } - } - - public void WinExit() - { - WinPause(); - Close(); - Application.Current.Shutdown(); - Environment.Exit(0); - } -} diff --git a/ClassScheduler.WPF/Utils/User32.cs b/ClassScheduler.WPF/Utils/User32.cs index 3d7b61c..eec187a 100644 --- a/ClassScheduler.WPF/Utils/User32.cs +++ b/ClassScheduler.WPF/Utils/User32.cs @@ -1,5 +1,4 @@ -using System; -using System.Runtime.InteropServices; +using System.Runtime.InteropServices; using System.Windows; namespace ClassScheduler.WPF.Utils; @@ -24,62 +23,72 @@ public partial class User32 internal static partial nint SetParent(nint hwnd, nint parentHwnd); [LibraryImport(user32dllPath, StringMarshalling = StringMarshalling.Utf16)] - public static partial nint FindWindowEx(nint hwndParent, nint hwndChildAfter, string className, string? winName); + public static partial nint FindWindowEx( + nint hwndParent, + nint hwndChildAfter, + string className, + string? winName); [LibraryImport(user32dllPath)] - internal static partial nint SendMessageTimeout(nint hwnd, uint msg, nint wParam, nint lParam, uint fuFlage, uint timeout, nint result); + internal static partial nint SendMessageTimeout( + nint hwnd, + uint msg, + nint wParam, + nint lParam, + uint fuFlage, + uint timeout, + nint result); +} - public static void SetDeskTop(Window wpfWindow) +public static class User32Extensions +{ + public static void MoveToBottom(this Window wpfWindow) { - var programIntPtr = FindWindow("Progman", null); + var programIntPtr = User32.FindWindow("Progman", null); - Console.WriteLine(programIntPtr); + if (programIntPtr == nint.Zero) // Ensure we found the `progman` + return; - // 窗口句柄有效 - if (programIntPtr != nint.Zero) - { - var result = nint.Zero; + var result = nint.Zero; - SendMessageTimeout( - programIntPtr, - 0x052C, - nint.Zero, - nint.Zero, - 0x0000, - 1000, - nint.Zero - ); + User32.SendMessageTimeout( + programIntPtr, + 0x052C, + nint.Zero, + nint.Zero, + 0x0000, + 1000, + nint.Zero + ); - // 遍历顶级窗口 - EnumWindows((hwnd, lParam) => + // Foreach top layer windows + User32.EnumWindows((hwnd, lParam) => + { + // Find `WorkerW` which includes handle of `SHELLDLL_DefView` + if (User32.FindWindowEx( + hwnd, + nint.Zero, + "SHELLDLL_DefView", + null + ) != nint.Zero) { - // 找到包含 SHELLDLL_DefView 这个窗口句柄的 WorkerW - if (FindWindowEx( - hwnd, - nint.Zero, - "SHELLDLL_DefView", - null - ) != nint.Zero) - { - // 找到当前 WorkerW 窗口的,后一个 WorkerW 窗口。 - var tempHwnd = FindWindowEx( - nint.Zero, - hwnd, - "WorkerW", - null - ); - - // 隐藏这个窗口 - ShowWindow(tempHwnd, 0); - } - return true; - }, nint.Zero); - } - - SetParent( + // Find the next `WorkerW` window after current one + var tempHwnd = User32.FindWindowEx( + nint.Zero, + hwnd, + "WorkerW", + null + ); + + // Hide this window + User32.ShowWindow(tempHwnd, 0); + } + return true; + }, nint.Zero); + + User32.SetParent( new System.Windows.Interop.WindowInteropHelper(wpfWindow).Handle, programIntPtr ); - } } diff --git a/ClassScheduler.WPF/Views/MainWindow.xaml b/ClassScheduler.WPF/Views/MainWindow.xaml new file mode 100644 index 0000000..a843b1a --- /dev/null +++ b/ClassScheduler.WPF/Views/MainWindow.xaml @@ -0,0 +1,14 @@ + + + + + diff --git a/ClassScheduler.WPF/Views/MainWindow.xaml.cs b/ClassScheduler.WPF/Views/MainWindow.xaml.cs new file mode 100644 index 0000000..4a2efd4 --- /dev/null +++ b/ClassScheduler.WPF/Views/MainWindow.xaml.cs @@ -0,0 +1,42 @@ +using ClassScheduler.WPF.Data; +using System; +using System.Windows; +using System.Windows.Media.Imaging; + +namespace ClassScheduler.WPF.Views; + +public partial class MainWindow : Window +{ + public ScheduleWindow? deskWindow = null; + + public MainWindow() + { + InitializeComponent(); + +#if DEBUG + new ScheduleWindow().Show(); +#endif + + Events.OnSetRootPath += () => + { + Icon = new BitmapImage( + new( + $"{GlobalData.RootPath}/Assets/icon.ico", + UriKind.Absolute + ) + ); + }; + } + + public void Pause() + { + Instances.DeskWindow?.Close(); + Instances.DeskWindow = null; + } + + public void Exit() + { + Application.Current.Shutdown(); + Environment.Exit(0); + } +} diff --git a/ClassScheduler.WPF/Views/ScheduleWindow.xaml b/ClassScheduler.WPF/Views/ScheduleWindow.xaml new file mode 100644 index 0000000..c2d2455 --- /dev/null +++ b/ClassScheduler.WPF/Views/ScheduleWindow.xaml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ClassScheduler.WPF/Views/ScheduleWindow.xaml.cs b/ClassScheduler.WPF/Views/ScheduleWindow.xaml.cs new file mode 100644 index 0000000..55e2852 --- /dev/null +++ b/ClassScheduler.WPF/Views/ScheduleWindow.xaml.cs @@ -0,0 +1,40 @@ +using System; +using System.Timers; +using System.Windows; + +namespace ClassScheduler.WPF.Views; + +public partial class ScheduleWindow : Window +{ + private Timer _timer; + + public ScheduleWindow() + { + InitializeComponent(); + + //this.MoveToBottom(); + + UpdateDatas(); + + _timer = new Timer() + { + Interval = 10 * 1000, + }; + + _timer.Elapsed += (_, _) => UpdateDatas(); + } + + public void UpdateDatas() + { + var now = DateTime.Now; + var high_school_entrance_day = DateTime.Parse("06-06"); + + if (high_school_entrance_day < now) + high_school_entrance_day = high_school_entrance_day.AddYears(1); + + TextBlock_Time.Text = now.ToString("HH:mm"); + TextBlock_Date.Text = now.ToString("MM 月 dd 日"); + TextBlock_WeekDay.Text = now.ToString("dddd"); + TextBlock_DaysLeft.Text = Math.Floor((high_school_entrance_day - now).TotalDays).ToString(); + } +} diff --git a/ClassScheduler.sln b/ClassScheduler.sln index b1b140d..f1c9cc6 100644 --- a/ClassScheduler.sln +++ b/ClassScheduler.sln @@ -5,22 +5,32 @@ VisualStudioVersion = 17.3.32811.315 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClassScheduler.WPF", "ClassScheduler.WPF\ClassScheduler.WPF.csproj", "{139C572D-31A7-4F5B-B16A-406AD12C4C83}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClassScheduler.Runner", "ClassScheduler.Runner\ClassScheduler.Runner.csproj", "{1267BA65-10DA-49DC-AEC5-40AD2A98F404}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClassScheduler.Runner", "ClassScheduler.Runner\ClassScheduler.Runner.csproj", "{1267BA65-10DA-49DC-AEC5-40AD2A98F404}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {139C572D-31A7-4F5B-B16A-406AD12C4C83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {139C572D-31A7-4F5B-B16A-406AD12C4C83}.Debug|Any CPU.Build.0 = Debug|Any CPU + {139C572D-31A7-4F5B-B16A-406AD12C4C83}.Debug|x64.ActiveCfg = Debug|x64 + {139C572D-31A7-4F5B-B16A-406AD12C4C83}.Debug|x64.Build.0 = Debug|x64 {139C572D-31A7-4F5B-B16A-406AD12C4C83}.Release|Any CPU.ActiveCfg = Release|Any CPU {139C572D-31A7-4F5B-B16A-406AD12C4C83}.Release|Any CPU.Build.0 = Release|Any CPU + {139C572D-31A7-4F5B-B16A-406AD12C4C83}.Release|x64.ActiveCfg = Release|x64 + {139C572D-31A7-4F5B-B16A-406AD12C4C83}.Release|x64.Build.0 = Release|x64 {1267BA65-10DA-49DC-AEC5-40AD2A98F404}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1267BA65-10DA-49DC-AEC5-40AD2A98F404}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1267BA65-10DA-49DC-AEC5-40AD2A98F404}.Debug|x64.ActiveCfg = Debug|x64 + {1267BA65-10DA-49DC-AEC5-40AD2A98F404}.Debug|x64.Build.0 = Debug|x64 {1267BA65-10DA-49DC-AEC5-40AD2A98F404}.Release|Any CPU.ActiveCfg = Release|Any CPU {1267BA65-10DA-49DC-AEC5-40AD2A98F404}.Release|Any CPU.Build.0 = Release|Any CPU + {1267BA65-10DA-49DC-AEC5-40AD2A98F404}.Release|x64.ActiveCfg = Release|x64 + {1267BA65-10DA-49DC-AEC5-40AD2A98F404}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 9bc16326942e3b42adb5511f4172086d29916f29 Mon Sep 17 00:00:00 2001 From: Dynesshely Date: Wed, 13 Sep 2023 20:31:54 +0800 Subject: [PATCH 08/35] =?UTF-8?q?=F0=9F=92=BE=20Feat:=20Multi=20features,?= =?UTF-8?q?=20see=20details.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Allow user add class in `MainWindow`. - Display notify icon in taskbar with context menu including a context menu item to quit app. - Updated `ScheduleWindow` with time, date, left days to HSEE and today classes. - Put `ScheduleWindow` to bottom under `Progman`. --- ClassScheduler.Runner/App.xaml.cs | 24 ++- ClassScheduler.WPF/ClassScheduler.WPF.csproj | 1 + ClassScheduler.WPF/Data/Classes.cs | 26 ++- ClassScheduler.WPF/Instances.cs | 20 ++- ClassScheduler.WPF/Models/ClassModel.cs | 34 ++++ ClassScheduler.WPF/Utils/User32.cs | 129 ++++++++++---- ClassScheduler.WPF/Views/MainWindow.xaml | 49 +++++- ClassScheduler.WPF/Views/MainWindow.xaml.cs | 161 +++++++++++++++++- ClassScheduler.WPF/Views/ScheduleWindow.xaml | 49 +++++- .../Views/ScheduleWindow.xaml.cs | 89 +++++++++- 10 files changed, 526 insertions(+), 56 deletions(-) diff --git a/ClassScheduler.Runner/App.xaml.cs b/ClassScheduler.Runner/App.xaml.cs index 1410ff1..f7fbc3a 100644 --- a/ClassScheduler.Runner/App.xaml.cs +++ b/ClassScheduler.Runner/App.xaml.cs @@ -2,6 +2,7 @@ using System; using System.ComponentModel.Composition.Hosting; using System.IO; +using System.Threading.Tasks; using System.Windows; namespace ClassScheduler.Runner; @@ -10,6 +11,23 @@ public partial class App : Application { private void Application_Startup(object sender, StartupEventArgs e) { + AppDomain.CurrentDomain.UnhandledException += (s, e) => + { + Console.WriteLine(e.ToString()); + }; + + DispatcherUnhandledException += (x, y) => + { + y.Handled = true; + Console.WriteLine($"{y.Exception.Message}\n{y.Exception.StackTrace}"); + }; + + TaskScheduler.UnobservedTaskException += (s, e) => + { + e.SetObserved(); + Console.WriteLine($"{e.Exception.Message}\n{e.Exception.StackTrace}"); + }; + try { LoadPlugin("./ClassScheduler.WPF.dll"); @@ -31,7 +49,7 @@ private void Application_Startup(object sender, StartupEventArgs e) private static void LoadPlugin(string path) { - if (File.Exists(path)) + if (File.Exists(Path.GetFullPath(path))) { var dirPath = Path.GetDirectoryName(path); var fileName = Path.GetFileName(path); @@ -56,5 +74,9 @@ private static void LoadPlugin(string path) break; } } + else + { + throw new ArgumentException("Path not exists.", nameof(path)); + } } } diff --git a/ClassScheduler.WPF/ClassScheduler.WPF.csproj b/ClassScheduler.WPF/ClassScheduler.WPF.csproj index 0d0a905..19becf2 100644 --- a/ClassScheduler.WPF/ClassScheduler.WPF.csproj +++ b/ClassScheduler.WPF/ClassScheduler.WPF.csproj @@ -5,6 +5,7 @@ net7.0-windows enable true + true null StarInk Assets\icon.ico diff --git a/ClassScheduler.WPF/Data/Classes.cs b/ClassScheduler.WPF/Data/Classes.cs index f41fe84..fc54c96 100644 --- a/ClassScheduler.WPF/Data/Classes.cs +++ b/ClassScheduler.WPF/Data/Classes.cs @@ -8,9 +8,31 @@ namespace ClassScheduler.WPF.Data; public class Classes { - public string? Name { get; set; } + public string? Name { get; set; } public List ClassesList { get; set; } = new(); + + public Classes Sort() + { + ClassesList.Sort( + new Comparison( + (x, y) => + { + if (x.WeekDay == y.WeekDay) + { + if (x.BeginTime == y.BeginTime) + return 0; + else + return x.BeginTime > y.BeginTime ? 1 : -1; + } + else + return x.WeekDay > y.WeekDay ? 1 : -1; + } + ) + ); + + return this; + } } public static class ClassesExtensions @@ -35,6 +57,8 @@ public static void Save( this string path, Action? optionsProcessor = null) { + if (!Path.Exists(path)) return null; + var options = new JsonSerializerOptions(); optionsProcessor?.Invoke(options); diff --git a/ClassScheduler.WPF/Instances.cs b/ClassScheduler.WPF/Instances.cs index b6ea4e2..411f97b 100644 --- a/ClassScheduler.WPF/Instances.cs +++ b/ClassScheduler.WPF/Instances.cs @@ -1,4 +1,7 @@ -using ClassScheduler.WPF.Views; +using ClassScheduler.WPF.Data; +using ClassScheduler.WPF.Views; +using System.IO; +using System.Windows.Forms; namespace ClassScheduler.WPF; @@ -6,14 +9,27 @@ internal static class Instances { internal static void Init() { + if (!Directory.Exists(Path.GetFullPath("./Data/"))) + Directory.CreateDirectory(Path.GetFullPath("./Data/")); + + Classes = "./Data/Classes.json".Load(); + Classes ??= new(); + Classes.Save("./Data/Classes.json"); + MainWindow = new(); + ScheduleWindow = new(); + Controller = new(); } internal static MainWindow? MainWindow { get; set; } - internal static ScheduleWindow? DeskWindow { get; set; } + internal static ScheduleWindow? ScheduleWindow { get; set; } internal static Controller? Controller { get; set; } + + internal static Classes? Classes { get; set; } + + internal static NotifyIcon? NotifyIcon { get; set; } } diff --git a/ClassScheduler.WPF/Models/ClassModel.cs b/ClassScheduler.WPF/Models/ClassModel.cs index 0fa72f7..6c703a9 100644 --- a/ClassScheduler.WPF/Models/ClassModel.cs +++ b/ClassScheduler.WPF/Models/ClassModel.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using ClassScheduler.WPF.Models.Types; namespace ClassScheduler.WPF.Models; @@ -15,5 +16,38 @@ public class ClassModel public DateTime? EndTime { get; set; } + /// + /// 0b00000001 - 2 - Monday + /// 0b00000010 - 4 - Tuesday + /// 0b00000100 - 8 - Wendsday + /// 0b00001000 - 16 - Thursday + /// 0b00010000 - 32 - Friday + /// 0b00100000 - 64 - Saturday + /// 0b01000000 - 128 - Sunday + /// + public byte? WeekDay { get; set; } + + public int? DayOfWeek + { + get + { + var weekDay = (int)WeekDay!; + var dividedCount = 0; + while(weekDay != 1) + { + weekDay /= 2; + ++dividedCount; + } + return dividedCount + 1; + } + } + public RepeatType RepeatType { get; set; } = RepeatType.NoRepeat; + + public override string ToString() + { + var teacher = $"{(Teacher is null ? "" : $" by {Teacher.Name ?? "null"} ")}"; + var duration = $" from {BeginTime?.ToString("HH:mm")} to {EndTime?.ToString("HH:mm")}"; + return $"{Name}{teacher}{duration} on {DayOfWeek}"; + } } diff --git a/ClassScheduler.WPF/Utils/User32.cs b/ClassScheduler.WPF/Utils/User32.cs index eec187a..bff7b50 100644 --- a/ClassScheduler.WPF/Utils/User32.cs +++ b/ClassScheduler.WPF/Utils/User32.cs @@ -1,43 +1,73 @@ -using System.Runtime.InteropServices; +using System; +using System.Runtime.InteropServices; using System.Windows; +using System.Windows.Interop; namespace ClassScheduler.WPF.Utils; +[Flags] +public enum SendMessageTimeoutFlags : uint +{ + SMTO_NORMAL = 0x0, + SMTO_BLOCK = 0x1, + SMTO_ABORTIFHUNG = 0x2, + SMTO_NOTIMEOUTIFNOTHUNG = 0x8, + SMTO_ERRORONEXIT = 0x20 +} + public partial class User32 { private const string user32dllPath = "user32.dll"; - [LibraryImport(user32dllPath)] - [return: MarshalAs(UnmanagedType.Bool)] - public static partial bool ShowWindow(nint hwnd, int nCmdShow); + [DllImport(user32dllPath, EntryPoint = "SetParent")] + internal static extern int SetParent(IntPtr hWndChild, IntPtr hWndNewParent); + + [DllImport(user32dllPath)] + internal static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndlnsertAfter, int X, int Y, int cx, int cy, uint Flags); - [LibraryImport(user32dllPath, StringMarshalling = StringMarshalling.Utf16)] - public static partial nint FindWindow(string className, string? winName); + [DllImport(user32dllPath, CharSet = CharSet.Ansi, EntryPoint = "FindWindowA", ExactSpelling = false, SetLastError = true)] + internal static extern IntPtr FindWindow(string lpClassName, string lpWindowName); + + [DllImport(user32dllPath, EntryPoint = "FindWindowEx")] + internal static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpClassName, string lpWindowName); + + [DllImport(user32dllPath, SetLastError = true, CharSet = CharSet.Auto)] + internal static extern IntPtr SendMessageTimeout(IntPtr hWnd, uint Msg, UIntPtr wParam, IntPtr lParam, SendMessageTimeoutFlags fuFlags, uint uTimeout, out UIntPtr lpdwResult); + + internal delegate bool EnumWindowsCallback(IntPtr hwnd, int lParam); + [DllImport(user32dllPath)] + internal static extern int EnumWindows(EnumWindowsCallback callPtr, int lParam); + + [DllImport(user32dllPath, EntryPoint = "ShowWindow", CharSet = CharSet.Auto)] + internal static extern int ShowWindow(IntPtr hwnd, int nCmdShow); + + [DllImport(user32dllPath)] + internal static extern int GetWindowRect(IntPtr hwnd, out Rect lpRect); [LibraryImport(user32dllPath)] [return: MarshalAs(UnmanagedType.Bool)] - public static partial bool EnumWindows(EnumWindowsProc proc, nint lParam); - public delegate bool EnumWindowsProc(nint hwnd, nint lParam); + internal static partial bool EnumWindows(EnumWindowsProc proc, nint lParam); + internal delegate bool EnumWindowsProc(nint hwnd, nint lParam); - [LibraryImport(user32dllPath)] - internal static partial nint SetParent(nint hwnd, nint parentHwnd); + //[LibraryImport(user32dllPath)] + //internal static partial nint SendMessageTimeout( + // nint hwnd, + // uint msg, + // nint wParam, + // nint lParam, + // uint fuFlage, + // uint timeout, + // nint result); - [LibraryImport(user32dllPath, StringMarshalling = StringMarshalling.Utf16)] - public static partial nint FindWindowEx( - nint hwndParent, - nint hwndChildAfter, - string className, - string? winName); + [DllImport(user32dllPath, SetLastError = true)] + internal static extern int SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong); - [LibraryImport(user32dllPath)] - internal static partial nint SendMessageTimeout( - nint hwnd, - uint msg, - nint wParam, - nint lParam, - uint fuFlage, - uint timeout, - nint result); + internal const uint SWP_NOSIZE = 0x0001; + internal const uint SWP_NOMOVE = 0x0002; + internal const uint SWP_NOACTIVATE = 0x0010; + internal const int GWL_HWNDPARENT = -8; + + internal static readonly IntPtr HWND_BOTTOM = new(1); } public static class User32Extensions @@ -51,18 +81,18 @@ public static void MoveToBottom(this Window wpfWindow) var result = nint.Zero; - User32.SendMessageTimeout( + _ = User32.SendMessageTimeout( programIntPtr, - 0x052C, - nint.Zero, + 0x52C, + nuint.Zero, nint.Zero, 0x0000, - 1000, - nint.Zero + 2000, + out var temp_result ); // Foreach top layer windows - User32.EnumWindows((hwnd, lParam) => + _ = User32.EnumWindows((hwnd, lParam) => { // Find `WorkerW` which includes handle of `SHELLDLL_DefView` if (User32.FindWindowEx( @@ -81,14 +111,45 @@ public static void MoveToBottom(this Window wpfWindow) ); // Hide this window - User32.ShowWindow(tempHwnd, 0); + _ = User32.ShowWindow(tempHwnd, 0); } return true; }, nint.Zero); - User32.SetParent( - new System.Windows.Interop.WindowInteropHelper(wpfWindow).Handle, + _ = User32.SetParent( + new WindowInteropHelper(wpfWindow).Handle, programIntPtr ); } + + public static void SetBottom(this Window window) + { + IntPtr hWnd = new WindowInteropHelper(window).Handle; + _ = User32.SetWindowPos( + hWnd, + User32.HWND_BOTTOM, + 0, + 0, + 0, + 0, + User32.SWP_NOSIZE | User32.SWP_NOMOVE | User32.SWP_NOACTIVATE + ); + } + + public static void BottomMost(this Window window) + { + var hWnd = new WindowInteropHelper(window).Handle; + var hWndProgMan = User32.FindWindow("Progman", "Program Manager"); + _ = User32.SetParent(hWnd, hWndProgMan); + var handle = new WindowInteropHelper(Application.Current.MainWindow).Handle; + + IntPtr hprog = User32.FindWindowEx( + User32.FindWindowEx( + User32.FindWindow("Progman", "Program Manager"), + IntPtr.Zero, "SHELLDLL_DefView", "" + ), + IntPtr.Zero, "SysListView32", "FolderView" + ); + _ = User32.SetWindowLong(handle, User32.GWL_HWNDPARENT, hprog); + } } diff --git a/ClassScheduler.WPF/Views/MainWindow.xaml b/ClassScheduler.WPF/Views/MainWindow.xaml index a843b1a..272cb15 100644 --- a/ClassScheduler.WPF/Views/MainWindow.xaml +++ b/ClassScheduler.WPF/Views/MainWindow.xaml @@ -4,11 +4,52 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:ClassScheduler.WPF.Views" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - Title="ClassScheduler.WPF-Controller" - Width="600" - Height="250" + Title="ClassScheduler.WPF" + Width="460" + Height="600" + WindowStartupLocation="CenterScreen" mc:Ignorable="d"> - + + + + + + + + + + + +