improve:PPT侧边面板

This commit is contained in:
2026-01-10 20:09:20 +08:00
parent 221a0f8e85
commit be6eb73671
2 changed files with 418 additions and 33 deletions
+47 -21
View File
@@ -170,27 +170,52 @@
</Separator.Background>
</Separator>
<!-- 图片插入按钮 -->
<Button x:Name="InsertImageButton"
Content="插入图片"
FontSize="11"
Height="30"
Background="#3b82f6"
Foreground="White"
BorderThickness="0"
Cursor="Hand"
Click="InsertImageButton_Click"
Margin="0,0,0,8">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}"
CornerRadius="4"
Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
<!-- 图片插入按钮区域 -->
<StackPanel Orientation="Vertical" Margin="0,0,0,8">
<!-- 选择文件按钮 -->
<Button x:Name="InsertImageSelectFileButton"
Content="选择文件"
FontSize="11"
Height="30"
Background="#3b82f6"
Foreground="White"
BorderThickness="0"
Cursor="Hand"
Click="InsertImageSelectFileButton_Click"
Margin="0,0,0,4">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}"
CornerRadius="4"
Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
<!-- 截图插入按钮 -->
<Button x:Name="InsertImageScreenshotButton"
Content="截图插入"
FontSize="11"
Height="30"
Background="#3b82f6"
Foreground="White"
BorderThickness="0"
Cursor="Hand"
Click="InsertImageScreenshotButton_Click"
Margin="0,0,0,0">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}"
CornerRadius="4"
Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
</StackPanel>
<!-- 聚焦放大镜(暂未设计)- 暂时隐藏 -->
<Border x:Name="MagnifierSection" Margin="0,0,0,8" Visibility="Collapsed">
@@ -216,3 +241,4 @@
</Grid>
</UserControl>
+371 -12
View File
@@ -1,6 +1,7 @@
using Ink_Canvas.Helpers;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
@@ -9,6 +10,7 @@ using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using Microsoft.Win32;
using Newtonsoft.Json;
@@ -134,16 +136,128 @@ namespace Ink_Canvas.Windows
// 获取MainWindow引用
_mainWindow = Application.Current.MainWindow as MainWindow;
// 订阅PPT事件
SubscribeToPPTEvents();
// 延迟初始化音量显示,确保音频设备已初始化
SubscribeToInkCanvasChildrenChanges();
Dispatcher.BeginInvoke(new Action(() =>
{
UpdateVolumeDisplay();
}), DispatcherPriority.Loaded);
}
private void SubscribeToInkCanvasChildrenChanges()
{
try
{
if (_mainWindow == null) return;
System.Windows.Controls.InkCanvas inkCanvas = null;
var inkCanvasField = _mainWindow.GetType().GetField("inkCanvas",
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)
{
var inkCanvasProperty = _mainWindow.GetType().GetProperty("inkCanvas",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
inkCanvas = inkCanvasProperty?.GetValue(_mainWindow) as System.Windows.Controls.InkCanvas;
}
if (inkCanvas != null && inkCanvas.Children is INotifyCollectionChanged notifyCollection)
{
notifyCollection.CollectionChanged += InkCanvasChildren_CollectionChanged;
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"订阅inkCanvas.Children变化事件失败: {ex.Message}", LogHelper.LogType.Error);
}
}
private void InkCanvasChildren_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
try
{
if (e.Action == NotifyCollectionChangedAction.Remove)
{
foreach (var item in e.OldItems)
{
if (item is System.Windows.Controls.Image image)
{
RemoveImageFromPPT(image);
}
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理inkCanvas.Children变化失败: {ex.Message}", LogHelper.LogType.Error);
}
}
private void RemoveImageFromPPT(System.Windows.Controls.Image image)
{
try
{
if (image == null) return;
if (_pptImages.ContainsKey(image))
{
int slideNumber = _pptImages[image];
_pptImages.Remove(image);
if (_pptImagePaths.ContainsKey(slideNumber))
{
string imagePath = image.Tag as string;
if (!string.IsNullOrEmpty(imagePath) && _pptImagePaths[slideNumber].Contains(imagePath))
{
_pptImagePaths[slideNumber].Remove(imagePath);
if (_pptImagePaths[slideNumber].Count == 0)
{
_pptImagePaths.Remove(slideNumber);
DeletePPTImagePathsFile(slideNumber);
}
else
{
SavePPTImagePaths(slideNumber);
}
LogHelper.WriteLogToFile($"已从PPT页面{slideNumber}移除图片: {imagePath}");
}
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"从PPT关联数据中移除图片失败: {ex.Message}", LogHelper.LogType.Error);
}
}
private void DeletePPTImagePathsFile(int slideIndex)
{
try
{
if (slideIndex <= 0) return;
var folderPath = GetPresentationFolderPath();
if (string.IsNullOrEmpty(folderPath) || !Directory.Exists(folderPath))
return;
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);
}
}
private void SubscribeToPPTEvents()
{
try
@@ -359,6 +473,38 @@ namespace Ink_Canvas.Windows
private void PPTQuickPanel_Unloaded(object sender, RoutedEventArgs e)
{
SystemEvents.UserPreferenceChanged -= SystemEvents_UserPreferenceChanged;
UnsubscribeFromInkCanvasChildrenChanges();
}
private void UnsubscribeFromInkCanvasChildrenChanges()
{
try
{
if (_mainWindow == null) return;
System.Windows.Controls.InkCanvas inkCanvas = null;
var inkCanvasField = _mainWindow.GetType().GetField("inkCanvas",
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)
{
var inkCanvasProperty = _mainWindow.GetType().GetProperty("inkCanvas",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
inkCanvas = inkCanvasProperty?.GetValue(_mainWindow) as System.Windows.Controls.InkCanvas;
}
if (inkCanvas != null && inkCanvas.Children is INotifyCollectionChanged notifyCollection)
{
notifyCollection.CollectionChanged -= InkCanvasChildren_CollectionChanged;
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"取消订阅inkCanvas.Children变化事件失败: {ex.Message}", LogHelper.LogType.Error);
}
}
private void SystemEvents_UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e)
@@ -775,13 +921,12 @@ namespace Ink_Canvas.Windows
#region
private async void InsertImageButton_Click(object sender, RoutedEventArgs e)
private async void InsertImageSelectFileButton_Click(object sender, RoutedEventArgs e)
{
if (_mainWindow == null) return;
try
{
// 调用MainWindow的图片插入功能
var dialog = new OpenFileDialog
{
Filter = "图片文件|*.jpg;*.jpeg;*.png;*.bmp;*.gif"
@@ -791,7 +936,6 @@ namespace Ink_Canvas.Windows
{
string filePath = dialog.FileName;
// 使用反射调用MainWindow的CreateAndCompressImageAsync方法
var createImageMethod = _mainWindow.GetType().GetMethod("CreateAndCompressImageAsync",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
@@ -804,8 +948,6 @@ namespace Ink_Canvas.Windows
if (image != null)
{
image.Tag = filePath;
// 使用反射调用MainWindow的图片插入相关方法
await InsertImageToMainWindow(image, filePath);
}
}
@@ -822,6 +964,227 @@ namespace Ink_Canvas.Windows
}
}
private async void InsertImageScreenshotButton_Click(object sender, RoutedEventArgs e)
{
if (_mainWindow == null) return;
try
{
var captureScreenshotMethod = _mainWindow.GetType().GetMethod("CaptureScreenshotAndInsert",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
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;
System.Windows.Controls.InkCanvas inkCanvas = null;
var inkCanvasField = _mainWindow.GetType().GetField("inkCanvas",
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)
{
var inkCanvasProperty = _mainWindow.GetType().GetProperty("inkCanvas",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
inkCanvas = inkCanvasProperty?.GetValue(_mainWindow) as System.Windows.Controls.InkCanvas;
}
if (inkCanvas == null) return;
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;
}
}
if (lastScreenshot == null) return;
string screenshotFilePath = await SaveScreenshotToFile(lastScreenshot);
if (string.IsNullOrEmpty(screenshotFilePath))
{
LogHelper.WriteLogToFile("保存截图文件失败", LogHelper.LogType.Warning);
return;
}
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;
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");
}
}
}
}
}
}
if (string.IsNullOrEmpty(savePath))
{
LogHelper.WriteLogToFile("无法获取AutoSavedStrokesLocation", LogHelper.LogType.Warning);
return null;
}
if (!Directory.Exists(savePath))
{
Directory.CreateDirectory(savePath);
}
string timestamp = image.Name;
string filePath = Path.Combine(savePath, timestamp + ".png");
await Application.Current.Dispatcher.InvokeAsync(() =>
{
if (image.Source is BitmapSource bitmapSource)
{
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmapSource));
using (var fileStream = new FileStream(filePath, FileMode.Create))
{
encoder.Save(fileStream);
}
}
});
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;
await Application.Current.Dispatcher.InvokeAsync(() =>
{
try
{
int currentSlideNumber = 0;
try
{
var pptManagerProperty = _mainWindow.GetType().GetProperty("PPTManager",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
var pptManager = pptManagerProperty?.GetValue(_mainWindow);
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;
}
}
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);
}
if (currentSlideNumber > 0 && !string.IsNullOrEmpty(filePath))
{
_pptImages[image] = currentSlideNumber;
if (!_pptImagePaths.ContainsKey(currentSlideNumber))
{
_pptImagePaths[currentSlideNumber] = new List<string>();
}
_pptImagePaths[currentSlideNumber].Add(filePath);
SavePPTImagePaths(currentSlideNumber);
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);
}
private async System.Threading.Tasks.Task InsertImageToMainWindow(System.Windows.Controls.Image image, string originalFilePath = null, bool saveToJson = true)
{
if (_mainWindow == null || image == null) return;
@@ -839,10 +1202,7 @@ namespace Ink_Canvas.Windows
image.IsHitTestVisible = true;
image.Focusable = false;
// 获取inkCanvas - 尝试字段和属性两种方式
System.Windows.Controls.InkCanvas inkCanvas = null;
// 先尝试字段
var inkCanvasField = _mainWindow.GetType().GetField("inkCanvas",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
if (inkCanvasField != null)
@@ -850,7 +1210,6 @@ namespace Ink_Canvas.Windows
inkCanvas = inkCanvasField.GetValue(_mainWindow) as System.Windows.Controls.InkCanvas;
}
// 如果字段获取失败,尝试属性
if (inkCanvas == null)
{
var inkCanvasProperty = _mainWindow.GetType().GetProperty("inkCanvas",