This commit is contained in:
2026-02-14 15:59:10 +08:00
parent 97d5b12732
commit ec3a826e01
5 changed files with 1163 additions and 0 deletions
+5
View File
@@ -44,6 +44,8 @@ namespace Ink_Canvas
public static bool IsAppExitByUser;
// 新增:标记是否启用了UIA置顶功能
public static bool IsUIAccessTopMostEnabled;
// 新增:标记是否正在显示 OOBE(首次启动向导),看门狗在此期间不判定为卡死/假死
public static bool IsOobeShowing;
// 新增:退出信号文件路径
private static string watchdogExitSignalFile = Path.Combine(Path.GetTempPath(), "icc_watchdog_exit_" + Process.GetCurrentProcess().Id + ".flag");
// 新增:崩溃日志文件路径
@@ -1158,6 +1160,9 @@ namespace Ink_Canvas
watchdogTimer = new Timer(_ =>
{
if (IsOobeShowing)
return;
if (!isStartupComplete && appStartupStartTime != DateTime.MinValue)
{
DateTime startTime = _isSplashScreenShown && splashScreenStartTime != DateTime.MinValue
+37
View File
@@ -931,6 +931,8 @@ namespace Ink_Canvas
AutoBackupManager.Initialize(Settings);
CheckUpdateChannelAndTelemetryConsistency();
ShowOobeIfNeeded();
// 初始化Dlass上传队列(恢复上次的上传队列)
DlassNoteUploader.InitializeQueue();
@@ -1228,6 +1230,41 @@ namespace Ink_Canvas
AddTouchSupportToSliders();
}
private void ShowOobeIfNeeded()
{
try
{
if (Settings?.Startup == null) return;
if (Settings.Startup.HasShownOobe) return;
var oobeWindow = new OobeWindow(Settings)
{
Owner = this,
WindowStartupLocation = WindowStartupLocation.CenterOwner
};
try
{
App.IsOobeShowing = true;
oobeWindow.ShowDialog();
}
finally
{
App.IsOobeShowing = false;
}
Settings.Startup.HasShownOobe = true;
SaveSettingsToFile();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"显示首次启动体验(OOBE)时出错: {ex}", LogHelper.LogType.Error);
}
finally
{
App.IsOobeShowing = false;
}
}
private void SystemEventsOnDisplaySettingsChanged(object sender, EventArgs e)
{
if (!Settings.Advanced.IsEnableResolutionChangeDetection) return;
+2
View File
@@ -203,6 +203,8 @@ namespace Ink_Canvas
public TelemetryUploadLevel TelemetryUploadLevel { get; set; } = TelemetryUploadLevel.None;
[JsonProperty("hasAcceptedTelemetryPrivacy")]
public bool HasAcceptedTelemetryPrivacy { get; set; } = false;
[JsonProperty("hasShownOobe")]
public bool HasShownOobe { get; set; } = false;
}
public class Appearance
+530
View File
@@ -0,0 +1,530 @@
<Window x:Class="Ink_Canvas.Windows.OobeWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="欢迎使用 InkCanvasForClass"
Height="460"
Width="780"
WindowStartupLocation="CenterScreen"
ResizeMode="NoResize"
ShowInTaskbar="False"
Background="{DynamicResource SettingsPageBackground}"
Loaded="OobeWindow_OnLoaded">
<Grid Margin="24">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- Header -->
<StackPanel Orientation="Horizontal">
<StackPanel>
<TextBlock Text="欢迎使用 InkCanvasForClass"
FontSize="22"
FontWeight="SemiBold"
Foreground="{DynamicResource SettingsPageForeground}" />
<TextBlock Text="先完成一次简单设置,让课堂体验更稳定、更安全。"
Margin="0,6,0,0"
FontSize="13"
Foreground="{DynamicResource SettingsPageAnnotationForeground}"
TextWrapping="Wrap" />
</StackPanel>
</StackPanel>
<!-- Content -->
<ScrollViewer Grid.Row="1"
Margin="0,24,0,24"
VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Disabled">
<Border Padding="18"
Background="{DynamicResource SettingsPageBackground}"
CornerRadius="10">
<StackPanel>
<!-- 步骤标题与说明 -->
<TextBlock x:Name="StepIndicatorText"
FontSize="12"
Foreground="{DynamicResource SettingsPageAnnotationForeground}"
Text="步骤 1 / 12" />
<TextBlock x:Name="StepTitleText"
Margin="0,4,0,0"
FontSize="18"
FontWeight="SemiBold"
Foreground="{DynamicResource SettingsPageForeground}" />
<TextBlock x:Name="StepSubtitleText"
Margin="0,4,0,0"
FontSize="13"
Foreground="{DynamicResource SettingsPageAnnotationForeground}"
TextWrapping="Wrap" />
<!-- 步骤内容容器 -->
<Grid Margin="0,16,0,0">
<!-- 步骤 1:启动(对应设置 → 启动、高级 → 遥测) -->
<StackPanel x:Name="StepTelemetryPanel">
<TextBlock FontSize="12"
Foreground="{DynamicResource SettingsPageAnnotationForeground}"
Text="对应设置:启动、高级 → 遥测" />
<TextBlock Text="匿名使用数据与隐私"
Margin="0,6,0,0"
FontSize="16"
FontWeight="SemiBold"
Foreground="{DynamicResource SettingsPageForeground}" />
<TextBlock Margin="0,8,0,16"
FontSize="13"
Foreground="{DynamicResource SettingsPageAnnotationForeground}"
TextWrapping="Wrap">
<Run Text="InkCanvasForClass 可以选择上传" />
<Run Text="完全匿名" FontWeight="SemiBold" />
<Run Text="的使用统计,用于改进软件稳定性与性能。无论选择哪一项,课堂核心功能均可正常使用。" />
</TextBlock>
<StackPanel Margin="0,8,0,0">
<RadioButton x:Name="RadioTelemetryNone"
Content="不上传任何匿名使用数据"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
IsChecked="True"
Margin="0,0,0,6" />
<RadioButton x:Name="RadioTelemetryBasic"
Content="仅上传基础匿名使用数据(崩溃信息、版本与系统信息等)"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
Margin="0,0,0,6" />
<RadioButton x:Name="RadioTelemetryExtended"
Content="上传更多匿名使用数据(功能使用频率等,用于持续改进体验)"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}" />
</StackPanel>
<TextBlock Margin="0,16,0,0"
FontSize="12"
Foreground="{DynamicResource SettingsPageAnnotationForeground}"
TextWrapping="Wrap">
隐私说明:本软件不会收集课堂内容、学生个人信息或可识别您的原始墨迹内容,详情可查看安装目录中的 privacy.txt。
</TextBlock>
<TextBlock Margin="0,12,0,0"
FontSize="12"
Foreground="{DynamicResource SettingsPageAnnotationForeground}">
启动与更新选项(对应 设置 → 启动)
</TextBlock>
<CheckBox x:Name="CheckBoxFoldAtStartup"
Margin="0,6,0,0"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
Content="启动时自动将浮动工具栏收纳到屏幕边缘" />
<CheckBox x:Name="CheckBoxAutoUpdate"
Margin="0,4,0,0"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
Content="允许自动检查更新并在后台下载新版本" />
</StackPanel>
<!-- 步骤 2:画板和墨迹(对应设置 → 画板和墨迹) -->
<StackPanel x:Name="StepCanvasPanel" Visibility="Collapsed">
<TextBlock FontSize="12"
Foreground="{DynamicResource SettingsPageAnnotationForeground}"
Text="对应设置:画板和墨迹" />
<TextBlock Text="画板与墨迹"
Margin="0,6,0,0"
FontSize="16"
FontWeight="SemiBold"
Foreground="{DynamicResource SettingsPageForeground}" />
<TextBlock Margin="0,8,0,12"
FontSize="13"
Foreground="{DynamicResource SettingsPageAnnotationForeground}"
TextWrapping="Wrap">
画笔光标、压感、墨迹显示等可在 设置 → 画板和墨迹 中修改。
</TextBlock>
<CheckBox x:Name="CheckBoxShowCursor"
Margin="0,4,0,0"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
Content="显示画笔光标(绘制时显示光标位置)" />
<CheckBox x:Name="CheckBoxDisablePressure"
Margin="0,4,0,0"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
Content="屏蔽压感(所有笔画统一粗细)" />
<CheckBox x:Name="CheckBoxHideStrokeWhenSelecting"
Margin="0,4,0,0"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
Content="退出画板模式时隐藏墨迹(进入 PPT 非批注模式不显示墨迹)" />
</StackPanel>
<!-- 步骤 3:手势操作(对应设置 → 手势操作) -->
<StackPanel x:Name="StepGesturesPanel" Visibility="Collapsed">
<TextBlock FontSize="12"
Foreground="{DynamicResource SettingsPageAnnotationForeground}"
Text="对应设置:手势操作" />
<TextBlock Text="手势操作"
Margin="0,6,0,0"
FontSize="16"
FontWeight="SemiBold"
Foreground="{DynamicResource SettingsPageForeground}" />
<TextBlock Margin="0,8,0,12"
FontSize="13"
Foreground="{DynamicResource SettingsPageAnnotationForeground}"
TextWrapping="Wrap">
双指缩放、平移、旋转及手掌擦等可在 设置 → 手势操作 中修改。
</TextBlock>
<CheckBox x:Name="CheckBoxTwoFingerZoom"
Margin="0,4,0,0"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
Content="启用双指缩放" />
<CheckBox x:Name="CheckBoxTwoFingerTranslate"
Margin="0,4,0,0"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
Content="启用双指平移" />
<CheckBox x:Name="CheckBoxAutoSwitchTwoFingerGesture"
Margin="0,4,0,0"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
Content="进退白板模式时自动开关双指移动" />
<CheckBox x:Name="CheckBoxEnablePalmEraser"
Margin="0,4,0,0"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
Content="启用手掌擦(多触点且触摸面积大时临时切换为橡皮)" />
</StackPanel>
<!-- 步骤 4:墨迹纠正(对应设置 → 墨迹纠正) -->
<StackPanel x:Name="StepInkRecognitionPanel" Visibility="Collapsed">
<TextBlock FontSize="12"
Foreground="{DynamicResource SettingsPageAnnotationForeground}"
Text="对应设置:墨迹纠正" />
<TextBlock Text="墨迹纠正"
Margin="0,6,0,0"
FontSize="16"
FontWeight="SemiBold"
Foreground="{DynamicResource SettingsPageForeground}" />
<TextBlock Margin="0,8,0,12"
FontSize="13"
Foreground="{DynamicResource SettingsPageAnnotationForeground}"
TextWrapping="Wrap">
手绘图形识别为标准形状等可在 设置 → 墨迹纠正 中修改。
</TextBlock>
<CheckBox x:Name="CheckBoxInkToShapeEnabled"
Margin="0,4,0,0"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
Content="启用墨迹识别(手绘图形自动转为标准形状)" />
</StackPanel>
<!-- 步骤 5:个性化设置(对应设置 → 个性化设置) -->
<StackPanel x:Name="StepAppearancePanel" Visibility="Collapsed">
<TextBlock FontSize="12"
Foreground="{DynamicResource SettingsPageAnnotationForeground}"
Text="对应设置:外观" />
<TextBlock Text="外观与界面"
Margin="0,6,0,0"
FontSize="16"
FontWeight="SemiBold"
Foreground="{DynamicResource SettingsPageForeground}" />
<TextBlock Margin="0,8,0,12"
FontSize="13"
Foreground="{DynamicResource SettingsPageAnnotationForeground}"
TextWrapping="Wrap">
主题、启动动画、托盘图标等均可在 设置 → 外观 中修改。
</TextBlock>
<!-- 主题 -->
<StackPanel Margin="0,4,0,0">
<TextBlock Text="应用主题"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}" />
<StackPanel Orientation="Horizontal"
Margin="0,4,0,0">
<RadioButton x:Name="RadioThemeFollowSystem"
Content="跟随系统"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
Margin="0,0,12,0" />
<RadioButton x:Name="RadioThemeLight"
Content="浅色"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
Margin="0,0,12,0" />
<RadioButton x:Name="RadioThemeDark"
Content="深色"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}" />
</StackPanel>
</StackPanel>
<CheckBox x:Name="CheckBoxEnableSplashScreen"
Margin="0,10,0,0"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
Content="启用启动动画(全屏欢迎页)" />
<!-- 托盘与快速面板 -->
<CheckBox x:Name="CheckBoxEnableTrayIcon"
Margin="0,10,0,0"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
Content="在系统托盘显示 InkCanvasForClass 图标,方便后台快速唤出" />
<CheckBox x:Name="CheckBoxShowQuickPanel"
Margin="0,4,0,0"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
Content="在主界面底部显示快速工具栏(计时器、点名等)" />
</StackPanel>
<!-- 步骤 6:快捷键设置(对应设置 → 快捷键设置) -->
<StackPanel x:Name="StepShortcutsPanel" Visibility="Collapsed">
<TextBlock FontSize="12"
Foreground="{DynamicResource SettingsPageAnnotationForeground}"
Text="对应设置:快捷键设置" />
<TextBlock Text="快捷键设置"
Margin="0,6,0,0"
FontSize="16"
FontWeight="SemiBold"
Foreground="{DynamicResource SettingsPageForeground}" />
<TextBlock Margin="0,8,0,12"
FontSize="13"
Foreground="{DynamicResource SettingsPageAnnotationForeground}"
TextWrapping="Wrap">
具体快捷键可在 设置 → 快捷键设置 中配置。
</TextBlock>
<CheckBox x:Name="CheckBoxEnableHotkeysInMouseMode"
Margin="0,4,0,0"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
Content="鼠标模式下启用全局快捷键" />
</StackPanel>
<!-- 步骤 7:崩溃处理(对应设置 → 崩溃处理) -->
<StackPanel x:Name="StepCrashActionPanel" Visibility="Collapsed">
<TextBlock FontSize="12"
Foreground="{DynamicResource SettingsPageAnnotationForeground}"
Text="对应设置:崩溃处理" />
<TextBlock Text="崩溃处理"
Margin="0,6,0,0"
FontSize="16"
FontWeight="SemiBold"
Foreground="{DynamicResource SettingsPageForeground}" />
<TextBlock Margin="0,8,0,12"
FontSize="13"
Foreground="{DynamicResource SettingsPageAnnotationForeground}"
TextWrapping="Wrap">
发生未处理异常时的行为可在 设置 → 崩溃处理 中修改。
</TextBlock>
<StackPanel Margin="0,4,0,0">
<RadioButton x:Name="RadioCrashSilentRestart"
Content="静默重启软件(推荐)"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
IsChecked="True"
Margin="0,0,0,6" />
<RadioButton x:Name="RadioCrashNoAction"
Content="无操作(仅记录日志)"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}" />
</StackPanel>
</StackPanel>
<!-- 步骤 8:课件与放映(对应设置 → PPT) -->
<StackPanel x:Name="StepPptPanel" Visibility="Collapsed">
<TextBlock FontSize="12"
Foreground="{DynamicResource SettingsPageAnnotationForeground}"
Text="对应设置:PPT(课件与放映)" />
<TextBlock Text="课件与 PPT 联动"
Margin="0,6,0,0"
FontSize="16"
FontWeight="SemiBold"
Foreground="{DynamicResource SettingsPageForeground}" />
<TextBlock Margin="0,8,0,12"
FontSize="13"
Foreground="{DynamicResource SettingsPageAnnotationForeground}"
TextWrapping="Wrap">
以下选项均可在 设置 → PPT 中修改,用于与 PowerPoint/WPS 放映联动。
</TextBlock>
<CheckBox x:Name="CheckBoxPptSupport"
Margin="0,4,0,0"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
Content="启用与 PowerPoint/WPS 的联动支持(在幻灯片中一键呼出画板)" />
<CheckBox x:Name="CheckBoxPptAutoSaveStrokes"
Margin="0,4,0,0"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
Content="在 PPT 放映中自动保存所有墨迹(避免误关丢失板书)" />
<CheckBox x:Name="CheckBoxPptAutoSaveScreenshots"
Margin="0,4,0,0"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
Content="在 PPT 放映中自动保存截屏(用于事后回看课堂内容)" />
<CheckBox x:Name="CheckBoxPptTimeCapsule"
Margin="0,4,0,0"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
Content="启用 PPT 时间胶囊(放映时显示时间提醒)" />
</StackPanel>
<!-- 步骤 9:自动化行为(对应设置 → 自动化行为) -->
<StackPanel x:Name="StepAutomationPanel" Visibility="Collapsed">
<TextBlock FontSize="12"
Foreground="{DynamicResource SettingsPageAnnotationForeground}"
Text="对应设置:自动化行为" />
<TextBlock Text="自动化行为"
Margin="0,6,0,0"
FontSize="16"
FontWeight="SemiBold"
Foreground="{DynamicResource SettingsPageForeground}" />
<TextBlock Margin="0,8,0,12"
FontSize="13"
Foreground="{DynamicResource SettingsPageAnnotationForeground}"
TextWrapping="Wrap">
进入/退出特定软件时自动收纳、墨迹自动保存、悬浮窗拦截等可在 设置 → 自动化行为 中修改。
</TextBlock>
<CheckBox x:Name="CheckBoxAutoFoldInPPTSlideShow"
Margin="0,4,0,0"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
Content="进入 PPT 放映时自动收纳到侧边" />
<CheckBox x:Name="CheckBoxEnableAutoSaveStrokes"
Margin="0,4,0,0"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
Content="启用墨迹自动保存(定时保存到本地)" />
<CheckBox x:Name="CheckBoxFloatingWindowInterceptorEnabled"
Margin="0,8,0,0"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
Content="启用悬浮窗拦截(拦截希沃、鸿合等课堂软件的悬浮窗,避免遮挡画板)" />
<CheckBox x:Name="CheckBoxFloatingWindowInterceptorAutoStart"
Margin="0,4,0,0"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
Content="悬浮窗拦截随软件启动自动开启" />
</StackPanel>
<!-- 步骤 10:随机点名(对应设置 → 随机点名) -->
<StackPanel x:Name="StepLuckyRandomPanel" Visibility="Collapsed">
<TextBlock FontSize="12"
Foreground="{DynamicResource SettingsPageAnnotationForeground}"
Text="对应设置:随机点名" />
<TextBlock Text="随机点名"
Margin="0,6,0,0"
FontSize="16"
FontWeight="SemiBold"
Foreground="{DynamicResource SettingsPageForeground}" />
<TextBlock Margin="0,8,0,12"
FontSize="13"
Foreground="{DynamicResource SettingsPageAnnotationForeground}"
TextWrapping="Wrap">
点名窗口样式与行为可在 设置 → 随机点名 中修改。
</TextBlock>
<CheckBox x:Name="CheckBoxShowRandomAndSingleDraw"
Margin="0,4,0,0"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
Content="显示随机抽和单次抽按钮" />
</StackPanel>
<!-- 步骤 11:高级选项(对应设置 → 高级选项) -->
<StackPanel x:Name="StepAdvancedPanel" Visibility="Collapsed">
<TextBlock FontSize="12"
Foreground="{DynamicResource SettingsPageAnnotationForeground}"
Text="对应设置:高级选项" />
<TextBlock Text="高级选项"
Margin="0,6,0,0"
FontSize="16"
FontWeight="SemiBold"
Foreground="{DynamicResource SettingsPageForeground}" />
<TextBlock Margin="0,8,0,12"
FontSize="13"
Foreground="{DynamicResource SettingsPageAnnotationForeground}"
TextWrapping="Wrap">
日志、特殊屏幕、窗口模式等可在 设置 → 高级选项 中修改。
</TextBlock>
<CheckBox x:Name="CheckBoxIsLogEnabled"
Margin="0,4,0,0"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
Content="启用日志(便于问题排查)" />
</StackPanel>
<!-- 步骤 12:截图和屏幕捕捉(对应设置 → 截图和屏幕捕捉) -->
<StackPanel x:Name="StepSnapshotPanel" Visibility="Collapsed">
<TextBlock FontSize="12"
Foreground="{DynamicResource SettingsPageAnnotationForeground}"
Text="对应设置:截图和屏幕捕捉" />
<TextBlock Text="截图和屏幕捕捉"
Margin="0,6,0,0"
FontSize="16"
FontWeight="SemiBold"
Foreground="{DynamicResource SettingsPageForeground}" />
<TextBlock Margin="0,8,0,12"
FontSize="13"
Foreground="{DynamicResource SettingsPageAnnotationForeground}"
TextWrapping="Wrap">
清屏截图、按日期保存等可在 设置 → 截图和屏幕捕捉 中修改。
</TextBlock>
<CheckBox x:Name="CheckBoxAutoSaveStrokesAtClear"
Margin="0,4,0,0"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
Content="清屏时自动保存截图" />
<CheckBox x:Name="CheckBoxSaveScreenshotsInDateFolders"
Margin="0,4,0,0"
FontSize="13"
Foreground="{DynamicResource SettingsPageForeground}"
Content="截图按日期分文件夹保存" />
</StackPanel>
</Grid>
</StackPanel>
</Border>
</ScrollViewer>
<!-- Footer -->
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
VerticalAlignment="Center"
FontSize="12"
Foreground="{DynamicResource SettingsPageAnnotationForeground}"
TextWrapping="Wrap">
此向导仅在首次启动时出现;之后可在 设置 中按侧边栏分区修改对应选项。
</TextBlock>
<Button x:Name="BtnPreviousStep"
Grid.Column="1"
Width="100"
Height="32"
Margin="0,0,8,0"
Content="上一步"
Background="#FF3A3A3A"
Foreground="White"
BorderBrush="#FF505050"
Click="BtnPreviousStep_Click" />
<Button x:Name="BtnConfirm"
Grid.Column="2"
Width="140"
Height="32"
Content="保存并开始使用"
Background="#FF0078D4"
Foreground="White"
BorderBrush="#FF0078D4"
Click="BtnConfirm_Click" />
</Grid>
</Grid>
</Window>
+589
View File
@@ -0,0 +1,589 @@
using System;
using System.Windows;
namespace Ink_Canvas.Windows
{
/// <summary>
/// 首次启动体验(OOBE)窗口,用于引导用户选择遥测与隐私设置。
/// </summary>
public partial class OobeWindow : Window
{
private readonly Settings _settings;
private int _currentStep = 0;
private const int MaxStepIndex = 11;
public OobeWindow(Settings settings)
{
if (settings == null) throw new ArgumentNullException(nameof(settings));
_settings = settings;
InitializeComponent();
// 初始时设置为透明,等待加载完成后淡入
Opacity = 0;
InitializeFromSettings();
UpdateStepUI();
}
private void InitializeFromSettings()
{
// 根据当前设置回显遥测选项
switch (_settings.Startup.TelemetryUploadLevel)
{
case TelemetryUploadLevel.Basic:
RadioTelemetryBasic.IsChecked = true;
break;
case TelemetryUploadLevel.Extended:
RadioTelemetryExtended.IsChecked = true;
break;
case TelemetryUploadLevel.None:
default:
RadioTelemetryNone.IsChecked = true;
break;
}
// 主题与外观设置
try
{
if (_settings.Appearance != null)
{
switch (_settings.Appearance.Theme)
{
case 0: // 浅色
RadioThemeLight.IsChecked = true;
break;
case 1: // 深色
RadioThemeDark.IsChecked = true;
break;
case 2: // 跟随系统
default:
RadioThemeFollowSystem.IsChecked = true;
break;
}
CheckBoxEnableSplashScreen.IsChecked = _settings.Appearance.EnableSplashScreen;
}
}
catch
{
// 忽略外观初始化异常,避免影响启动
}
// 启动行为设置
try
{
if (_settings.Startup != null)
{
CheckBoxFoldAtStartup.IsChecked = _settings.Startup.IsFoldAtStartup;
CheckBoxAutoUpdate.IsChecked = _settings.Startup.IsAutoUpdate;
}
}
catch
{
// 忽略启动行为初始化异常
}
// 托盘与快速面板
try
{
if (_settings.Appearance != null)
{
CheckBoxEnableTrayIcon.IsChecked = _settings.Appearance.EnableTrayIcon;
CheckBoxShowQuickPanel.IsChecked = _settings.Appearance.IsShowQuickPanel;
}
}
catch
{
// 忽略托盘/快速面板初始化异常
}
// PPT 联动
try
{
if (_settings.PowerPointSettings != null)
{
CheckBoxPptSupport.IsChecked = _settings.PowerPointSettings.PowerPointSupport;
CheckBoxPptAutoSaveStrokes.IsChecked = _settings.PowerPointSettings.IsAutoSaveStrokesInPowerPoint;
CheckBoxPptAutoSaveScreenshots.IsChecked = _settings.PowerPointSettings.IsAutoSaveScreenShotInPowerPoint;
CheckBoxPptTimeCapsule.IsChecked = _settings.PowerPointSettings.EnablePPTTimeCapsule;
}
}
catch
{
// 忽略 PPT 联动初始化异常
}
// 画板和墨迹
try
{
if (_settings.Canvas != null)
{
CheckBoxShowCursor.IsChecked = _settings.Canvas.IsShowCursor;
CheckBoxDisablePressure.IsChecked = _settings.Canvas.DisablePressure;
CheckBoxHideStrokeWhenSelecting.IsChecked = _settings.Canvas.HideStrokeWhenSelecting;
}
}
catch { }
// 手势操作
try
{
if (_settings.Gesture != null)
{
CheckBoxTwoFingerZoom.IsChecked = _settings.Gesture.IsEnableTwoFingerZoom;
CheckBoxTwoFingerTranslate.IsChecked = _settings.Gesture.IsEnableTwoFingerTranslate;
CheckBoxAutoSwitchTwoFingerGesture.IsChecked = _settings.Gesture.AutoSwitchTwoFingerGesture;
CheckBoxEnablePalmEraser.IsChecked = _settings.Canvas != null && _settings.Canvas.EnablePalmEraser;
}
}
catch { }
// 墨迹纠正
try
{
if (_settings.InkToShape != null)
{
CheckBoxInkToShapeEnabled.IsChecked = _settings.InkToShape.IsInkToShapeEnabled;
}
}
catch { }
// 快捷键(外观)
try
{
if (_settings.Appearance != null)
{
CheckBoxEnableHotkeysInMouseMode.IsChecked = _settings.Appearance.EnableHotkeysInMouseMode;
}
}
catch { }
// 崩溃处理
try
{
RadioCrashSilentRestart.IsChecked = _settings.Startup.CrashAction == 0;
RadioCrashNoAction.IsChecked = _settings.Startup.CrashAction != 0;
}
catch { }
// 自动化行为
try
{
if (_settings.Automation != null)
{
CheckBoxAutoFoldInPPTSlideShow.IsChecked = _settings.Automation.IsAutoFoldInPPTSlideShow;
CheckBoxEnableAutoSaveStrokes.IsChecked = _settings.Automation.IsEnableAutoSaveStrokes;
if (_settings.Automation.FloatingWindowInterceptor != null)
{
CheckBoxFloatingWindowInterceptorEnabled.IsChecked = _settings.Automation.FloatingWindowInterceptor.IsEnabled;
CheckBoxFloatingWindowInterceptorAutoStart.IsChecked = _settings.Automation.FloatingWindowInterceptor.AutoStart;
}
}
}
catch { }
// 随机点名
try
{
if (_settings.RandSettings != null)
{
CheckBoxShowRandomAndSingleDraw.IsChecked = _settings.RandSettings.ShowRandomAndSingleDraw;
}
}
catch { }
// 高级选项
try
{
if (_settings.Advanced != null)
{
CheckBoxIsLogEnabled.IsChecked = _settings.Advanced.IsLogEnabled;
}
}
catch { }
// 截图(自动化中的截图相关)
try
{
if (_settings.Automation != null)
{
CheckBoxAutoSaveStrokesAtClear.IsChecked = _settings.Automation.IsAutoSaveStrokesAtClear;
CheckBoxSaveScreenshotsInDateFolders.IsChecked = _settings.Automation.IsSaveScreenshotsInDateFolders;
}
}
catch { }
}
private void ApplySelection()
{
// 将当前遥测选项写回到设置
if (RadioTelemetryBasic.IsChecked == true)
{
_settings.Startup.TelemetryUploadLevel = TelemetryUploadLevel.Basic;
}
else if (RadioTelemetryExtended.IsChecked == true)
{
_settings.Startup.TelemetryUploadLevel = TelemetryUploadLevel.Extended;
}
else
{
_settings.Startup.TelemetryUploadLevel = TelemetryUploadLevel.None;
}
// 写回主题与外观设置
try
{
if (_settings.Appearance != null)
{
if (RadioThemeLight.IsChecked == true)
{
_settings.Appearance.Theme = 0;
}
else if (RadioThemeDark.IsChecked == true)
{
_settings.Appearance.Theme = 1;
}
else
{
// 默认视为跟随系统
_settings.Appearance.Theme = 2;
}
_settings.Appearance.EnableSplashScreen = CheckBoxEnableSplashScreen.IsChecked == true;
}
}
catch
{
// 忽略外观写回异常
}
// 写回启动行为设置
try
{
if (_settings.Startup != null)
{
_settings.Startup.IsFoldAtStartup = CheckBoxFoldAtStartup.IsChecked == true;
_settings.Startup.IsAutoUpdate = CheckBoxAutoUpdate.IsChecked == true;
}
}
catch
{
// 忽略启动行为写回异常
}
// 写回托盘与快速面板设置
try
{
if (_settings.Appearance != null)
{
_settings.Appearance.EnableTrayIcon = CheckBoxEnableTrayIcon.IsChecked == true;
_settings.Appearance.IsShowQuickPanel = CheckBoxShowQuickPanel.IsChecked == true;
}
}
catch
{
// 忽略托盘/快速面板写回异常
}
// 写回 PPT 联动设置
try
{
if (_settings.PowerPointSettings != null)
{
_settings.PowerPointSettings.PowerPointSupport = CheckBoxPptSupport.IsChecked == true;
_settings.PowerPointSettings.IsAutoSaveStrokesInPowerPoint = CheckBoxPptAutoSaveStrokes.IsChecked == true;
_settings.PowerPointSettings.IsAutoSaveScreenShotInPowerPoint = CheckBoxPptAutoSaveScreenshots.IsChecked == true;
_settings.PowerPointSettings.EnablePPTTimeCapsule = CheckBoxPptTimeCapsule.IsChecked == true;
}
}
catch
{
// 忽略 PPT 联动写回异常
}
// 写回画板和墨迹
try
{
if (_settings.Canvas != null)
{
_settings.Canvas.IsShowCursor = CheckBoxShowCursor.IsChecked == true;
_settings.Canvas.DisablePressure = CheckBoxDisablePressure.IsChecked == true;
_settings.Canvas.HideStrokeWhenSelecting = CheckBoxHideStrokeWhenSelecting.IsChecked == true;
_settings.Canvas.EnablePalmEraser = CheckBoxEnablePalmEraser.IsChecked == true;
}
}
catch { }
// 写回手势操作
try
{
if (_settings.Gesture != null)
{
_settings.Gesture.IsEnableTwoFingerZoom = CheckBoxTwoFingerZoom.IsChecked == true;
_settings.Gesture.IsEnableTwoFingerTranslate = CheckBoxTwoFingerTranslate.IsChecked == true;
_settings.Gesture.AutoSwitchTwoFingerGesture = CheckBoxAutoSwitchTwoFingerGesture.IsChecked == true;
}
}
catch { }
// 写回墨迹纠正
try
{
if (_settings.InkToShape != null)
{
_settings.InkToShape.IsInkToShapeEnabled = CheckBoxInkToShapeEnabled.IsChecked == true;
}
}
catch { }
// 写回快捷键(外观)
try
{
if (_settings.Appearance != null)
{
_settings.Appearance.EnableHotkeysInMouseMode = CheckBoxEnableHotkeysInMouseMode.IsChecked == true;
}
}
catch { }
// 写回崩溃处理(0=静默重启,1=无操作)
try
{
_settings.Startup.CrashAction = RadioCrashNoAction.IsChecked == true ? 1 : 0;
}
catch { }
// 写回自动化行为
try
{
if (_settings.Automation != null)
{
_settings.Automation.IsAutoFoldInPPTSlideShow = CheckBoxAutoFoldInPPTSlideShow.IsChecked == true;
_settings.Automation.IsEnableAutoSaveStrokes = CheckBoxEnableAutoSaveStrokes.IsChecked == true;
_settings.Automation.IsAutoSaveStrokesAtClear = CheckBoxAutoSaveStrokesAtClear.IsChecked == true;
_settings.Automation.IsSaveScreenshotsInDateFolders = CheckBoxSaveScreenshotsInDateFolders.IsChecked == true;
if (_settings.Automation.FloatingWindowInterceptor != null)
{
_settings.Automation.FloatingWindowInterceptor.IsEnabled = CheckBoxFloatingWindowInterceptorEnabled.IsChecked == true;
_settings.Automation.FloatingWindowInterceptor.AutoStart = CheckBoxFloatingWindowInterceptorAutoStart.IsChecked == true;
}
}
}
catch { }
// 写回随机点名
try
{
if (_settings.RandSettings != null)
{
_settings.RandSettings.ShowRandomAndSingleDraw = CheckBoxShowRandomAndSingleDraw.IsChecked == true;
}
}
catch { }
// 写回高级选项
try
{
if (_settings.Advanced != null)
{
_settings.Advanced.IsLogEnabled = CheckBoxIsLogEnabled.IsChecked == true;
}
}
catch { }
// 标记用户已经阅读并确认过隐私说明
_settings.Startup.HasAcceptedTelemetryPrivacy = true;
}
private void BtnConfirm_Click(object sender, RoutedEventArgs e)
{
// 如果还没到最后一步,则进入下一步
if (_currentStep < MaxStepIndex)
{
_currentStep++;
UpdateStepUI();
return;
}
// 最后一步:应用选择并关闭窗口
ApplySelection();
DialogResult = true;
Close();
}
private void BtnPreviousStep_Click(object sender, RoutedEventArgs e)
{
if (_currentStep <= 0) return;
_currentStep--;
UpdateStepUI();
}
/// <summary>
/// 窗口加载完成时触发淡入动画。
/// </summary>
private void OobeWindow_OnLoaded(object sender, RoutedEventArgs e)
{
try
{
var animation = new System.Windows.Media.Animation.DoubleAnimation
{
From = 0,
To = 1,
Duration = TimeSpan.FromMilliseconds(220),
EasingFunction = new System.Windows.Media.Animation.CubicEase
{
EasingMode = System.Windows.Media.Animation.EasingMode.EaseOut
}
};
BeginAnimation(OpacityProperty, animation);
}
catch
{
// 动画失败时直接显示
Opacity = 1;
}
}
/// <summary>
/// 根据当前步骤更新界面显示和按钮文案。
/// </summary>
private void UpdateStepUI()
{
try
{
StepTelemetryPanel.Visibility = _currentStep == 0 ? Visibility.Visible : Visibility.Collapsed;
StepCanvasPanel.Visibility = _currentStep == 1 ? Visibility.Visible : Visibility.Collapsed;
StepGesturesPanel.Visibility = _currentStep == 2 ? Visibility.Visible : Visibility.Collapsed;
StepInkRecognitionPanel.Visibility = _currentStep == 3 ? Visibility.Visible : Visibility.Collapsed;
StepAppearancePanel.Visibility = _currentStep == 4 ? Visibility.Visible : Visibility.Collapsed;
StepShortcutsPanel.Visibility = _currentStep == 5 ? Visibility.Visible : Visibility.Collapsed;
StepCrashActionPanel.Visibility = _currentStep == 6 ? Visibility.Visible : Visibility.Collapsed;
StepPptPanel.Visibility = _currentStep == 7 ? Visibility.Visible : Visibility.Collapsed;
StepAutomationPanel.Visibility = _currentStep == 8 ? Visibility.Visible : Visibility.Collapsed;
StepLuckyRandomPanel.Visibility = _currentStep == 9 ? Visibility.Visible : Visibility.Collapsed;
StepAdvancedPanel.Visibility = _currentStep == 10 ? Visibility.Visible : Visibility.Collapsed;
StepSnapshotPanel.Visibility = _currentStep == 11 ? Visibility.Visible : Visibility.Collapsed;
FrameworkElement activePanel = null;
if (_currentStep == 0) activePanel = StepTelemetryPanel;
else if (_currentStep == 1) activePanel = StepCanvasPanel;
else if (_currentStep == 2) activePanel = StepGesturesPanel;
else if (_currentStep == 3) activePanel = StepInkRecognitionPanel;
else if (_currentStep == 4) activePanel = StepAppearancePanel;
else if (_currentStep == 5) activePanel = StepShortcutsPanel;
else if (_currentStep == 6) activePanel = StepCrashActionPanel;
else if (_currentStep == 7) activePanel = StepPptPanel;
else if (_currentStep == 8) activePanel = StepAutomationPanel;
else if (_currentStep == 9) activePanel = StepLuckyRandomPanel;
else if (_currentStep == 10) activePanel = StepAdvancedPanel;
else if (_currentStep == 11) activePanel = StepSnapshotPanel;
if (activePanel != null)
{
activePanel.Opacity = 0;
var transform = activePanel.RenderTransform as System.Windows.Media.TranslateTransform;
if (transform == null)
{
transform = new System.Windows.Media.TranslateTransform(0, 12);
activePanel.RenderTransform = transform;
}
else
{
transform.Y = 12;
}
var fade = new System.Windows.Media.Animation.DoubleAnimation
{
From = 0,
To = 1,
Duration = TimeSpan.FromMilliseconds(200),
EasingFunction = new System.Windows.Media.Animation.CubicEase
{
EasingMode = System.Windows.Media.Animation.EasingMode.EaseOut
}
};
var slide = new System.Windows.Media.Animation.DoubleAnimation
{
From = 12,
To = 0,
Duration = TimeSpan.FromMilliseconds(200),
EasingFunction = new System.Windows.Media.Animation.CubicEase
{
EasingMode = System.Windows.Media.Animation.EasingMode.EaseOut
}
};
activePanel.BeginAnimation(OpacityProperty, fade);
transform.BeginAnimation(System.Windows.Media.TranslateTransform.YProperty, slide);
}
StepIndicatorText.Text = $"步骤 {_currentStep + 1} / 12";
BtnPreviousStep.Visibility = _currentStep > 0 ? Visibility.Visible : Visibility.Collapsed;
switch (_currentStep)
{
case 0:
StepTitleText.Text = "启动时行为";
StepSubtitleText.Text = "遥测、自动更新与启动行为,对应 设置 → 启动时行为、高级 → 遥测。";
break;
case 1:
StepTitleText.Text = "画板和墨迹";
StepSubtitleText.Text = "画笔光标、压感、墨迹显示,对应 设置 → 画板和墨迹。";
break;
case 2:
StepTitleText.Text = "手势操作";
StepSubtitleText.Text = "双指缩放/平移、手掌擦等,对应 设置 → 手势操作。";
break;
case 3:
StepTitleText.Text = "墨迹纠正";
StepSubtitleText.Text = "手绘图形识别为标准形状,对应 设置 → 墨迹纠正。";
break;
case 4:
StepTitleText.Text = "个性化设置";
StepSubtitleText.Text = "主题、启动动画、托盘与快速工具栏,对应 设置 → 个性化设置。";
break;
case 5:
StepTitleText.Text = "快捷键设置";
StepSubtitleText.Text = "鼠标模式下全局快捷键,对应 设置 → 快捷键设置。";
break;
case 6:
StepTitleText.Text = "崩溃处理";
StepSubtitleText.Text = "未处理异常时的行为,对应 设置 → 崩溃处理。";
break;
case 7:
StepTitleText.Text = "PowerPoint 支持";
StepSubtitleText.Text = "放映联动与墨迹保存等,对应 设置 → PowerPoint 支持。";
break;
case 8:
StepTitleText.Text = "自动化行为";
StepSubtitleText.Text = "自动收纳、墨迹自动保存等,对应 设置 → 自动化行为。";
break;
case 9:
StepTitleText.Text = "随机点名";
StepSubtitleText.Text = "点名窗口选项,对应 设置 → 随机点名。";
break;
case 10:
StepTitleText.Text = "高级选项";
StepSubtitleText.Text = "日志、特殊屏幕等,对应 设置 → 高级选项。";
break;
case 11:
StepTitleText.Text = "截图和屏幕捕捉";
StepSubtitleText.Text = "清屏截图、按日期保存等,对应 设置 → 截图和屏幕捕捉。";
break;
}
BtnConfirm.Content = _currentStep == MaxStepIndex ? "保存并开始使用" : "下一步";
}
catch
{
// 忽略 UI 更新异常,避免影响主流程
}
}
}
}