2025-08-03 16:46:33 +08:00
|
|
|
|
using Microsoft.Win32;
|
|
|
|
|
|
using System;
|
2025-07-21 12:44:05 +08:00
|
|
|
|
using System.IO;
|
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
using System.Windows;
|
|
|
|
|
|
using System.Windows.Controls;
|
|
|
|
|
|
using System.Windows.Media;
|
|
|
|
|
|
using System.Windows.Media.Imaging;
|
2025-08-30 21:23:36 +08:00
|
|
|
|
using System.Windows.Threading;
|
|
|
|
|
|
using Ink_Canvas.Helpers;
|
2025-07-21 12:44:05 +08:00
|
|
|
|
|
|
|
|
|
|
namespace Ink_Canvas
|
|
|
|
|
|
{
|
|
|
|
|
|
public partial class MainWindow : Window
|
|
|
|
|
|
{
|
|
|
|
|
|
#region Image
|
|
|
|
|
|
private async void BtnImageInsert_Click(object sender, RoutedEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
OpenFileDialog openFileDialog = new OpenFileDialog();
|
|
|
|
|
|
openFileDialog.Filter = "Image files (*.jpg; *.jpeg; *.png; *.bmp)|*.jpg;*.jpeg;*.png;*.bmp";
|
|
|
|
|
|
|
|
|
|
|
|
if (openFileDialog.ShowDialog() == true)
|
|
|
|
|
|
{
|
|
|
|
|
|
string filePath = openFileDialog.FileName;
|
|
|
|
|
|
|
|
|
|
|
|
Image image = await CreateAndCompressImageAsync(filePath);
|
|
|
|
|
|
|
|
|
|
|
|
if (image != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
string timestamp = "img_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff");
|
|
|
|
|
|
image.Name = timestamp;
|
|
|
|
|
|
|
2025-07-29 17:38:58 +08:00
|
|
|
|
CenterAndScaleElement(image);
|
2025-07-21 12:44:05 +08:00
|
|
|
|
inkCanvas.Children.Add(image);
|
|
|
|
|
|
|
|
|
|
|
|
timeMachine.CommitElementInsertHistory(image);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private async Task<Image> CreateAndCompressImageAsync(string filePath)
|
|
|
|
|
|
{
|
|
|
|
|
|
string savePath = Path.Combine(Settings.Automation.AutoSavedStrokesLocation, "File Dependency");
|
|
|
|
|
|
if (!Directory.Exists(savePath))
|
|
|
|
|
|
{
|
|
|
|
|
|
Directory.CreateDirectory(savePath);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string fileExtension = Path.GetExtension(filePath);
|
|
|
|
|
|
string timestamp = "img_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff");
|
|
|
|
|
|
string newFilePath = Path.Combine(savePath, timestamp + fileExtension);
|
|
|
|
|
|
|
|
|
|
|
|
await Task.Run(() => File.Copy(filePath, newFilePath, true));
|
|
|
|
|
|
|
|
|
|
|
|
return await Dispatcher.InvokeAsync(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
BitmapImage bitmapImage = new BitmapImage();
|
|
|
|
|
|
bitmapImage.BeginInit();
|
|
|
|
|
|
bitmapImage.UriSource = new Uri(newFilePath);
|
|
|
|
|
|
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
|
|
|
|
|
|
bitmapImage.EndInit();
|
|
|
|
|
|
|
|
|
|
|
|
int width = bitmapImage.PixelWidth;
|
|
|
|
|
|
int height = bitmapImage.PixelHeight;
|
|
|
|
|
|
|
|
|
|
|
|
Image image = new Image();
|
2025-07-28 11:15:35 +08:00
|
|
|
|
// 设置拉伸模式为Fill,支持任意比例缩放
|
|
|
|
|
|
image.Stretch = Stretch.Fill;
|
|
|
|
|
|
|
2025-07-21 12:44:05 +08:00
|
|
|
|
if (isLoaded && Settings.Canvas.IsCompressPicturesUploaded && (width > 1920 || height > 1080))
|
|
|
|
|
|
{
|
|
|
|
|
|
double scaleX = 1920.0 / width;
|
|
|
|
|
|
double scaleY = 1080.0 / height;
|
|
|
|
|
|
double scale = Math.Min(scaleX, scaleY);
|
|
|
|
|
|
|
|
|
|
|
|
TransformedBitmap transformedBitmap = new TransformedBitmap(bitmapImage, new ScaleTransform(scale, scale));
|
|
|
|
|
|
|
|
|
|
|
|
image.Source = transformedBitmap;
|
|
|
|
|
|
image.Width = transformedBitmap.PixelWidth;
|
|
|
|
|
|
image.Height = transformedBitmap.PixelHeight;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
image.Source = bitmapImage;
|
|
|
|
|
|
image.Width = width;
|
|
|
|
|
|
image.Height = height;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return image;
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Media
|
|
|
|
|
|
private async void BtnMediaInsert_Click(object sender, RoutedEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
OpenFileDialog openFileDialog = new OpenFileDialog();
|
|
|
|
|
|
openFileDialog.Filter = "Media files (*.mp4; *.avi; *.wmv)|*.mp4;*.avi;*.wmv";
|
|
|
|
|
|
|
|
|
|
|
|
if (openFileDialog.ShowDialog() == true)
|
|
|
|
|
|
{
|
|
|
|
|
|
string filePath = openFileDialog.FileName;
|
|
|
|
|
|
|
|
|
|
|
|
byte[] mediaBytes = await Task.Run(() => File.ReadAllBytes(filePath));
|
|
|
|
|
|
|
|
|
|
|
|
MediaElement mediaElement = await CreateMediaElementAsync(filePath);
|
|
|
|
|
|
|
|
|
|
|
|
if (mediaElement != null)
|
|
|
|
|
|
{
|
2025-07-29 17:38:58 +08:00
|
|
|
|
CenterAndScaleElement(mediaElement);
|
|
|
|
|
|
|
2025-07-21 12:44:05 +08:00
|
|
|
|
InkCanvas.SetLeft(mediaElement, 0);
|
|
|
|
|
|
InkCanvas.SetTop(mediaElement, 0);
|
|
|
|
|
|
inkCanvas.Children.Add(mediaElement);
|
|
|
|
|
|
|
|
|
|
|
|
mediaElement.LoadedBehavior = MediaState.Manual;
|
|
|
|
|
|
mediaElement.UnloadedBehavior = MediaState.Manual;
|
|
|
|
|
|
mediaElement.Loaded += async (_, args) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
mediaElement.Play();
|
|
|
|
|
|
await Task.Delay(100);
|
|
|
|
|
|
mediaElement.Pause();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
timeMachine.CommitElementInsertHistory(mediaElement);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private async Task<MediaElement> CreateMediaElementAsync(string filePath)
|
|
|
|
|
|
{
|
|
|
|
|
|
string savePath = Path.Combine(Settings.Automation.AutoSavedStrokesLocation, "File Dependency");
|
|
|
|
|
|
if (!Directory.Exists(savePath))
|
|
|
|
|
|
{
|
|
|
|
|
|
Directory.CreateDirectory(savePath);
|
|
|
|
|
|
}
|
|
|
|
|
|
return await Dispatcher.InvokeAsync(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
MediaElement mediaElement = new MediaElement();
|
|
|
|
|
|
mediaElement.Source = new Uri(filePath);
|
|
|
|
|
|
string timestamp = "media_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff");
|
|
|
|
|
|
mediaElement.Name = timestamp;
|
|
|
|
|
|
mediaElement.LoadedBehavior = MediaState.Manual;
|
|
|
|
|
|
mediaElement.UnloadedBehavior = MediaState.Manual;
|
|
|
|
|
|
|
|
|
|
|
|
mediaElement.Width = 256;
|
|
|
|
|
|
mediaElement.Height = 256;
|
|
|
|
|
|
|
|
|
|
|
|
string fileExtension = Path.GetExtension(filePath);
|
|
|
|
|
|
string newFilePath = Path.Combine(savePath, mediaElement.Name + fileExtension);
|
|
|
|
|
|
|
|
|
|
|
|
File.Copy(filePath, newFilePath, true);
|
|
|
|
|
|
|
|
|
|
|
|
mediaElement.Source = new Uri(newFilePath);
|
|
|
|
|
|
|
|
|
|
|
|
return mediaElement;
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
2025-07-28 19:02:45 +08:00
|
|
|
|
|
|
|
|
|
|
#region Image Operations
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 旋转图片
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="image">要旋转的图片</param>
|
|
|
|
|
|
/// <param name="angle">旋转角度(正数为顺时针,负数为逆时针)</param>
|
|
|
|
|
|
private void RotateImage(Image image, double angle)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (image == null) return;
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 获取当前的变换
|
|
|
|
|
|
var transformGroup = image.RenderTransform as TransformGroup ?? new TransformGroup();
|
|
|
|
|
|
|
|
|
|
|
|
// 查找现有的旋转变换
|
|
|
|
|
|
RotateTransform rotateTransform = null;
|
|
|
|
|
|
foreach (Transform transform in transformGroup.Children)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (transform is RotateTransform rt)
|
|
|
|
|
|
{
|
|
|
|
|
|
rotateTransform = rt;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 如果没有旋转变换,创建一个新的
|
|
|
|
|
|
if (rotateTransform == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
rotateTransform = new RotateTransform();
|
|
|
|
|
|
transformGroup.Children.Add(rotateTransform);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 设置旋转中心为图片中心
|
|
|
|
|
|
rotateTransform.CenterX = image.ActualWidth / 2;
|
|
|
|
|
|
rotateTransform.CenterY = image.ActualHeight / 2;
|
|
|
|
|
|
|
|
|
|
|
|
// 累加旋转角度
|
|
|
|
|
|
rotateTransform.Angle = (rotateTransform.Angle + angle) % 360;
|
|
|
|
|
|
|
|
|
|
|
|
// 应用变换
|
|
|
|
|
|
image.RenderTransform = transformGroup;
|
|
|
|
|
|
|
|
|
|
|
|
// 提交到时间机器以支持撤销
|
|
|
|
|
|
// 注意:旋转操作目前不支持撤销,因为需要更复杂的历史记录机制
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 记录错误但不中断程序
|
|
|
|
|
|
System.Diagnostics.Debug.WriteLine($"旋转图片时发生错误: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-31 13:23:33 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 克隆图片
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="image">要克隆的图片</param>
|
|
|
|
|
|
private void CloneImage(Image image)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (image == null) return;
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 创建图片的副本
|
|
|
|
|
|
var clonedImage = new Image
|
|
|
|
|
|
{
|
|
|
|
|
|
Source = image.Source,
|
|
|
|
|
|
Width = image.Width,
|
|
|
|
|
|
Height = image.Height,
|
|
|
|
|
|
Stretch = image.Stretch,
|
|
|
|
|
|
RenderTransform = image.RenderTransform?.Clone() as Transform
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 设置位置,稍微偏移以避免重叠
|
|
|
|
|
|
InkCanvas.SetLeft(clonedImage, InkCanvas.GetLeft(image) + 20);
|
|
|
|
|
|
InkCanvas.SetTop(clonedImage, InkCanvas.GetTop(image) + 20);
|
|
|
|
|
|
|
|
|
|
|
|
// 添加到画布
|
|
|
|
|
|
inkCanvas.Children.Add(clonedImage);
|
|
|
|
|
|
|
|
|
|
|
|
// 提交到时间机器以支持撤销
|
|
|
|
|
|
timeMachine.CommitElementInsertHistory(clonedImage);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 记录错误但不中断程序
|
|
|
|
|
|
System.Diagnostics.Debug.WriteLine($"克隆图片时发生错误: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 克隆图片到新页面
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="image">要克隆的图片</param>
|
|
|
|
|
|
private void CloneImageToNewBoard(Image image)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (image == null) return;
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 创建图片的副本
|
|
|
|
|
|
var clonedImage = new Image
|
|
|
|
|
|
{
|
|
|
|
|
|
Source = image.Source,
|
|
|
|
|
|
Width = image.Width,
|
|
|
|
|
|
Height = image.Height,
|
|
|
|
|
|
Stretch = image.Stretch,
|
|
|
|
|
|
RenderTransform = image.RenderTransform?.Clone() as Transform
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 设置位置,稍微偏移以避免重叠
|
|
|
|
|
|
InkCanvas.SetLeft(clonedImage, InkCanvas.GetLeft(image) + 20);
|
|
|
|
|
|
InkCanvas.SetTop(clonedImage, InkCanvas.GetTop(image) + 20);
|
|
|
|
|
|
|
|
|
|
|
|
// 创建新页面
|
|
|
|
|
|
BtnWhiteBoardAdd_Click(null, null);
|
|
|
|
|
|
|
|
|
|
|
|
// 添加到新页面的画布
|
|
|
|
|
|
inkCanvas.Children.Add(clonedImage);
|
|
|
|
|
|
|
|
|
|
|
|
// 提交到时间机器以支持撤销
|
|
|
|
|
|
timeMachine.CommitElementInsertHistory(clonedImage);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 记录错误但不中断程序
|
|
|
|
|
|
System.Diagnostics.Debug.WriteLine($"克隆图片到新页面时发生错误: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 缩放图片
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="image">要缩放的图片</param>
|
|
|
|
|
|
/// <param name="scaleFactor">缩放因子(大于1为放大,小于1为缩小)</param>
|
|
|
|
|
|
private void ScaleImage(Image image, double scaleFactor)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (image == null) return;
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 获取当前的变换
|
|
|
|
|
|
var transformGroup = image.RenderTransform as TransformGroup ?? new TransformGroup();
|
|
|
|
|
|
|
|
|
|
|
|
// 查找现有的缩放变换
|
|
|
|
|
|
ScaleTransform scaleTransform = null;
|
|
|
|
|
|
foreach (Transform transform in transformGroup.Children)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (transform is ScaleTransform st)
|
|
|
|
|
|
{
|
|
|
|
|
|
scaleTransform = st;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 如果没有缩放变换,创建一个新的
|
|
|
|
|
|
if (scaleTransform == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
scaleTransform = new ScaleTransform();
|
|
|
|
|
|
transformGroup.Children.Add(scaleTransform);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 设置缩放中心为图片中心
|
|
|
|
|
|
scaleTransform.CenterX = image.ActualWidth / 2;
|
|
|
|
|
|
scaleTransform.CenterY = image.ActualHeight / 2;
|
|
|
|
|
|
|
|
|
|
|
|
// 应用缩放因子
|
|
|
|
|
|
scaleTransform.ScaleX *= scaleFactor;
|
|
|
|
|
|
scaleTransform.ScaleY *= scaleFactor;
|
|
|
|
|
|
|
|
|
|
|
|
// 应用变换
|
|
|
|
|
|
image.RenderTransform = transformGroup;
|
|
|
|
|
|
|
|
|
|
|
|
// 提交到时间机器以支持撤销
|
|
|
|
|
|
// 注意:缩放操作目前不支持撤销,因为需要更复杂的历史记录机制
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 记录错误但不中断程序
|
|
|
|
|
|
System.Diagnostics.Debug.WriteLine($"缩放图片时发生错误: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-28 19:02:45 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 删除图片
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="image">要删除的图片</param>
|
|
|
|
|
|
private void DeleteImage(Image image)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (image == null) return;
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 从画布中移除图片
|
|
|
|
|
|
if (inkCanvas.Children.Contains(image))
|
|
|
|
|
|
{
|
|
|
|
|
|
inkCanvas.Children.Remove(image);
|
|
|
|
|
|
|
|
|
|
|
|
// 提交到时间机器以支持撤销
|
|
|
|
|
|
timeMachine.CommitElementRemoveHistory(image);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 记录错误但不中断程序
|
|
|
|
|
|
System.Diagnostics.Debug.WriteLine($"删除图片时发生错误: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
2025-07-29 17:38:58 +08:00
|
|
|
|
|
|
|
|
|
|
private void CenterAndScaleElement(FrameworkElement element)
|
|
|
|
|
|
{
|
2025-08-30 21:23:36 +08:00
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 确保元素已加载且有有效尺寸
|
|
|
|
|
|
if (element == null || element.ActualWidth <= 0 || element.ActualHeight <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 如果元素尺寸无效,等待加载完成后再处理
|
|
|
|
|
|
element.Loaded += (sender, e) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
Dispatcher.BeginInvoke(new Action(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
CenterAndScaleElement(element);
|
|
|
|
|
|
}), System.Windows.Threading.DispatcherPriority.Loaded);
|
|
|
|
|
|
};
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取画布的实际尺寸
|
|
|
|
|
|
double canvasWidth = inkCanvas.ActualWidth;
|
|
|
|
|
|
double canvasHeight = inkCanvas.ActualHeight;
|
|
|
|
|
|
|
|
|
|
|
|
// 如果画布尺寸为0,使用窗口尺寸作为备选
|
|
|
|
|
|
if (canvasWidth <= 0 || canvasHeight <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
canvasWidth = this.ActualWidth;
|
|
|
|
|
|
canvasHeight = this.ActualHeight;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 如果仍然为0,使用屏幕尺寸
|
|
|
|
|
|
if (canvasWidth <= 0 || canvasHeight <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
canvasWidth = SystemParameters.PrimaryScreenWidth;
|
|
|
|
|
|
canvasHeight = SystemParameters.PrimaryScreenHeight;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 计算最大允许尺寸(画布的70%)
|
|
|
|
|
|
double maxWidth = canvasWidth * 0.7;
|
|
|
|
|
|
double maxHeight = canvasHeight * 0.7;
|
|
|
|
|
|
|
|
|
|
|
|
// 获取元素的当前尺寸
|
|
|
|
|
|
double elementWidth = element.ActualWidth;
|
|
|
|
|
|
double elementHeight = element.ActualHeight;
|
|
|
|
|
|
|
|
|
|
|
|
// 计算缩放比例
|
|
|
|
|
|
double scaleX = maxWidth / elementWidth;
|
|
|
|
|
|
double scaleY = maxHeight / elementHeight;
|
|
|
|
|
|
double scale = Math.Min(scaleX, scaleY);
|
|
|
|
|
|
|
|
|
|
|
|
// 如果元素本身比最大尺寸小,不进行缩放
|
|
|
|
|
|
if (scale > 1.0)
|
|
|
|
|
|
{
|
|
|
|
|
|
scale = 1.0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 计算新的尺寸
|
|
|
|
|
|
double newWidth = elementWidth * scale;
|
|
|
|
|
|
double newHeight = elementHeight * scale;
|
2025-07-29 17:38:58 +08:00
|
|
|
|
|
2025-08-30 21:23:36 +08:00
|
|
|
|
// 设置元素尺寸
|
|
|
|
|
|
element.Width = newWidth;
|
|
|
|
|
|
element.Height = newHeight;
|
2025-07-29 17:38:58 +08:00
|
|
|
|
|
2025-08-30 21:23:36 +08:00
|
|
|
|
// 计算居中位置
|
|
|
|
|
|
double centerX = (canvasWidth - newWidth) / 2;
|
|
|
|
|
|
double centerY = (canvasHeight - newHeight) / 2;
|
2025-07-30 14:18:45 +08:00
|
|
|
|
|
2025-08-30 21:23:36 +08:00
|
|
|
|
// 确保位置不为负数
|
|
|
|
|
|
centerX = Math.Max(0, centerX);
|
|
|
|
|
|
centerY = Math.Max(0, centerY);
|
2025-07-29 17:38:58 +08:00
|
|
|
|
|
2025-08-30 21:23:36 +08:00
|
|
|
|
// 设置位置
|
|
|
|
|
|
InkCanvas.SetLeft(element, centerX);
|
|
|
|
|
|
InkCanvas.SetTop(element, centerY);
|
2025-07-29 17:38:58 +08:00
|
|
|
|
|
2025-08-30 21:23:36 +08:00
|
|
|
|
// 清除任何现有的RenderTransform
|
|
|
|
|
|
element.RenderTransform = Transform.Identity;
|
2025-07-29 17:38:58 +08:00
|
|
|
|
|
2025-08-30 21:23:36 +08:00
|
|
|
|
LogHelper.WriteLogToFile($"元素居中完成: 位置({centerX}, {centerY}), 尺寸({newWidth}x{newHeight})");
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
LogHelper.WriteLogToFile($"元素居中失败: {ex.Message}", LogHelper.LogType.Error);
|
|
|
|
|
|
}
|
2025-07-29 17:38:58 +08:00
|
|
|
|
}
|
2025-07-21 12:44:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|