Files
community/Ink Canvas/Windows/PPTQuickPanel.xaml.cs
T

1928 lines
80 KiB
C#
Raw Normal View History

2026-04-05 17:31:35 +08:00
using Ink_Canvas.Controls;
2025-12-31 18:42:26 +08:00
using Ink_Canvas.Helpers;
2026-03-03 16:04:20 +08:00
using Microsoft.Win32;
using Newtonsoft.Json;
2025-12-31 18:42:26 +08:00
using System;
2025-12-31 19:24:10 +08:00
using System.Collections.Generic;
2026-01-10 20:09:20 +08:00
using System.Collections.Specialized;
2025-12-31 19:24:10 +08:00
using System.IO;
using System.Linq;
2025-12-31 18:42:26 +08:00
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
2026-01-10 20:09:20 +08:00
using System.Windows.Media.Imaging;
2025-12-31 18:42:26 +08:00
using System.Windows.Threading;
using SystemEvents = Microsoft.Win32.SystemEvents;
namespace Ink_Canvas.Windows
{
/// <summary>
/// PPT侧滑快捷面板
/// </summary>
public partial class PPTQuickPanel : UserControl
{
// Windows Core Audio API
[ComImport]
[Guid("5CDF2C82-841E-4546-9722-0CF74078229A")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IAudioEndpointVolume
{
int NotImpl1();
int NotImpl2();
int GetChannelCount(out int channelCount);
int SetMasterVolumeLevel(float level, Guid eventContext);
int SetMasterVolumeLevelScalar(float level, Guid eventContext);
int GetMasterVolumeLevel(out float level);
int GetMasterVolumeLevelScalar(out float level);
int SetChannelVolumeLevel(uint channelNumber, float level, Guid eventContext);
int SetChannelVolumeLevelScalar(uint channelNumber, float level, Guid eventContext);
int GetChannelVolumeLevel(uint channelNumber, out float level);
int GetChannelVolumeLevelScalar(uint channelNumber, out float level);
int SetMute([MarshalAs(UnmanagedType.Bool)] bool mute, Guid eventContext);
int GetMute(out bool mute);
}
[ComImport]
[Guid("D666063F-1587-4E43-81F1-B948E807363F")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IMMDevice
{
int Activate(ref Guid iid, int clsCtx, IntPtr activationParams, [MarshalAs(UnmanagedType.IUnknown)] out object interfacePointer);
int OpenPropertyStore(int stgmAccess, out IPropertyStore propertyStore);
int GetId([MarshalAs(UnmanagedType.LPWStr)] out string id);
int GetState(out int state);
}
[ComImport]
[Guid("A95664D2-9614-4F35-A746-DE8DB63617E6")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IMMDeviceEnumerator
{
int NotImpl1();
int GetDefaultAudioEndpoint(int dataFlow, int role, out IMMDevice device);
}
[ComImport]
[Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IPropertyStore
{
int GetCount(out int propertyCount);
int GetAt(int propertyIndex, out Guid propertyKey);
int GetValue(ref Guid propertyKey, out object value);
int SetValue(ref Guid propertyKey, ref object value);
int Commit();
}
private static class MMDeviceEnumeratorFactory
{
[ComImport]
[Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")]
private class MMDeviceEnumerator
{
}
public static IMMDeviceEnumerator CreateInstance()
{
return new MMDeviceEnumerator() as IMMDeviceEnumerator;
}
}
private const int DEVICE_STATE_ACTIVE = 1;
private const int eRender = 0;
private const int eConsole = 0;
private IAudioEndpointVolume _audioEndpointVolume;
private bool _isExpanded = false;
private bool _isDragging = false;
private Point _dragStartPoint;
private double _collapsedOffset = 200; // 折叠时的偏移量(隐藏内容区域)
private MainWindow _mainWindow;
2026-03-03 16:04:20 +08:00
2026-04-05 17:31:35 +08:00
private Dictionary<FrameworkElement, int> _pptImages = new Dictionary<FrameworkElement, int>();
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
private Dictionary<int, List<string>> _pptImagePaths = new Dictionary<int, List<string>>();
2025-12-31 18:42:26 +08:00
public PPTQuickPanel()
{
InitializeComponent();
InitializeAudio();
ApplyTheme();
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
// 监听主题变化
SystemEvents.UserPreferenceChanged += SystemEvents_UserPreferenceChanged;
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
Loaded += PPTQuickPanel_Loaded;
Unloaded += PPTQuickPanel_Unloaded;
IsVisibleChanged += PPTQuickPanel_IsVisibleChanged;
}
private void PPTQuickPanel_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (Visibility == Visibility.Visible)
{
ApplyTheme();
}
}
private void PPTQuickPanel_Loaded(object sender, RoutedEventArgs e)
{
// 初始状态为折叠
PanelTransform.X = _collapsedOffset;
UpdateArrowRotation();
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
// 获取MainWindow引用
_mainWindow = Application.Current.MainWindow as MainWindow;
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
SubscribeToPPTEvents();
2026-01-10 20:09:20 +08:00
SubscribeToInkCanvasChildrenChanges();
2025-12-31 18:42:26 +08:00
Dispatcher.BeginInvoke(new Action(() =>
{
UpdateVolumeDisplay();
}), DispatcherPriority.Loaded);
}
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
private void SubscribeToInkCanvasChildrenChanges()
{
try
{
if (_mainWindow == null) return;
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
System.Windows.Controls.InkCanvas inkCanvas = null;
2026-03-03 16:04:20 +08:00
var inkCanvasField = _mainWindow.GetType().GetField("inkCanvas",
2026-01-10 20:09:20 +08:00
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
if (inkCanvasField != null)
{
inkCanvas = inkCanvasField.GetValue(_mainWindow) as System.Windows.Controls.InkCanvas;
}
if (inkCanvas == null)
{
2026-03-03 16:04:20 +08:00
var inkCanvasProperty = _mainWindow.GetType().GetProperty("inkCanvas",
2026-01-10 20:09:20 +08:00
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
inkCanvas = inkCanvasProperty?.GetValue(_mainWindow) as System.Windows.Controls.InkCanvas;
}
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
if (inkCanvas != null && inkCanvas.Children is INotifyCollectionChanged notifyCollection)
{
notifyCollection.CollectionChanged += InkCanvasChildren_CollectionChanged;
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"订阅inkCanvas.Children变化事件失败: {ex.Message}", LogHelper.LogType.Error);
}
}
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
private void InkCanvasChildren_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
try
{
if (e.Action == NotifyCollectionChangedAction.Remove)
{
foreach (var item in e.OldItems)
{
2026-04-05 17:31:35 +08:00
if (item is FrameworkElement fe && _pptImages.ContainsKey(fe))
2026-01-10 20:09:20 +08:00
{
2026-04-05 17:31:35 +08:00
RemoveImageFromPPT(fe);
2026-01-10 20:09:20 +08:00
}
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理inkCanvas.Children变化失败: {ex.Message}", LogHelper.LogType.Error);
}
}
2026-03-03 16:04:20 +08:00
2026-04-05 17:31:35 +08:00
private void RemoveImageFromPPT(FrameworkElement element)
2026-01-10 20:09:20 +08:00
{
try
{
2026-04-05 17:31:35 +08:00
if (element == null) return;
2026-03-03 16:04:20 +08:00
2026-04-05 17:31:35 +08:00
if (_pptImages.ContainsKey(element))
2026-01-10 20:09:20 +08:00
{
2026-04-05 17:31:35 +08:00
int slideNumber = _pptImages[element];
_pptImages.Remove(element);
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
if (_pptImagePaths.ContainsKey(slideNumber))
{
2026-04-05 17:31:35 +08:00
string imagePath = element.Tag as string;
2026-01-10 20:09:20 +08:00
if (!string.IsNullOrEmpty(imagePath) && _pptImagePaths[slideNumber].Contains(imagePath))
{
_pptImagePaths[slideNumber].Remove(imagePath);
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
if (_pptImagePaths[slideNumber].Count == 0)
{
_pptImagePaths.Remove(slideNumber);
DeletePPTImagePathsFile(slideNumber);
}
else
{
SavePPTImagePaths(slideNumber);
}
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
LogHelper.WriteLogToFile($"已从PPT页面{slideNumber}移除图片: {imagePath}");
}
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"从PPT关联数据中移除图片失败: {ex.Message}", LogHelper.LogType.Error);
}
}
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
private void DeletePPTImagePathsFile(int slideIndex)
{
try
{
if (slideIndex <= 0) return;
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
var folderPath = GetPresentationFolderPath();
2026-03-03 16:04:20 +08:00
if (string.IsNullOrEmpty(folderPath) || !Directory.Exists(folderPath))
2026-01-10 20:09:20 +08:00
return;
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
var jsonFilePath = Path.Combine(folderPath, slideIndex.ToString("0000") + ".images.json");
if (File.Exists(jsonFilePath))
{
File.Delete(jsonFilePath);
LogHelper.WriteLogToFile($"已删除第{slideIndex}页图片路径JSON文件: {jsonFilePath}");
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"删除PPT图片路径JSON文件失败: {ex.Message}", LogHelper.LogType.Error);
}
}
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
private void SubscribeToPPTEvents()
{
try
{
if (_mainWindow == null) return;
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
// 获取PPTManager
2026-03-03 16:04:20 +08:00
var pptManagerProperty = _mainWindow.GetType().GetProperty("PPTManager",
2025-12-31 19:24:10 +08:00
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
var pptManager = pptManagerProperty?.GetValue(_mainWindow);
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
if (pptManager != null)
{
// 订阅PPT演示文稿打开事件
var presentationOpenEvent = pptManager.GetType().GetEvent("PresentationOpen");
if (presentationOpenEvent != null)
{
2026-01-18 08:18:38 +08:00
var openHandler = new Action<object>(OnPPTPresentationOpen);
2025-12-31 19:24:10 +08:00
presentationOpenEvent.AddEventHandler(pptManager, openHandler);
}
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
// 订阅PPT开始事件
var slideShowBeginEvent = pptManager.GetType().GetEvent("SlideShowBegin");
if (slideShowBeginEvent != null)
{
2026-01-18 08:18:38 +08:00
var beginHandler = new Action<object>(OnPPTSlideShowBegin);
2025-12-31 19:24:10 +08:00
slideShowBeginEvent.AddEventHandler(pptManager, beginHandler);
}
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
// 订阅PPT翻页事件
var slideShowNextSlideEvent = pptManager.GetType().GetEvent("SlideShowNextSlide");
if (slideShowNextSlideEvent != null)
{
2026-01-18 08:18:38 +08:00
var handler = new Action<object>(OnPPTSlideChanged);
2025-12-31 19:24:10 +08:00
slideShowNextSlideEvent.AddEventHandler(pptManager, handler);
}
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
// 订阅PPT结束事件
var slideShowEndEvent = pptManager.GetType().GetEvent("SlideShowEnd");
if (slideShowEndEvent != null)
{
2026-01-18 08:18:38 +08:00
var handler = new Action<object>(OnPPTSlideShowEnd);
2025-12-31 19:24:10 +08:00
slideShowEndEvent.AddEventHandler(pptManager, handler);
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"订阅PPT事件失败: {ex.Message}", LogHelper.LogType.Error);
}
}
2026-03-03 16:04:20 +08:00
2026-01-18 08:18:38 +08:00
private void OnPPTPresentationOpen(object presentation)
2025-12-31 19:24:10 +08:00
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
// PPT打开时,加载所有图片路径
LoadAllPPTImagePaths();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理PPT打开事件失败: {ex.Message}", LogHelper.LogType.Error);
}
}), DispatcherPriority.Normal);
}
2026-03-03 16:04:20 +08:00
2026-01-18 08:18:38 +08:00
private void OnPPTSlideShowBegin(object window)
2025-12-31 19:24:10 +08:00
{
Application.Current.Dispatcher.BeginInvoke(new Action(async () =>
{
try
{
// PPT开始时,加载所有图片路径并加载当前页面的图片
LoadAllPPTImagePaths();
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
if (_mainWindow == null) return;
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
// 获取当前PPT页面编号
2026-03-03 16:04:20 +08:00
var pptManagerProperty = _mainWindow.GetType().GetProperty("PPTManager",
2025-12-31 19:24:10 +08:00
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
var pptManager = pptManagerProperty?.GetValue(_mainWindow);
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
if (pptManager != null)
{
var getCurrentSlideNumberMethod = pptManager.GetType().GetMethod("GetCurrentSlideNumber");
int currentSlide = 0;
if (getCurrentSlideNumberMethod != null)
{
var result = getCurrentSlideNumberMethod.Invoke(pptManager, null);
if (result != null)
{
currentSlide = (int)result;
}
}
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
// 加载当前页面的图片
if (currentSlide > 0)
{
await LoadPPTImages(currentSlide);
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理PPT开始事件失败: {ex.Message}", LogHelper.LogType.Error);
}
}), DispatcherPriority.Normal);
}
2026-03-03 16:04:20 +08:00
2026-01-18 08:18:38 +08:00
private void OnPPTSlideChanged(object window)
2025-12-31 19:24:10 +08:00
{
Application.Current.Dispatcher.BeginInvoke(new Action(async () =>
{
try
{
if (_mainWindow == null) return;
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
// 获取当前PPT页面编号
2026-03-03 16:04:20 +08:00
var pptManagerProperty = _mainWindow.GetType().GetProperty("PPTManager",
2025-12-31 19:24:10 +08:00
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
var pptManager = pptManagerProperty?.GetValue(_mainWindow);
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
if (pptManager != null)
{
var getCurrentSlideNumberMethod = pptManager.GetType().GetMethod("GetCurrentSlideNumber");
int currentSlide = 0;
if (getCurrentSlideNumberMethod != null)
{
var result = getCurrentSlideNumberMethod.Invoke(pptManager, null);
if (result != null)
{
currentSlide = (int)result;
}
}
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
// 更新图片可见性
UpdatePPTImagesVisibility(currentSlide);
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
// 加载当前页面的图片(如果还没有加载)
if (currentSlide > 0 && (!_pptImagePaths.ContainsKey(currentSlide) || _pptImagePaths[currentSlide].Count == 0))
{
// 先加载图片路径
var imagePaths = LoadPPTImagePaths(currentSlide);
if (imagePaths != null && imagePaths.Count > 0)
{
_pptImagePaths[currentSlide] = imagePaths;
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
// 加载图片
await LoadPPTImages(currentSlide);
}
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理PPT翻页事件失败: {ex.Message}", LogHelper.LogType.Error);
}
}), DispatcherPriority.Normal);
}
2026-03-03 16:04:20 +08:00
2026-01-18 08:18:38 +08:00
private void OnPPTSlideShowEnd(object presentation)
2025-12-31 19:24:10 +08:00
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
// PPT退出时隐藏所有图片
HideAllPPTImages();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理PPT结束事件失败: {ex.Message}", LogHelper.LogType.Error);
}
}), DispatcherPriority.Normal);
}
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
private void UpdatePPTImagesVisibility(int currentSlide)
{
try
{
foreach (var kvp in _pptImages)
{
var image = kvp.Key;
var slideNumber = kvp.Value;
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
// 如果图片在当前页面,显示;否则隐藏
image.Visibility = (slideNumber == currentSlide) ? Visibility.Visible : Visibility.Collapsed;
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"更新PPT图片可见性失败: {ex.Message}", LogHelper.LogType.Error);
}
}
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
private void HideAllPPTImages()
{
try
{
foreach (var image in _pptImages.Keys)
{
image.Visibility = Visibility.Collapsed;
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"隐藏所有PPT图片失败: {ex.Message}", LogHelper.LogType.Error);
}
}
2025-12-31 18:42:26 +08:00
private void PPTQuickPanel_Unloaded(object sender, RoutedEventArgs e)
{
SystemEvents.UserPreferenceChanged -= SystemEvents_UserPreferenceChanged;
2026-01-10 20:09:20 +08:00
UnsubscribeFromInkCanvasChildrenChanges();
}
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
private void UnsubscribeFromInkCanvasChildrenChanges()
{
try
{
if (_mainWindow == null) return;
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
System.Windows.Controls.InkCanvas inkCanvas = null;
2026-03-03 16:04:20 +08:00
var inkCanvasField = _mainWindow.GetType().GetField("inkCanvas",
2026-01-10 20:09:20 +08:00
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
if (inkCanvasField != null)
{
inkCanvas = inkCanvasField.GetValue(_mainWindow) as System.Windows.Controls.InkCanvas;
}
if (inkCanvas == null)
{
2026-03-03 16:04:20 +08:00
var inkCanvasProperty = _mainWindow.GetType().GetProperty("inkCanvas",
2026-01-10 20:09:20 +08:00
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
inkCanvas = inkCanvasProperty?.GetValue(_mainWindow) as System.Windows.Controls.InkCanvas;
}
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
if (inkCanvas != null && inkCanvas.Children is INotifyCollectionChanged notifyCollection)
{
notifyCollection.CollectionChanged -= InkCanvasChildren_CollectionChanged;
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"取消订阅inkCanvas.Children变化事件失败: {ex.Message}", LogHelper.LogType.Error);
}
2025-12-31 18:42:26 +08:00
}
private void SystemEvents_UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e)
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
ApplyTheme();
}), DispatcherPriority.Normal);
}
#region
private void InitializeAudio()
{
try
{
var deviceEnumerator = MMDeviceEnumeratorFactory.CreateInstance();
IMMDevice device;
deviceEnumerator.GetDefaultAudioEndpoint(eRender, eConsole, out device);
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
Guid IID_IAudioEndpointVolume = new Guid("5CDF2C82-841E-4546-9722-0CF74078229A");
object interfacePointer;
device.Activate(ref IID_IAudioEndpointVolume, 0, IntPtr.Zero, out interfacePointer);
_audioEndpointVolume = interfacePointer as IAudioEndpointVolume;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"初始化音频控制失败: {ex.Message}", LogHelper.LogType.Error);
}
}
private float GetVolume()
{
if (_audioEndpointVolume == null) return 0.5f;
try
{
float level;
_audioEndpointVolume.GetMasterVolumeLevelScalar(out level);
return level;
}
catch
{
return 0.5f;
}
}
private void SetVolume(float volume)
{
if (_audioEndpointVolume == null) return;
try
{
volume = Math.Max(0f, Math.Min(1f, volume));
_audioEndpointVolume.SetMasterVolumeLevelScalar(volume, Guid.Empty);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"设置音量失败: {ex.Message}", LogHelper.LogType.Error);
}
}
private bool GetMute()
{
if (_audioEndpointVolume == null) return false;
try
{
bool mute;
_audioEndpointVolume.GetMute(out mute);
return mute;
}
catch
{
return false;
}
}
private void SetMute(bool mute)
{
if (_audioEndpointVolume == null) return;
try
{
_audioEndpointVolume.SetMute(mute, Guid.Empty);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"设置静音失败: {ex.Message}", LogHelper.LogType.Error);
}
}
private void UpdateVolumeDisplay()
{
if (_audioEndpointVolume == null) return;
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
try
{
float volume = GetVolume();
bool isMuted = GetMute();
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
// 更新滑块值(不触发事件)
VolumeSlider.ValueChanged -= VolumeSlider_ValueChanged;
VolumeSlider.Value = volume * 100;
VolumeSlider.ValueChanged += VolumeSlider_ValueChanged;
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
// 更新文本显示
VolumeValueText.Text = $"{(int)(volume * 100)}%";
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
// 更新图标
UpdateVolumeIcon(isMuted, volume);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"更新音量显示失败: {ex.Message}", LogHelper.LogType.Error);
}
}
private void UpdateVolumeIcon(bool isMuted, float volume)
{
// 清除描边
VolumeIconPath.Stroke = null;
VolumeIconPath.StrokeThickness = 0;
VolumeIconPath2.Stroke = null;
VolumeIconPath2.StrokeThickness = 0;
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
// 默认隐藏第二个Path
VolumeIconPath2.Visibility = Visibility.Collapsed;
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
// 静音或音量为0%时显示静音图标
if (isMuted || volume <= 0f)
{
// 静音图标:扬声器 + X
// 扬声器部分
var speakerGeometry = Geometry.Parse("M 7,1.00772 C 6.70313,1.00381 6.42188,1.13272 6.23048,1.35928 L 3,4.99991 H 2 C 0.906251,4.99991 0,5.84366 0,6.99991 V 8.99991 C 0,10.0898 0.910157,10.9999 2,10.9999 H 3 L 6.23048,14.6405 C 6.44141,14.8944 6.72266,15.0038 7,14.9999 V 1.00772 Z");
// X部分
var xGeometry = Geometry.Parse("M 10,5.00012 C 9.73441,5.00012 9.4805,5.10559 9.293,5.29309 C 8.90237,5.68372 8.90237,6.31653 9.293,6.70715 L 10.586,8.00013 L 9.293,9.2931 C 8.90237,9.68372 8.90237,10.3165 9.293,10.7072 C 9.68362,11.0978 10.3164,11.0978 10.7071,10.7072 L 12,9.41419 L 13.293,10.7072 C 13.6836,11.0978 14.3164,11.0978 14.7071,10.7072 C 15.0977,10.3165 15.0977,9.68372 14.7071,9.2931 L 13.4141,8.00013 L 14.7071,6.70715 C 15.0977,6.31653 15.0977,5.68372 14.7071,5.29309 C 14.5196,5.10559 14.2657,5.00012 14,5.00012 C 13.7344,5.00012 13.4805,5.10559 13.293,5.29309 L 12,6.58606 L 10.7071,5.29309 C 10.5196,5.10559 10.2657,5.00012 10,5.00012 Z");
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
var group = new GeometryGroup();
group.Children.Add(speakerGeometry);
group.Children.Add(xGeometry);
VolumeIconPath.Data = group;
VolumeIconPath2.Visibility = Visibility.Collapsed;
}
else if (volume >= 0.5f)
{
// 音量>=50%:扬声器 + 两条声波线
// 扬声器部分
var speakerGeometry = Geometry.Parse("M 7,0 C 6.70313,0 6.42188,0.125086 6.23048,0.35165 L 3,3.99228 H 2 C 0.906251,3.99228 0,4.83603 0,5.99228 V 7.99228 C 0,9.08213 0.910157,9.99228 2,9.99228 H 3 L 6.23048,13.6329 C 6.44141,13.8868 6.72266,13.9962 7,13.9923 V 0 Z");
// 第一条声波线
var wave1Geometry = Geometry.Parse("M 13.461,0.961025 C 13.2695,0.957119 13.0742,1.01571 12.9024,1.12899 C 12.4453,1.44149 12.3242,2.06259 12.6328,2.51962 C 14.457,5.22666 14.457,8.75791 12.6328,11.4649 C 12.3242,11.922 12.4453,12.5431 12.9024,12.8556 C 13.3594,13.1642 13.9805,13.0431 14.293,12.586 C 15.4297,10.8946 16,8.94541 16,6.99228 C 16,5.03915 15.4297,3.08993 14.293,1.39853 C 14.0977,1.11337 13.7813,0.961025 13.461,0.961025 Z");
// 第二条声波线
var wave2Geometry = Geometry.Parse("M 10.0391,2.98056 C 9.81642,2.97275 9.58595,3.03915 9.39454,3.18368 C 9.13282,3.3829 9.00001,3.68368 9.00001,3.98837 V 4.04697 C 9.01173,4.23837 9.07423,4.42197 9.19923,4.58212 C 10.2734,6.01181 10.2734,7.97275 9.19923,9.39853 C 9.07423,9.5626 9.01173,9.74619 9.00001,9.93369 V 9.99619 C 9.00001,10.3009 9.13282,10.6017 9.39454,10.8009 C 9.83595,11.1329 10.4609,11.0431 10.793,10.6017 C 11.5977,9.53525 12,8.26572 12,6.99228 C 12,5.71884 11.5977,4.44931 10.793,3.379 C 10.6094,3.1329 10.3281,2.99618 10.0391,2.98056 Z");
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
var group = new GeometryGroup();
group.Children.Add(speakerGeometry);
group.Children.Add(wave1Geometry);
group.Children.Add(wave2Geometry);
VolumeIconPath.Data = group;
VolumeIconPath2.Visibility = Visibility.Collapsed;
}
else
{
// 音量<50%:扬声器 + 一条实线声波线
// 扬声器部分
var speakerGeometry = Geometry.Parse("M 7,1.00759 C 6.70313,1.00369 6.42188,1.13259 6.23048,1.35916 L 3,4.99979 H 2 C 0.906251,4.99979 0,5.84354 0,6.99979 V 8.99979 C 0,10.0896 0.910157,10.9998 2,10.9998 H 3 L 6.23048,14.6404 C 6.44141,14.8943 6.72266,15.0037 7,14.9998 V 1.00759 Z");
// 声波线(实线,不透明度100%
var wave1Geometry = Geometry.Parse("M 10.0391,3.98807 C 9.81642,3.98025 9.58595,4.04666 9.39454,4.19119 C 9.13282,4.39041 9.00001,4.69119 9.00001,4.99588 V 5.06229 C 9.01173,5.24979 9.07813,5.43338 9.19923,5.58963 C 10.2734,7.01932 10.2734,8.98026 9.19923,10.406 C 9.07813,10.5662 9.01173,10.7498 9.00001,10.9373 V 11.0037 C 9.00001,11.3084 9.13282,11.6092 9.39454,11.8084 C 9.83595,12.1404 10.4609,12.0506 10.793,11.6092 C 11.5977,10.5428 12,9.27323 12,7.99979 C 12,6.72635 11.5977,5.45682 10.793,4.3865 C 10.6094,4.14041 10.3281,4.00369 10.0391,3.98807 Z");
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
// 主Path:扬声器 + 声波线
var group = new GeometryGroup();
group.Children.Add(speakerGeometry);
group.Children.Add(wave1Geometry);
VolumeIconPath.Data = group;
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
// 隐藏第二个Path
VolumeIconPath2.Visibility = Visibility.Collapsed;
}
}
#endregion
#region /
private void ExpandPanel()
{
if (_isExpanded) return;
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
_isExpanded = true;
UpdateArrowRotation();
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
var animation = (Storyboard)Resources["ExpandAnimation"];
var doubleAnimation = animation.Children[0] as DoubleAnimation;
doubleAnimation.From = PanelTransform.X;
doubleAnimation.To = 0;
animation.Begin();
}
private void CollapsePanel()
{
if (!_isExpanded) return;
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
_isExpanded = false;
UpdateArrowRotation();
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
var animation = (Storyboard)Resources["CollapseAnimation"];
var doubleAnimation = animation.Children[0] as DoubleAnimation;
doubleAnimation.From = PanelTransform.X;
doubleAnimation.To = _collapsedOffset;
animation.Begin();
}
private void UpdateArrowRotation()
{
if (_isExpanded)
{
// 展开时箭头指向左(折叠)
ArrowRotateTransform.Angle = 0;
}
else
{
// 折叠时箭头指向右(展开)
ArrowRotateTransform.Angle = 180;
}
}
#endregion
#region
private void ArrowButton_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
if (_isExpanded)
{
CollapsePanel();
}
else
{
ExpandPanel();
}
}
private void ArrowButton_MouseEnter(object sender, MouseEventArgs e)
{
// 根据当前主题设置悬停颜色
bool isDark = ArrowButtonBackgroundBrush.Color.R < 128;
if (isDark)
{
ArrowButtonBackgroundBrush.Color = Color.FromArgb(230, 32, 32, 32);
}
else
{
ArrowButtonBackgroundBrush.Color = Color.FromArgb(230, 255, 255, 255);
}
}
private void ArrowButton_MouseLeave(object sender, MouseEventArgs e)
{
// 恢复主题颜色
ApplyTheme();
}
#endregion
#region
private void ContentBorder_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.OriginalSource is Slider) return; // 如果点击的是滑块,不处理拖动
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
_isDragging = true;
_dragStartPoint = e.GetPosition(MainCanvas);
ContentBorder.CaptureMouse();
e.Handled = true;
}
private void ContentBorder_MouseMove(object sender, MouseEventArgs e)
{
if (!_isDragging) return;
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
Point currentPoint = e.GetPosition(MainCanvas);
double deltaX = currentPoint.X - _dragStartPoint.X;
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
// 计算新位置
double newX = PanelTransform.X + deltaX;
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
// 限制拖动范围
newX = Math.Max(0, Math.Min(_collapsedOffset, newX));
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
PanelTransform.X = newX;
_dragStartPoint = currentPoint;
}
private void ContentBorder_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (!_isDragging) return;
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
_isDragging = false;
ContentBorder.ReleaseMouseCapture();
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
// 判断是否超过一半
if (PanelTransform.X < _collapsedOffset / 2)
{
ExpandPanel();
}
else
{
CollapsePanel();
}
}
private void ContentBorder_TouchDown(object sender, TouchEventArgs e)
{
if (e.OriginalSource is Slider) return;
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
_isDragging = true;
_dragStartPoint = e.GetTouchPoint(MainCanvas).Position;
e.Handled = true;
}
private void ContentBorder_TouchMove(object sender, TouchEventArgs e)
{
if (!_isDragging) return;
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
Point currentPoint = e.GetTouchPoint(MainCanvas).Position;
double deltaX = currentPoint.X - _dragStartPoint.X;
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
double newX = PanelTransform.X + deltaX;
newX = Math.Max(0, Math.Min(_collapsedOffset, newX));
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
PanelTransform.X = newX;
_dragStartPoint = currentPoint;
}
private void ContentBorder_TouchUp(object sender, TouchEventArgs e)
{
if (!_isDragging) return;
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
_isDragging = false;
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
if (PanelTransform.X < _collapsedOffset / 2)
{
ExpandPanel();
}
else
{
CollapsePanel();
}
}
#endregion
#region
private void VolumeMuteButton_Click(object sender, RoutedEventArgs e)
{
try
{
bool currentMute = GetMute();
float volume = GetVolume();
SetMute(!currentMute);
UpdateVolumeIcon(!currentMute, volume);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"切换静音失败: {ex.Message}", LogHelper.LogType.Error);
}
}
private void VolumeSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (!IsLoaded) return;
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
try
{
float volume = (float)(e.NewValue / 100.0);
SetVolume(volume);
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
// 更新文本显示
VolumeValueText.Text = $"{(int)e.NewValue}%";
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
// 如果音量大于0,取消静音
if (e.NewValue > 0)
{
bool isMuted = GetMute();
if (isMuted)
{
SetMute(false);
}
}
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
// 更新图标(根据当前音量和静音状态)
bool currentMute = GetMute();
UpdateVolumeIcon(currentMute, volume);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"音量滑块值改变处理失败: {ex.Message}", LogHelper.LogType.Error);
}
}
private void VolumeSlider_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
// 确保精度为1%
double value = VolumeSlider.Value;
VolumeSlider.Value = Math.Round(value);
}
private void VolumeSlider_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
{
// 触摸操作完成时,确保精度为1%
double value = VolumeSlider.Value;
VolumeSlider.Value = Math.Round(value);
}
#endregion
#region
2026-01-10 20:09:20 +08:00
private async void InsertImageSelectFileButton_Click(object sender, RoutedEventArgs e)
2025-12-31 18:42:26 +08:00
{
if (_mainWindow == null) return;
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
try
{
var dialog = new OpenFileDialog
{
2026-04-05 17:31:35 +08:00
Filter = "图片与 PDF|*.jpg;*.jpeg;*.png;*.bmp;*.gif;*.pdf|图片文件|*.jpg;*.jpeg;*.png;*.bmp;*.gif|PDF|*.pdf"
2025-12-31 18:42:26 +08:00
};
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
if (dialog.ShowDialog() == true)
{
string filePath = dialog.FileName;
2026-03-03 16:04:20 +08:00
var createImageMethod = _mainWindow.GetType().GetMethod("CreateAndCompressImageAsync",
2025-12-31 18:42:26 +08:00
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
2026-03-03 16:04:20 +08:00
2025-12-31 18:42:26 +08:00
if (createImageMethod != null)
{
2026-04-05 17:31:35 +08:00
var imageTask = createImageMethod.Invoke(_mainWindow, new object[] { filePath }) as System.Threading.Tasks.Task<FrameworkElement>;
2025-12-31 18:42:26 +08:00
if (imageTask != null)
{
2026-04-05 17:31:35 +08:00
var inserted = await imageTask;
if (inserted != null)
2025-12-31 18:42:26 +08:00
{
2026-04-05 17:31:35 +08:00
inserted.Tag = filePath;
await InsertImageToMainWindow(inserted, filePath);
2025-12-31 18:42:26 +08:00
}
}
}
else
{
LogHelper.WriteLogToFile("无法找到CreateAndCompressImageAsync方法", LogHelper.LogType.Warning);
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"插入图片失败: {ex.Message}", LogHelper.LogType.Error);
}
}
2026-01-10 20:09:20 +08:00
private async void InsertImageScreenshotButton_Click(object sender, RoutedEventArgs e)
{
if (_mainWindow == null) return;
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
try
{
2026-03-03 16:04:20 +08:00
var captureScreenshotMethod = _mainWindow.GetType().GetMethod("CaptureScreenshotAndInsert",
2026-01-10 20:09:20 +08:00
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
if (captureScreenshotMethod != null)
{
var task = captureScreenshotMethod.Invoke(_mainWindow, null) as System.Threading.Tasks.Task;
if (task != null)
{
await task;
await SaveScreenshotToPPT();
}
}
else
{
LogHelper.WriteLogToFile("无法找到CaptureScreenshotAndInsert方法", LogHelper.LogType.Warning);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"截图插入失败: {ex.Message}", LogHelper.LogType.Error);
}
}
private async System.Threading.Tasks.Task SaveScreenshotToPPT()
{
try
{
if (_mainWindow == null) return;
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
System.Windows.Controls.InkCanvas inkCanvas = null;
2026-03-03 16:04:20 +08:00
var inkCanvasField = _mainWindow.GetType().GetField("inkCanvas",
2026-01-10 20:09:20 +08:00
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
if (inkCanvasField != null)
{
inkCanvas = inkCanvasField.GetValue(_mainWindow) as System.Windows.Controls.InkCanvas;
}
if (inkCanvas == null)
{
2026-03-03 16:04:20 +08:00
var inkCanvasProperty = _mainWindow.GetType().GetProperty("inkCanvas",
2026-01-10 20:09:20 +08:00
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
inkCanvas = inkCanvasProperty?.GetValue(_mainWindow) as System.Windows.Controls.InkCanvas;
}
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
if (inkCanvas == null) return;
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
System.Windows.Controls.Image lastScreenshot = null;
foreach (System.Windows.Controls.Image img in inkCanvas.Children.OfType<System.Windows.Controls.Image>())
{
if (img.Name != null && (img.Name.StartsWith("screenshot_") || img.Name.StartsWith("camera_")) && img.Tag == null)
{
lastScreenshot = img;
}
}
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
if (lastScreenshot == null) return;
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
string screenshotFilePath = await SaveScreenshotToFile(lastScreenshot);
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
if (string.IsNullOrEmpty(screenshotFilePath))
{
LogHelper.WriteLogToFile("保存截图文件失败", LogHelper.LogType.Warning);
return;
}
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
lastScreenshot.Tag = screenshotFilePath;
await ManageScreenshotInPPT(lastScreenshot, screenshotFilePath);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"保存截图到PPT失败: {ex.Message}", LogHelper.LogType.Error);
}
}
private async System.Threading.Tasks.Task<string> SaveScreenshotToFile(System.Windows.Controls.Image image)
{
try
{
if (image?.Source == null) return null;
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
string savePath = null;
var settingsProperty = _mainWindow.GetType().GetProperty("Settings");
if (settingsProperty != null)
{
var settings = settingsProperty.GetValue(_mainWindow);
if (settings != null)
{
var autoSavedStrokesLocationProperty = settings.GetType().GetProperty("Automation");
if (autoSavedStrokesLocationProperty != null)
{
var automation = autoSavedStrokesLocationProperty.GetValue(settings);
if (automation != null)
{
var locationProperty = automation.GetType().GetProperty("AutoSavedStrokesLocation");
if (locationProperty != null)
{
var location = locationProperty.GetValue(automation) as string;
if (!string.IsNullOrEmpty(location))
{
savePath = Path.Combine(location, "File Dependency");
}
}
}
}
}
}
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
if (string.IsNullOrEmpty(savePath))
{
LogHelper.WriteLogToFile("无法获取AutoSavedStrokesLocation", LogHelper.LogType.Warning);
return null;
}
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
if (!Directory.Exists(savePath))
{
Directory.CreateDirectory(savePath);
}
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
string timestamp = image.Name;
string filePath = Path.Combine(savePath, timestamp + ".png");
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
await Application.Current.Dispatcher.InvokeAsync(() =>
{
if (image.Source is BitmapSource bitmapSource)
{
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmapSource));
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
using (var fileStream = new FileStream(filePath, FileMode.Create))
{
encoder.Save(fileStream);
}
}
});
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
return filePath;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"保存截图到文件失败: {ex.Message}", LogHelper.LogType.Error);
return null;
}
}
private async System.Threading.Tasks.Task ManageScreenshotInPPT(System.Windows.Controls.Image image, string filePath)
{
if (_mainWindow == null || image == null || string.IsNullOrEmpty(filePath)) return;
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
await Application.Current.Dispatcher.InvokeAsync(() =>
{
try
{
int currentSlideNumber = 0;
try
{
2026-03-03 16:04:20 +08:00
var pptManagerProperty = _mainWindow.GetType().GetProperty("PPTManager",
2026-01-10 20:09:20 +08:00
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
var pptManager = pptManagerProperty?.GetValue(_mainWindow);
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
if (pptManager != null)
{
var isInSlideShowProperty = pptManager.GetType().GetProperty("IsInSlideShow");
bool isInSlideShow = false;
if (isInSlideShowProperty != null)
{
var result = isInSlideShowProperty.GetValue(pptManager);
if (result != null)
{
isInSlideShow = (bool)result;
}
}
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
if (isInSlideShow)
{
var getCurrentSlideNumberMethod = pptManager.GetType().GetMethod("GetCurrentSlideNumber");
if (getCurrentSlideNumberMethod != null)
{
var result = getCurrentSlideNumberMethod.Invoke(pptManager, null);
if (result != null)
{
currentSlideNumber = (int)result;
}
}
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"获取当前PPT页面编号失败: {ex.Message}", LogHelper.LogType.Warning);
}
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
if (currentSlideNumber > 0 && !string.IsNullOrEmpty(filePath))
{
_pptImages[image] = currentSlideNumber;
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
if (!_pptImagePaths.ContainsKey(currentSlideNumber))
{
_pptImagePaths[currentSlideNumber] = new List<string>();
}
_pptImagePaths[currentSlideNumber].Add(filePath);
SavePPTImagePaths(currentSlideNumber);
2026-03-03 16:04:20 +08:00
2026-01-10 20:09:20 +08:00
LogHelper.WriteLogToFile($"截图已关联到PPT页面{currentSlideNumber}: {filePath}");
}
else if (currentSlideNumber > 0)
{
_pptImages[image] = currentSlideNumber;
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"管理截图在PPT中的关联失败: {ex.Message}", LogHelper.LogType.Error);
}
}, DispatcherPriority.Normal);
}
2026-04-05 17:31:35 +08:00
private async System.Threading.Tasks.Task InsertImageToMainWindow(FrameworkElement element, string originalFilePath = null, bool saveToJson = true)
2025-12-31 18:42:26 +08:00
{
2026-04-05 17:31:35 +08:00
if (_mainWindow == null || element == null) return;
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
// 确保在UI线程上执行
await Application.Current.Dispatcher.InvokeAsync(() =>
2025-12-31 18:42:26 +08:00
{
2025-12-31 19:24:10 +08:00
try
{
// 生成唯一名称
string timestamp = "img_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff");
2026-04-05 17:31:35 +08:00
element.Name = timestamp;
2025-12-31 19:24:10 +08:00
// 设置图片属性
2026-04-05 17:31:35 +08:00
element.IsHitTestVisible = true;
element.Focusable = false;
2025-12-31 19:24:10 +08:00
System.Windows.Controls.InkCanvas inkCanvas = null;
2026-03-03 16:04:20 +08:00
var inkCanvasField = _mainWindow.GetType().GetField("inkCanvas",
2025-12-31 19:24:10 +08:00
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
if (inkCanvasField != null)
{
inkCanvas = inkCanvasField.GetValue(_mainWindow) as System.Windows.Controls.InkCanvas;
}
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
if (inkCanvas == null)
{
2026-03-03 16:04:20 +08:00
var inkCanvasProperty = _mainWindow.GetType().GetProperty("inkCanvas",
2025-12-31 19:24:10 +08:00
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
if (inkCanvasProperty != null)
{
inkCanvas = inkCanvasProperty.GetValue(_mainWindow) as System.Windows.Controls.InkCanvas;
}
}
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
if (inkCanvas == null)
{
LogHelper.WriteLogToFile("无法获取inkCanvas", LogHelper.LogType.Error);
return;
}
// 初始化InkCanvas选择设置
2026-03-03 16:04:20 +08:00
var initializeInkCanvasSelectionSettingsMethod = _mainWindow.GetType().GetMethod("InitializeInkCanvasSelectionSettings",
2025-12-31 19:24:10 +08:00
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
initializeInkCanvasSelectionSettingsMethod?.Invoke(_mainWindow, null);
// 获取当前PPT页面编号(如果在PPT模式下)
int currentSlideNumber = 0;
try
{
2026-03-03 16:04:20 +08:00
var pptManagerProperty = _mainWindow.GetType().GetProperty("PPTManager",
2025-12-31 19:24:10 +08:00
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
var pptManager = pptManagerProperty?.GetValue(_mainWindow);
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
if (pptManager != null)
{
var isInSlideShowProperty = pptManager.GetType().GetProperty("IsInSlideShow");
bool isInSlideShow = false;
if (isInSlideShowProperty != null)
{
var result = isInSlideShowProperty.GetValue(pptManager);
if (result != null)
{
isInSlideShow = (bool)result;
}
}
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
if (isInSlideShow)
{
var getCurrentSlideNumberMethod = pptManager.GetType().GetMethod("GetCurrentSlideNumber");
if (getCurrentSlideNumberMethod != null)
{
var result = getCurrentSlideNumberMethod.Invoke(pptManager, null);
if (result != null)
{
currentSlideNumber = (int)result;
}
}
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"获取当前PPT页面编号失败: {ex.Message}", LogHelper.LogType.Warning);
}
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
// 如果在PPT模式下,记录图片和页面编号的关联,并保存图片路径
if (currentSlideNumber > 0 && !string.IsNullOrEmpty(originalFilePath) && saveToJson)
{
2026-04-05 17:31:35 +08:00
_pptImages[element] = currentSlideNumber;
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
// 添加到页面图片路径列表
if (!_pptImagePaths.ContainsKey(currentSlideNumber))
{
_pptImagePaths[currentSlideNumber] = new List<string>();
}
_pptImagePaths[currentSlideNumber].Add(originalFilePath);
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
// 保存图片路径到JSON文件
SavePPTImagePaths(currentSlideNumber);
}
else if (currentSlideNumber > 0)
{
// 即使不保存到JSON,也要记录图片和页面编号的关联(用于翻页显示/隐藏)
2026-04-05 17:31:35 +08:00
_pptImages[element] = currentSlideNumber;
2025-12-31 19:24:10 +08:00
}
// 先添加到画布(与MainWindow的实现保持一致)
2026-04-05 17:31:35 +08:00
inkCanvas.Children.Add(element);
2025-12-31 19:24:10 +08:00
// 等待图片加载完成后再进行后续处理
2026-04-05 17:31:35 +08:00
element.Loaded += (s, args) =>
2025-12-31 19:24:10 +08:00
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
// 初始化TransformGroup
2026-03-03 16:04:20 +08:00
var initializeTransformMethod = _mainWindow.GetType().GetMethod("InitializeElementTransform",
2025-12-31 19:24:10 +08:00
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
2026-04-05 17:31:35 +08:00
initializeTransformMethod?.Invoke(_mainWindow, new object[] { element });
2025-12-31 18:42:26 +08:00
2025-12-31 19:24:10 +08:00
// 居中缩放
2026-03-03 16:04:20 +08:00
var centerMethod = _mainWindow.GetType().GetMethod("CenterAndScaleElement",
2025-12-31 19:24:10 +08:00
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
2026-04-05 17:31:35 +08:00
centerMethod?.Invoke(_mainWindow, new object[] { element });
2025-12-31 19:24:10 +08:00
// 绑定事件处理器
2026-03-03 16:04:20 +08:00
var bindEventsMethod = _mainWindow.GetType().GetMethod("BindElementEvents",
2025-12-31 19:24:10 +08:00
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
2026-04-05 17:31:35 +08:00
bindEventsMethod?.Invoke(_mainWindow, new object[] { element });
2025-12-31 19:24:10 +08:00
2026-04-05 17:31:35 +08:00
LogHelper.WriteLogToFile($"图片插入完成: {element.Name}, PPT页面: {currentSlideNumber}");
2025-12-31 19:24:10 +08:00
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"图片加载后处理失败: {ex.Message}", LogHelper.LogType.Error);
}
}), DispatcherPriority.Loaded);
};
// 提交历史记录
2026-03-03 16:04:20 +08:00
var timeMachineProperty = _mainWindow.GetType().GetProperty("timeMachine",
2025-12-31 19:24:10 +08:00
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
var timeMachine = timeMachineProperty?.GetValue(_mainWindow);
if (timeMachine != null)
{
var commitMethod = timeMachine.GetType().GetMethod("CommitElementInsertHistory");
2026-04-05 17:31:35 +08:00
commitMethod?.Invoke(timeMachine, new object[] { element });
2025-12-31 19:24:10 +08:00
}
// 切换到选择模式
2026-03-03 16:04:20 +08:00
var setModeMethod = _mainWindow.GetType().GetMethod("SetCurrentToolMode",
2025-12-31 19:24:10 +08:00
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
setModeMethod?.Invoke(_mainWindow, new object[] { System.Windows.Controls.InkCanvasEditingMode.Select });
2026-03-03 16:04:20 +08:00
var updateModeMethod = _mainWindow.GetType().GetMethod("UpdateCurrentToolMode",
2025-12-31 19:24:10 +08:00
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
updateModeMethod?.Invoke(_mainWindow, new object[] { "select" });
2026-03-03 16:04:20 +08:00
var hidePanelsMethod = _mainWindow.GetType().GetMethod("HideSubPanels",
2025-12-31 19:24:10 +08:00
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
hidePanelsMethod?.Invoke(_mainWindow, new object[] { "select" });
}
catch (Exception ex)
2025-12-31 18:42:26 +08:00
{
2025-12-31 19:24:10 +08:00
LogHelper.WriteLogToFile($"插入图片到MainWindow失败: {ex.Message}", LogHelper.LogType.Error);
2025-12-31 18:42:26 +08:00
}
2025-12-31 19:24:10 +08:00
}, DispatcherPriority.Normal);
}
2025-12-31 18:42:26 +08:00
2025-12-31 19:24:10 +08:00
#endregion
2025-12-31 18:42:26 +08:00
2025-12-31 19:24:10 +08:00
#region PPT图片保存和加载
2025-12-31 18:42:26 +08:00
2025-12-31 19:24:10 +08:00
/// <summary>
/// 获取PPT演示文稿的文件夹路径
/// </summary>
private string GetPresentationFolderPath()
{
try
{
if (_mainWindow == null) return null;
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
// 获取PPTInkManager
2026-03-03 16:04:20 +08:00
var singlePPTInkManagerField = _mainWindow.GetType().GetField("_singlePPTInkManager",
2025-12-31 18:42:26 +08:00
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
2025-12-31 19:24:10 +08:00
var singlePPTInkManager = singlePPTInkManagerField?.GetValue(_mainWindow);
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
if (singlePPTInkManager != null)
2025-12-31 18:42:26 +08:00
{
2025-12-31 19:24:10 +08:00
// 使用反射获取AutoSaveLocation
var autoSaveLocationProperty = singlePPTInkManager.GetType().GetProperty("AutoSaveLocation");
var autoSaveLocation = autoSaveLocationProperty?.GetValue(singlePPTInkManager) as string;
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
if (!string.IsNullOrEmpty(autoSaveLocation))
2025-12-31 18:42:26 +08:00
{
2025-12-31 19:24:10 +08:00
// 获取PPTManager以获取当前演示文稿信息
2026-03-03 16:04:20 +08:00
var pptManagerProperty = _mainWindow.GetType().GetProperty("PPTManager",
2025-12-31 19:24:10 +08:00
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
var pptManager = pptManagerProperty?.GetValue(_mainWindow);
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
if (pptManager != null)
{
2026-01-19 21:02:24 +08:00
// 尝试获取当前演示文稿,使用重试机制
Microsoft.Office.Interop.PowerPoint.Presentation presentation = null;
2026-03-03 16:04:20 +08:00
2026-01-19 21:02:24 +08:00
// 首先尝试使用 CurrentPresentation 属性(可能是缓存的)
try
{
2026-03-03 16:04:20 +08:00
var currentPresentationProperty = pptManager.GetType().GetProperty("CurrentPresentation",
2026-01-19 21:02:24 +08:00
System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
presentation = currentPresentationProperty?.GetValue(pptManager) as Microsoft.Office.Interop.PowerPoint.Presentation;
}
2026-02-21 16:51:34 +08:00
catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex); }
2026-03-03 16:04:20 +08:00
2026-01-19 21:02:24 +08:00
// 如果 CurrentPresentation 不可用,尝试 GetCurrentActivePresentation
if (presentation == null)
{
try
{
var getCurrentActivePresentationMethod = pptManager.GetType().GetMethod("GetCurrentActivePresentation");
presentation = getCurrentActivePresentationMethod?.Invoke(pptManager, null) as Microsoft.Office.Interop.PowerPoint.Presentation;
}
2026-02-21 16:51:34 +08:00
catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex); }
2026-01-19 21:02:24 +08:00
}
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
if (presentation != null)
{
2026-01-19 21:02:24 +08:00
try
{
// 立即检查COM对象是否仍然有效
if (!System.Runtime.InteropServices.Marshal.IsComObject(presentation))
{
return null;
}
2026-03-03 16:04:20 +08:00
2026-01-19 21:02:24 +08:00
// 尝试访问对象以验证其有效性
try
{
var _ = System.Runtime.InteropServices.Marshal.GetIUnknownForObject(presentation);
System.Runtime.InteropServices.Marshal.Release(_);
}
catch (System.Runtime.InteropServices.InvalidComObjectException)
{
// COM对象已失效,静默返回
return null;
}
2026-03-03 16:04:20 +08:00
2026-01-19 21:02:24 +08:00
// 立即生成演示文稿ID(在对象失效前)
string presentationId = GeneratePresentationId(presentation);
if (string.IsNullOrEmpty(presentationId) || presentationId.StartsWith("unknown_") || presentationId.StartsWith("invalid_") || presentationId.StartsWith("com_error_"))
{
// 生成ID失败,返回null而不是抛出异常
return null;
}
2026-03-03 16:04:20 +08:00
2026-01-19 21:02:24 +08:00
return Path.Combine(autoSaveLocation, "Auto Saved - Presentations", presentationId);
}
catch (System.Runtime.InteropServices.InvalidComObjectException)
{
// COM对象已失效,静默返回(不记录错误日志)
return null;
}
catch (System.Runtime.InteropServices.COMException)
{
// COM异常,对象可能已失效,静默返回(不记录错误日志)
return null;
}
catch (Exception ex)
{
// 其他异常,只记录非COM相关异常
2026-03-03 16:04:20 +08:00
if (!(ex is System.Runtime.InteropServices.InvalidComObjectException) &&
2026-01-19 21:02:24 +08:00
!(ex is System.Runtime.InteropServices.COMException))
{
LogHelper.WriteLogToFile($"获取PPT文件夹路径时发生非COM异常: {ex.Message}", LogHelper.LogType.Warning);
}
return null;
}
2025-12-31 19:24:10 +08:00
}
}
2025-12-31 18:42:26 +08:00
}
}
2025-12-31 19:24:10 +08:00
}
2026-01-19 21:02:24 +08:00
catch (System.Runtime.InteropServices.InvalidComObjectException)
{
// COM对象已失效,静默返回(不记录错误日志)
return null;
}
catch (System.Runtime.InteropServices.COMException)
{
// COM异常,对象可能已失效,静默返回(不记录错误日志)
return null;
}
2025-12-31 19:24:10 +08:00
catch (Exception ex)
{
2026-01-19 21:02:24 +08:00
// 只记录非COM相关异常
2026-03-03 16:04:20 +08:00
if (!(ex is System.Runtime.InteropServices.InvalidComObjectException) &&
2026-01-19 21:02:24 +08:00
!(ex is System.Runtime.InteropServices.COMException))
{
LogHelper.WriteLogToFile($"获取PPT文件夹路径失败: {ex.Message}", LogHelper.LogType.Error);
}
2025-12-31 19:24:10 +08:00
}
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
return null;
}
2025-12-31 18:42:26 +08:00
2025-12-31 19:24:10 +08:00
/// <summary>
/// 生成演示文稿ID(与PPTInkManager一致)
/// </summary>
private string GeneratePresentationId(Microsoft.Office.Interop.PowerPoint.Presentation presentation)
{
2026-01-19 21:02:24 +08:00
if (presentation == null)
{
return $"unknown_{DateTime.Now.Ticks}";
}
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
try
{
2026-01-19 21:02:24 +08:00
// 检查COM对象是否仍然有效
if (!System.Runtime.InteropServices.Marshal.IsComObject(presentation))
{
return $"unknown_{DateTime.Now.Ticks}";
}
2026-03-03 16:04:20 +08:00
2026-01-19 21:02:24 +08:00
// 验证COM对象有效性
try
{
var _ = System.Runtime.InteropServices.Marshal.GetIUnknownForObject(presentation);
System.Runtime.InteropServices.Marshal.Release(_);
}
catch (System.Runtime.InteropServices.InvalidComObjectException)
{
// COM对象已失效
return $"unknown_{DateTime.Now.Ticks}";
}
2026-03-03 16:04:20 +08:00
2026-01-19 21:02:24 +08:00
// 逐个访问属性,每个都进行异常处理
string presentationName = null;
string presentationPath = null;
int slidesCount = 0;
2026-03-03 16:04:20 +08:00
2026-01-19 21:02:24 +08:00
try
{
presentationName = presentation.Name;
}
catch (System.Runtime.InteropServices.InvalidComObjectException)
{
return $"unknown_{DateTime.Now.Ticks}";
}
catch (System.Runtime.InteropServices.COMException)
{
return $"unknown_{DateTime.Now.Ticks}";
}
2026-03-03 16:04:20 +08:00
2026-01-19 21:02:24 +08:00
try
{
presentationPath = presentation.FullName;
}
catch (System.Runtime.InteropServices.InvalidComObjectException)
{
return $"unknown_{DateTime.Now.Ticks}";
}
catch (System.Runtime.InteropServices.COMException)
{
return $"unknown_{DateTime.Now.Ticks}";
}
2026-03-03 16:04:20 +08:00
2026-01-19 21:02:24 +08:00
try
{
slidesCount = presentation.Slides.Count;
}
catch (System.Runtime.InteropServices.InvalidComObjectException)
{
return $"unknown_{DateTime.Now.Ticks}";
}
catch (System.Runtime.InteropServices.COMException)
{
return $"unknown_{DateTime.Now.Ticks}";
}
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
var fileHash = GetFileHash(presentationPath);
2026-01-19 21:02:24 +08:00
return $"{presentationName}_{slidesCount}_{fileHash}";
}
catch (System.Runtime.InteropServices.InvalidComObjectException)
{
// COM对象已失效
return $"unknown_{DateTime.Now.Ticks}";
}
catch (System.Runtime.InteropServices.COMException)
{
// COM异常,对象可能已失效
return $"unknown_{DateTime.Now.Ticks}";
2025-12-31 19:24:10 +08:00
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"生成演示文稿ID失败: {ex}", LogHelper.LogType.Error);
return $"unknown_{DateTime.Now.Ticks}";
}
}
/// <summary>
/// 计算文件哈希值
/// </summary>
private string GetFileHash(string filePath)
{
try
{
if (string.IsNullOrEmpty(filePath)) return "unknown";
using (var md5 = System.Security.Cryptography.MD5.Create())
2025-12-31 18:42:26 +08:00
{
2025-12-31 19:24:10 +08:00
byte[] hashBytes = md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(filePath));
return BitConverter.ToString(hashBytes).Replace("-", "").Substring(0, 8);
2025-12-31 18:42:26 +08:00
}
2025-12-31 19:24:10 +08:00
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"计算文件哈希值失败: {ex}", LogHelper.LogType.Error);
return "error";
}
}
2025-12-31 18:42:26 +08:00
2025-12-31 19:24:10 +08:00
/// <summary>
/// 保存指定页面的图片路径到JSON文件
/// </summary>
private void SavePPTImagePaths(int slideIndex)
{
try
{
if (slideIndex <= 0 || !_pptImagePaths.ContainsKey(slideIndex)) return;
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
var folderPath = GetPresentationFolderPath();
if (string.IsNullOrEmpty(folderPath)) return;
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
if (!Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
}
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
var jsonFilePath = Path.Combine(folderPath, slideIndex.ToString("0000") + ".images.json");
var imagePaths = _pptImagePaths[slideIndex];
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
string json = JsonConvert.SerializeObject(imagePaths, Formatting.Indented);
File.WriteAllText(jsonFilePath, json);
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
LogHelper.WriteLogToFile($"已保存第{slideIndex}页图片路径到JSON: {jsonFilePath}");
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"保存PPT图片路径失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 从JSON文件加载指定页面的图片路径
/// </summary>
private List<string> LoadPPTImagePaths(int slideIndex)
{
try
{
if (slideIndex <= 0) return new List<string>();
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
var folderPath = GetPresentationFolderPath();
2026-03-03 16:04:20 +08:00
if (string.IsNullOrEmpty(folderPath) || !Directory.Exists(folderPath))
2025-12-31 19:24:10 +08:00
return new List<string>();
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
var jsonFilePath = Path.Combine(folderPath, slideIndex.ToString("0000") + ".images.json");
2026-03-03 16:04:20 +08:00
if (!File.Exists(jsonFilePath))
2025-12-31 19:24:10 +08:00
return new List<string>();
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
string json = File.ReadAllText(jsonFilePath);
var imagePaths = JsonConvert.DeserializeObject<List<string>>(json);
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
return imagePaths ?? new List<string>();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"加载PPT图片路径失败: {ex.Message}", LogHelper.LogType.Error);
return new List<string>();
}
}
/// <summary>
/// 加载指定页面的图片
/// </summary>
private async System.Threading.Tasks.Task LoadPPTImages(int slideIndex)
{
try
{
if (_mainWindow == null || slideIndex <= 0) return;
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
var imagePaths = LoadPPTImagePaths(slideIndex);
if (imagePaths == null || imagePaths.Count == 0) return;
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
// 获取inkCanvas,检查是否已有图片
System.Windows.Controls.InkCanvas inkCanvas = null;
2026-03-03 16:04:20 +08:00
var inkCanvasField = _mainWindow.GetType().GetField("inkCanvas",
2025-12-31 19:24:10 +08:00
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
if (inkCanvasField != null)
{
inkCanvas = inkCanvasField.GetValue(_mainWindow) as System.Windows.Controls.InkCanvas;
}
if (inkCanvas == null)
{
2026-03-03 16:04:20 +08:00
var inkCanvasProperty = _mainWindow.GetType().GetProperty("inkCanvas",
2025-12-31 19:24:10 +08:00
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
inkCanvas = inkCanvasProperty?.GetValue(_mainWindow) as System.Windows.Controls.InkCanvas;
}
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
if (inkCanvas == null) return;
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
// 检查已存在的图片路径(通过Tag)
var existingImagePaths = new HashSet<string>();
2026-04-05 17:31:35 +08:00
foreach (var existingImage in inkCanvas.Children.OfType<System.Windows.Controls.Image>())
2025-12-31 19:24:10 +08:00
{
if (existingImage.Tag is string tagPath && !string.IsNullOrEmpty(tagPath))
existingImagePaths.Add(tagPath);
2026-04-05 17:31:35 +08:00
}
foreach (var existingPdf in inkCanvas.Children.OfType<PdfEmbeddedView>())
{
if (existingPdf.Tag is string tagPath && !string.IsNullOrEmpty(tagPath))
existingImagePaths.Add(tagPath);
2025-12-31 19:24:10 +08:00
}
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
// 使用反射调用MainWindow的CreateAndCompressImageAsync方法
2026-03-03 16:04:20 +08:00
var createImageMethod = _mainWindow.GetType().GetMethod("CreateAndCompressImageAsync",
2025-12-31 18:42:26 +08:00
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
if (createImageMethod == null)
{
LogHelper.WriteLogToFile("无法找到CreateAndCompressImageAsync方法", LogHelper.LogType.Warning);
return;
}
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
foreach (var imagePath in imagePaths)
{
try
{
// 如果图片已存在,跳过
if (existingImagePaths.Contains(imagePath))
{
continue;
}
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
if (!File.Exists(imagePath))
{
LogHelper.WriteLogToFile($"图片文件不存在: {imagePath}", LogHelper.LogType.Warning);
continue;
}
2026-03-03 16:04:20 +08:00
2026-04-05 17:31:35 +08:00
var imageTask = createImageMethod.Invoke(_mainWindow, new object[] { imagePath }) as System.Threading.Tasks.Task<FrameworkElement>;
2025-12-31 19:24:10 +08:00
if (imageTask != null)
{
2026-04-05 17:31:35 +08:00
var inserted = await imageTask;
if (inserted != null)
2025-12-31 19:24:10 +08:00
{
// 保存原始文件路径到Tag
2026-04-05 17:31:35 +08:00
inserted.Tag = imagePath;
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
// 插入图片(不保存路径,因为已经存在)
2026-04-05 17:31:35 +08:00
await InsertImageToMainWindow(inserted, imagePath, false);
2025-12-31 19:24:10 +08:00
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"加载图片失败: {imagePath}, 错误: {ex.Message}", LogHelper.LogType.Error);
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"加载PPT图片失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 加载所有页面的图片路径(在PPT打开时调用)
/// </summary>
public void LoadAllPPTImagePaths()
{
try
{
if (_mainWindow == null) return;
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
var folderPath = GetPresentationFolderPath();
2026-03-03 16:04:20 +08:00
if (string.IsNullOrEmpty(folderPath) || !Directory.Exists(folderPath))
2025-12-31 19:24:10 +08:00
return;
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
// 清空现有数据
_pptImagePaths.Clear();
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
// 查找所有图片JSON文件
var jsonFiles = Directory.GetFiles(folderPath, "*.images.json");
foreach (var jsonFile in jsonFiles)
{
try
{
var fileName = Path.GetFileNameWithoutExtension(jsonFile);
fileName = fileName.Replace(".images", ""); // 移除.images后缀
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
if (int.TryParse(fileName, out int slideIndex) && slideIndex > 0)
{
var imagePaths = LoadPPTImagePaths(slideIndex);
if (imagePaths != null && imagePaths.Count > 0)
{
_pptImagePaths[slideIndex] = imagePaths;
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"加载图片路径文件失败: {jsonFile}, 错误: {ex.Message}", LogHelper.LogType.Error);
}
}
2026-03-03 16:04:20 +08:00
2025-12-31 19:24:10 +08:00
LogHelper.WriteLogToFile($"已加载{_pptImagePaths.Count}个页面的图片路径");
2025-12-31 18:42:26 +08:00
}
catch (Exception ex)
{
2025-12-31 19:24:10 +08:00
LogHelper.WriteLogToFile($"加载所有PPT图片路径失败: {ex.Message}", LogHelper.LogType.Error);
2025-12-31 18:42:26 +08:00
}
}
#endregion
#region
private void ApplyTheme()
{
try
{
if (MainWindow.Settings != null)
{
ApplyTheme(MainWindow.Settings);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"应用PPT快捷面板主题失败: {ex.Message}", LogHelper.LogType.Error);
}
}
private void ApplyTheme(Settings settings)
{
try
{
bool isDarkTheme = false;
if (settings.Appearance.Theme == 0) // 浅色主题
{
isDarkTheme = false;
}
else if (settings.Appearance.Theme == 1) // 深色主题
{
isDarkTheme = true;
}
else // 跟随系统主题
{
bool isSystemLight = IsSystemThemeLight();
isDarkTheme = !isSystemLight;
}
if (isDarkTheme)
{
// 深色主题:使用80%不透明度的深色背景
ArrowButtonBackgroundBrush.Color = Color.FromArgb(204, 32, 32, 32); // #CC202020
ContentBackgroundBrush.Color = Color.FromArgb(204, 32, 32, 32); // #CC202020
ArrowPathFillBrush.Color = Colors.White;
VolumeIconFillBrush.Color = Colors.White;
VolumeIconFillBrush2.Color = Colors.White;
VolumeValueForegroundBrush.Color = Color.FromArgb(200, 255, 255, 255);
MagnifierTitleForegroundBrush.Color = Colors.White;
MagnifierDescForegroundBrush.Color = Color.FromArgb(200, 255, 255, 255);
Separator1BackgroundBrush.Color = Color.FromArgb(128, 255, 255, 255);
}
else
{
// 浅色主题:使用80%不透明度的白色背景
ArrowButtonBackgroundBrush.Color = Color.FromArgb(204, 255, 255, 255); // #CCFFFFFF
ContentBackgroundBrush.Color = Color.FromArgb(204, 255, 255, 255); // #CCFFFFFF
ArrowPathFillBrush.Color = Colors.Black;
VolumeIconFillBrush.Color = Colors.Black;
VolumeIconFillBrush2.Color = Colors.Black;
VolumeValueForegroundBrush.Color = Color.FromArgb(128, 0, 0, 0);
MagnifierTitleForegroundBrush.Color = Colors.Black;
MagnifierDescForegroundBrush.Color = Color.FromArgb(128, 0, 0, 0);
Separator1BackgroundBrush.Color = Color.FromArgb(255, 224, 224, 224);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"应用PPT快捷面板主题失败: {ex.Message}", LogHelper.LogType.Error);
}
}
private bool IsSystemThemeLight()
{
var light = false;
try
{
var registryKey = Microsoft.Win32.Registry.CurrentUser;
var themeKey = registryKey.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize");
if (themeKey != null)
{
var value = themeKey.GetValue("AppsUseLightTheme");
if (value != null)
{
light = (int)value == 1;
}
themeKey.Close();
}
}
catch
{
// 如果读取注册表失败,默认为浅色主题
light = true;
}
return light;
}
#endregion
#region
/// <summary>
/// 设置面板的可见性(仅在PPT模式下显示)
/// </summary>
public void UpdateVisibility(bool isInPPTMode)
{
Visibility = isInPPTMode ? Visibility.Visible : Visibility.Collapsed;
}
#endregion
}
}