add:PPT增强预览视图

This commit is contained in:
2026-04-30 19:09:55 +08:00
parent 6fd4a4f036
commit 40fc4e89e0
7 changed files with 332 additions and 11 deletions
+293 -9
View File
@@ -12,7 +12,10 @@ using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Ink;
using System.Windows.Markup;
using System.Windows.Media.Imaging;
using System.Windows.Media;
using System.Windows.Threading;
using Application = System.Windows.Application;
@@ -180,6 +183,9 @@ namespace Ink_Canvas
/// PowerPoint 全屏放映顶层窗口类名(与编辑态 PPTFrameClass 区分)。
/// </summary>
private const string PowerPointSlideShowWindowClassName = "screenClass";
private Popup _pptEnhancedPreviewPopup;
private ListBox _pptEnhancedPreviewListBox;
#endregion
#region PPT Managers
@@ -1371,6 +1377,8 @@ namespace Ink_Canvas
{
try
{
await Application.Current.Dispatcher.InvokeAsync(() => DestroyPptEnhancedPreviewPopup());
if (Settings.Automation.IsAutoFoldAfterPPTSlideShow && !isFloatingBarFolded)
{
FoldFloatingBar_MouseUp(new object(), null);
@@ -2349,19 +2357,26 @@ namespace Ink_Canvas
GridTransparencyFakeBackground.Background = new SolidColorBrush(StringToColor("#01FFFFFF"));
CursorIcon_Click(null, null);
// 使用新的PPT管理器显示导航
if (_pptManager.TryShowSlideNavigation())
if (Settings.PowerPointSettings.EnablePPTButtonEnhancedPreview)
{
LogHelper.WriteLogToFile("成功显示PPT幻灯片导航", LogHelper.LogType.Trace);
// 若启用了“翻页时跳过PPT动画”,显示导航后把焦点拉回本窗口
if (Settings.PowerPointSettings.SkipAnimationsWhenGoNext)
{
try { this.Activate(); } catch { }
}
await ShowEnhancedPptPreviewAsync(sender as FrameworkElement);
}
else
{
LogHelper.WriteLogToFile("显示PPT幻灯片导航失败", LogHelper.LogType.Warning);
// 使用新的PPT管理器显示导航
if (_pptManager.TryShowSlideNavigation())
{
LogHelper.WriteLogToFile("成功显示PPT幻灯片导航", LogHelper.LogType.Trace);
// 若启用了“翻页时跳过PPT动画”,显示导航后把焦点拉回本窗口
if (Settings.PowerPointSettings.SkipAnimationsWhenGoNext)
{
try { this.Activate(); } catch { }
}
}
else
{
LogHelper.WriteLogToFile("显示PPT幻灯片导航失败", LogHelper.LogType.Warning);
}
}
// 控制居中
@@ -2377,6 +2392,273 @@ namespace Ink_Canvas
}
}
private sealed class PptEnhancedPreviewItem
{
public int SlideNumber { get; set; }
public BitmapImage Thumbnail { get; set; }
}
private async Task ShowEnhancedPptPreviewAsync(FrameworkElement placementTarget = null)
{
if (_pptEnhancedPreviewPopup != null && _pptEnhancedPreviewPopup.IsOpen && placementTarget != null &&
ReferenceEquals(_pptEnhancedPreviewPopup.PlacementTarget, placementTarget))
{
_pptEnhancedPreviewPopup.IsOpen = false;
return;
}
var slides = await Task.Run(BuildPptPreviewItems);
if (slides == null || slides.Count == 0)
{
LogHelper.WriteLogToFile("PPT增强预览未生成可用缩略图,改用默认导航", LogHelper.LogType.Warning);
_pptManager.TryShowSlideNavigation();
return;
}
await Application.Current.Dispatcher.InvokeAsync(() =>
{
EnsurePptEnhancedPreviewPopupCreated();
if (_pptEnhancedPreviewListBox == null || _pptEnhancedPreviewPopup == null) return;
_pptEnhancedPreviewListBox.ItemsSource = slides;
var currentSlide = _pptManager?.GetCurrentSlideNumber() ?? 0;
if (currentSlide > 0)
{
var selected = slides.Find(s => s.SlideNumber == currentSlide);
_pptEnhancedPreviewListBox.SelectedItem = selected;
if (selected != null)
{
_pptEnhancedPreviewListBox.ScrollIntoView(selected);
}
}
var anchor = placementTarget ?? PPTLSPageButton;
if (anchor != null)
{
_pptEnhancedPreviewPopup.PlacementTarget = anchor;
if (anchor == PPTLBPageButton || anchor == PPTRBPageButton)
{
_pptEnhancedPreviewPopup.Placement = PlacementMode.Top;
_pptEnhancedPreviewPopup.HorizontalOffset = 0;
_pptEnhancedPreviewPopup.VerticalOffset = -10;
}
else if (anchor == PPTRSPageButton)
{
_pptEnhancedPreviewPopup.Placement = PlacementMode.Left;
_pptEnhancedPreviewPopup.HorizontalOffset = -12;
_pptEnhancedPreviewPopup.VerticalOffset = 0;
}
else
{
_pptEnhancedPreviewPopup.Placement = PlacementMode.Right;
_pptEnhancedPreviewPopup.HorizontalOffset = 12;
_pptEnhancedPreviewPopup.VerticalOffset = 0;
}
}
_pptEnhancedPreviewPopup.IsOpen = true;
});
}
private void DestroyPptEnhancedPreviewPopup()
{
try
{
if (_pptEnhancedPreviewListBox != null)
{
_pptEnhancedPreviewListBox.MouseUp -= PPTEnhancedPreviewListBox_OnMouseUp;
_pptEnhancedPreviewListBox.ItemsSource = null;
}
if (_pptEnhancedPreviewPopup != null)
{
_pptEnhancedPreviewPopup.IsOpen = false;
_pptEnhancedPreviewPopup.Child = null;
_pptEnhancedPreviewPopup.PlacementTarget = null;
}
}
catch
{
// ignore dispose errors
}
finally
{
_pptEnhancedPreviewListBox = null;
_pptEnhancedPreviewPopup = null;
}
}
private void EnsurePptEnhancedPreviewPopupCreated()
{
if (_pptEnhancedPreviewPopup != null) return;
var listBox = new ListBox
{
Width = 220,
Height = 320,
Background = Brushes.Transparent,
BorderBrush = Brushes.Transparent,
BorderThickness = new Thickness(0),
SelectionMode = SelectionMode.Single
};
listBox.SetValue(ScrollViewer.VerticalScrollBarVisibilityProperty, ScrollBarVisibility.Hidden);
listBox.SetValue(ScrollViewer.HorizontalScrollBarVisibilityProperty, ScrollBarVisibility.Disabled);
listBox.MouseUp += PPTEnhancedPreviewListBox_OnMouseUp;
var templateXaml = @"
<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>
<Border Margin='6,5' Padding='0' Height='118' CornerRadius='6' BorderThickness='0' Background='Transparent'>
<Border BorderBrush='#7a8ea8' BorderThickness='0.6' CornerRadius='6' Background='Transparent' Padding='1'>
<Border CornerRadius='5' ClipToBounds='True' Background='Transparent'>
<Image Source='{Binding Thumbnail}' Stretch='UniformToFill'/>
</Border>
</Border>
</Border>
</DataTemplate>";
listBox.ItemTemplate = (DataTemplate)XamlReader.Parse(templateXaml);
var itemStyleXaml = @"
<Style xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
TargetType='ListBoxItem'>
<Setter Property='Background' Value='Transparent'/>
<Setter Property='BorderThickness' Value='0'/>
<Setter Property='FocusVisualStyle' Value='{x:Null}'/>
<Setter Property='Template'>
<Setter.Value>
<ControlTemplate TargetType='ListBoxItem'>
<ContentPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>";
listBox.ItemContainerStyle = (Style)XamlReader.Parse(itemStyleXaml);
_pptEnhancedPreviewListBox = listBox;
_pptEnhancedPreviewPopup = new Popup
{
AllowsTransparency = true,
StaysOpen = true,
Placement = PlacementMode.Right,
PopupAnimation = PopupAnimation.Fade,
Child = listBox
};
}
private void PPTEnhancedPreviewListBox_OnMouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (_pptEnhancedPreviewListBox?.SelectedItem is not PptEnhancedPreviewItem item) return;
try
{
if (_pptManager?.TryNavigateToSlide(item.SlideNumber) == true)
{
LogHelper.WriteLogToFile($"PPT增强预览跳转成功:{item.SlideNumber}", LogHelper.LogType.Trace);
}
else
{
LogHelper.WriteLogToFile($"PPT增强预览跳转失败:{item.SlideNumber}", LogHelper.LogType.Warning);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"PPT增强预览跳转异常: {ex}", LogHelper.LogType.Error);
}
finally
{
if (_pptEnhancedPreviewPopup != null)
{
_pptEnhancedPreviewPopup.IsOpen = false;
}
}
}
private List<PptEnhancedPreviewItem> BuildPptPreviewItems()
{
var result = new List<PptEnhancedPreviewItem>();
string tempDir = null;
Presentation activePresentation = null;
Slides slides = null;
try
{
activePresentation = _pptManager?.GetCurrentActivePresentation() as Presentation;
if (activePresentation == null)
{
return result;
}
slides = activePresentation.Slides;
if (slides == null) return result;
int count = slides.Count;
if (count <= 0) return result;
tempDir = Path.Combine(Path.GetTempPath(), "InkCanvas", "PPTPreviews", Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(tempDir);
for (int i = 1; i <= count; i++)
{
Slide slide = null;
try
{
slide = slides[i];
var imagePath = Path.Combine(tempDir, $"slide_{i:0000}.png");
slide.Export(imagePath, "PNG", 320, 180);
var image = LoadBitmapImage(imagePath);
if (image == null) continue;
result.Add(new PptEnhancedPreviewItem
{
SlideNumber = i,
Thumbnail = image
});
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"生成PPT第{i}页缩略图失败: {ex.Message}", LogHelper.LogType.Warning);
}
finally
{
if (slide != null)
{
try { Marshal.ReleaseComObject(slide); } catch { }
}
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"构建PPT增强预览列表失败: {ex}", LogHelper.LogType.Error);
}
finally
{
if (!string.IsNullOrWhiteSpace(tempDir) && Directory.Exists(tempDir))
{
try { Directory.Delete(tempDir, true); } catch { }
}
}
return result;
}
private static BitmapImage LoadBitmapImage(string path)
{
try
{
if (!File.Exists(path)) return null;
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.UriSource = new Uri(path, UriKind.Absolute);
bitmap.EndInit();
bitmap.Freeze();
return bitmap;
}
catch
{
return null;
}
}
/// <summary>
/// 处理“开始幻灯片放映”按钮的点击事件
/// </summary>
@@ -2505,6 +2787,8 @@ namespace Ink_Canvas
{
try
{
await Application.Current.Dispatcher.InvokeAsync(() => DestroyPptEnhancedPreviewPopup());
if (Settings.Automation.IsAutoFoldAfterPPTSlideShow && !isFloatingBarFolded)
{
FoldFloatingBar_MouseUp(new object(), null);
+1
View File
@@ -905,6 +905,7 @@ namespace Ink_Canvas
Settings.PowerPointSettings.IsEnableTwoFingerGestureInPresentationMode = false;
Settings.PowerPointSettings.IsEnableFingerGestureSlideShowControl = false;
Settings.PowerPointSettings.IsSupportWPS = false;
Settings.PowerPointSettings.EnablePPTButtonEnhancedPreview = false;
Settings.Canvas.InkWidth = 2.5;
Settings.Canvas.IsShowCursor = false;