关于 System.Windows.Forms的Clipboard

本文记录了一个有趣的现象:在使用Clipboard粘贴Excel表格时,不仅能够保留文本内容,还能同时保存为图片格式。这一特性展示了Clipboard的强大功能,对于WinForm开发者而言是个不错的发现。
今天在运用了Clipboard的地方,发现一个问题,当你粘贴Excel中的表格后,Clipboard中会同时存在[color=red]图片[/color]和[color=red]文本[/color]的内容。只能说Clipboard确定很强大,对于 WinForm基础知识不扎实的我来说确实是意料之外。呵呵。随手记一笔!
using DBWAT; using EBCore; using EBEmpower; using GuiDB; using Microsoft.Office.Core; using Microsoft.Win32; using SharpDX.Direct2D1; using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Data; using System.Drawing; using System.Drawing.Imaging; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Security.RightsManagement; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Forms; using System.Windows.Input; using System.Windows.Interop; using System.Windows.Markup; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using Xceed.Wpf.Toolkit; using Xceed.Wpf.Toolkit.Panels; using Xceed.Wpf.Toolkit.Primitives; using Xceed.Wpf.Toolkit.PropertyGrid.Attributes; using static System.Windows.Forms.AxHost; using static System.Windows.Forms.ImageList; using static System.Windows.Forms.VisualStyles.VisualStyleElement; using static System.Windows.Forms.VisualStyles.VisualStyleElement.TaskbarClock; using Bitmap = System.Drawing.Bitmap; using Brushes = System.Windows.Media.Brushes; using Clipboard = System.Windows.Clipboard; using Color = System.Drawing.Color; using ComboBox = System.Windows.Forms.ComboBox; using ContextMenu = System.Windows.Controls.ContextMenu; using DataGridCell = System.Windows.Controls.DataGridCell; using Image = System.Drawing.Image; using MenuItem = System.Windows.Controls.MenuItem; using MessageBox = System.Windows.MessageBox; using Point = System.Drawing.Point; using Size = System.Drawing.Size; using TextBox = System.Windows.Controls.TextBox; using Window = System.Windows.Window; namespace WatDe_EB { ///用户界面View,用户可见部分,接收展示数据,用于用户输入。 /// </summary> public partial class ProofreadListView : Window { /// <summary> /// 校审内容ViewModel /// </summary> public static ProofreadListViewModel pfviewModel = new ProofreadListViewModel(); /// <summary> /// 校审内容Model集合(接受功能的代码合集) /// </summary> public static List<ProofreadListModel> pfModels = new List<ProofreadListModel>(); /// <summary> /// 当前鼠标点击数据项在数据项集合中的索引 /// 用于索引当前数据项对应的云线标记(传递数据至功能代码) /// </summary> public static int CurrentIndex; /// <summary> /// 选定云线标记集合(接受功能代码数据) /// </summary> public static List<CloudLinePZ_P> PZ_P = new List<CloudLinePZ_P>(); /// <summary> /// 申明校审列表窗口 /// </summary> public static ProofreadListView wpf1 = null; public ProofreadListView() { InitializeComponent(); this.Owner = System.Windows.Application.Current.MainWindow; pfDataGrid.DataContext = pfviewModel; pfviewModel.DataItems.Clear(); pfviewModel.AddRange(pfModels); CurrentIndex = -1; this.Closed += MainWinClosed; // 初始化 RichTextBox 上下文菜单 InitializeRichTextBoxContextMenu(); } /// <summary> /// 窗口关闭时执行 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void MainWinClosed(object sender, EventArgs e) { PZ_P.Clear();//功能性的内容进行清除 pfviewModel.DataItems.Clear(); pfModels.Clear(); EBDB.Instance.UIReDrawAll(); EBDB.Instance.UICloseLastCMD(); } /// <summary> /// 初始化上下文菜单 /// </summary> private void InitializeRichTextBoxContextMenu() { ContextMenu menu = new ContextMenu(); MenuItem pasteItem = new MenuItem { Header = "粘贴图片", Command = ApplicationCommands.Paste }; MenuItem clearItem = new MenuItem { Header = "清空图片" }; clearItem.Click += (s, e) => rtbImages3.Document.Blocks.Clear(); menu.Items.Add(pasteItem); menu.Items.Add(clearItem); rtbImages3.ContextMenu = menu; } //各类点击事件 #region /// <summary> /// 单元格点击事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void DataGridCell_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { var cell = sender as DataGridCell;//申明一个cell单元格用来储存DataGridCell现有单元格中的数据 if (cell != null) { DataGridRow row = FindVisualParent<DataGridRow>(cell);//获取该单元格所在的行 if (row != null) { row.IsSelected = true;//选中当前行 } } //定位指定云线位置 if (cell != null && cell?.Column.Header.ToString() == "意见内容") { EBDB.Instance.UICloseLastCMD(); //数据项在数据源集合的索引 CurrentIndex = GetRowIndex(cell); EBDB.Instance.CmdRun("WatDe_EB.PositionYunxianPZ"); RenewalNum(pfviewModel.DataItems); } //点击修改状态打开PZEdit if (cell != null && cell?.Column.Header.ToString() == "修改状态" || cell != null && cell?.Column.Header.ToString() == "问题性质") { EBDB.Instance.UICloseLastCMD(); //数据项在数据源集合的索引 CurrentIndex = GetRowIndex(cell); EBDB.Instance.CmdRun("WatDe_EB.OpenPZEdit"); RenewalNum(pfviewModel.DataItems); } //if (cell != null && cell?.Column.Header.ToString() == "序号") //{ // EBDB.Instance.UICloseLastCMD(); // //数据项在数据源集合的索引 // CurrentIndex = GetRowIndex(cell); // RenewalNum(pfviewModel.DataItems); //} } /// <summary> /// 辅助方法:查找父级控件(如 DataGridRow 或 DataGridCell) /// </summary> /// <typeparam name="T"></typeparam> /// <param name="child"></param> /// <returns></returns> private T FindVisualParent<T>(DependencyObject child) where T : DependencyObject { while (child != null && !(child is T)) { child = VisualTreeHelper.GetParent(child); } return child as T; } /// <summary> /// 获取单元格的数据源集合中的索引 /// </summary> /// <param name="cell"></param> /// <returns></returns> private int GetRowIndex(DataGridCell cell) { var item = cell.DataContext;//获取行的绑定数据的对象 var collection = pfDataGrid.ItemsSource as IList; return collection?.IndexOf(item) ?? -1; } /// <summary> /// 更新数据项在界面的序号 /// </summary> /// <param name="DataItems"></param> public void RenewalNum(ObservableCollection<ProofreadListModel> DataItems) { for (int i = 0; i < pfviewModel.DataItems.Count; i++) { pfviewModel.DataItems[i].SerialNumber = i + 1; } } /// <summary> /// 数据导出按钮 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void DataExport_Btn_Click(object sender, RoutedEventArgs e) { EBDB.Instance.UICloseLastCMD(); EBDB.Instance.CmdRun(DrawProofTable); } /// <summary> /// 数据导出功能 /// </summary> public void DrawProofTable() { using (new Transaction("校审列表")) { if (EBDB.Instance.ActivView2D == null) { EBDB.Instance.UICmdLine("请在二维平面下使用该功能", null, null); return; } //窗口隐藏 EBDB.Instance.textBox.Dispatcher.Invoke(() => { this.Hide(); }); DbTable table = new DbTable(); //第一列序号 DbTableColumn column1 = new DbTableColumn(); for (int i = -1; i < pfviewModel.DataItems.Count; i++) { DbTableCell cell = null; if (i == -1) { cell = new DbTableCell("序号"); column1.Cells.Add(cell); continue; } cell = new DbTableCell((i + 1).ToString()); column1.Cells.Add(cell); } table.Columns.Add(column1); //第二列意见内容 DbTableColumn column2 = new DbTableColumn(); for (int i = -1; i < pfviewModel.DataItems.Count; i++) { DbTableCell cell = null; if (i == -1) { cell = new DbTableCell("意见内容"); column2.Cells.Add(cell); continue; } cell = new DbTableCell(pfviewModel.DataItems[i].OpinionContent.ToString()); column2.Cells.Add(cell); } table.Columns.Add(column2); //第三列批注时间 DbTableColumn column3 = new DbTableColumn(); for (int i = -1; i < pfviewModel.DataItems.Count; i++) { DbTableCell cell = null; if (i == -1) { cell = new DbTableCell("批注时间"); column3.Cells.Add(cell); continue; } cell = new DbTableCell(pfviewModel.DataItems[i].AnnotationTime.ToString()); column3.Cells.Add(cell); } table.Columns.Add(column3); //第四列修改状态 DbTableColumn column4 = new DbTableColumn(); for (int i = -1; i < pfviewModel.DataItems.Count; i++) { DbTableCell cell = null; if (i == -1) { cell = new DbTableCell("修改状态"); column4.Cells.Add(cell); continue; } cell = new DbTableCell(pfviewModel.DataItems[i].ModifyStatus.ToString()); column4.Cells.Add(cell); } table.Columns.Add(column4); //第五列批注人员 DbTableColumn column5 = new DbTableColumn(); for (int i = -1; i < pfviewModel.DataItems.Count; i++) { DbTableCell cell = null; if (i == -1) { cell = new DbTableCell("批注人员"); column5.Cells.Add(cell); continue; } cell = new DbTableCell(pfviewModel.DataItems[i].Annotator.ToString()); column5.Cells.Add(cell); } table.Columns.Add(column5); //第六列问题性质 DbTableColumn column6 = new DbTableColumn(); for (int i = -1; i < pfviewModel.DataItems.Count; i++) { DbTableCell cell = null; if (i == -1) { cell = new DbTableCell("批注人员"); column6.Cells.Add(cell); continue; } cell = new DbTableCell(pfviewModel.DataItems[i].ProblemNature.ToString()); column6.Cells.Add(cell); } table.Columns.Add(column6); DbPt pt = EBDB.Instance.UIPickPoint("请选择表格左上角插入点"); if (pt == null) { //打开窗口 EBDB.Instance.textBox.Dispatcher.Invoke(() => { this.Show(); }); } var gTable = new GuiDB.Table(pt, table, -1); gTable.ColumnWidth = 1000; gTable.RowHeight = 300; gTable.Activate(); EBDB.Instance.ActivView2D.GView.AddElement(gTable); EBDB.Instance.UIReDrawAll(); while (true) { DbPt tempPt = EBDB.Instance.UIPickPoint("请按ESC键退出"); if (tempPt == null) { break; } } //打开窗口 EBDB.Instance.textBox.Dispatcher.Invoke(() => { this.Show(); }); } } /// <summary> /// 全部标记已确认 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void MarkAll_Btn_Click(object sender, RoutedEventArgs e) { for (int i = 0; i < pfviewModel.DataItems.Count; i++) { if (pfviewModel.DataItems[i].ModifyStatus == "待确认" || pfviewModel.DataItems[i].ModifyStatus == "待修改") { pfviewModel.DataItems[i].ModifyStatus = "已确认"; PZ_P[i].PZMS = pfviewModel.DataItems[i].ModifyStatus;//这里对图元显示有关联 PZMS和pzMS区别不同 //PZ_P[i].pzMS = PZ_P[i].PZMS; } } } /// <summary> /// 全标记待修改 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void CancelMarkAll_Btn_Click(object sender, RoutedEventArgs e) { for (int i = 0; i < pfviewModel.DataItems.Count; i++) { if (pfviewModel.DataItems[i].ModifyStatus == "已确认") { pfviewModel.DataItems[i].ModifyStatus = "待修改"; PZ_P[i].PZMS = pfviewModel.DataItems[i].ModifyStatus;//这里对图元显示有关联 PZMS和pzMS区别不同 //PZ_P[i].PZMS = PZ_P[i].pzMS; } } } /// <summary> /// 退出按钮 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Exit_Btn_Click(object sender, RoutedEventArgs e) { this.Close(); } #endregion //加载示意图事件 /// <summary> /// 修改前-加载图片 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void rtbImages3_GotFocus(object sender, RoutedEventArgs e) { // 获得焦点时添加提示文本 if (rtbImages3.Document.Blocks.Count == 1) { AddHintText(); } } // 添加类级变量标记提示段落 private Paragraph _hintParagraph; // 提取提示文本添加方法 private void AddHintText() { _hintParagraph = new Paragraph(new Run("请截图后使用Ctrl+V粘贴图片...")); rtbImages3.Document.Blocks.Add(_hintParagraph); } // 提取移除文本添加方法 private void RemoveHintText() { if (_hintParagraph != null && rtbImages3.Document.Blocks.Contains(_hintParagraph)) { rtbImages3.Document.Blocks.Remove(_hintParagraph); _hintParagraph = null; // 清除引用 } } private void rtbImages3_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e) { // 直接响应Ctrl+V粘贴 if (e.Key == Key.V && (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control) { PasteImageToRichTextBox(); e.Handled = true; // 阻止事件继续传播 } } /// <summary> /// 粘贴截图并保存至富文本 /// </summary> private const double MaxImageWidth = 300; // 最大显示宽度 private const double MaxImageHeight = 150; // 最大显示高度 private void PasteImageToRichTextBox() { if (!Clipboard.ContainsImage()) { MessageBox.Show("剪贴板中没有图片"); return; } Dispatcher.Invoke(() => { try { // 清除提示文本 RemoveHintText(); // 图片保存路径 string ImageSavePath = "C:/ProgramData/EasyBIM/Proofread/"; // 确保目录存在 if (!Directory.Exists(ImageSavePath)) { Directory.CreateDirectory(ImageSavePath); } // 生成唯一文件名 string timestamp = DateTime.Now.ToString("yyyyMMddHHmmss"); string fileName = $"Image_{timestamp}.png"; string filePath = System.IO.Path.Combine(ImageSavePath, fileName); // 直接从剪贴板获取BitmapSource BitmapSource clipboardImage = Clipboard.GetImage(); if (clipboardImage == null) return; // 直接使用BitmapFrame创建BitmapImage BitmapImage bitmapImage; using (MemoryStream stream = new MemoryStream()) { // 使用BmpBitmapEncoder替代PngBitmapEncoder解决兼容性问题 BmpBitmapEncoder encoder = new BmpBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create(clipboardImage)); encoder.Save(stream); stream.Position = 0; bitmapImage = new BitmapImage(); bitmapImage.BeginInit(); bitmapImage.CacheOption = BitmapCacheOption.OnLoad; bitmapImage.StreamSource = stream; bitmapImage.EndInit(); } // 计算缩放比例 double scaleRatio = Math.Min( MaxImageWidth / bitmapImage.PixelWidth, MaxImageHeight / bitmapImage.PixelHeight ); scaleRatio = Math.Min(scaleRatio, 1.0); // 确保不放大图片 // 创建图像控件 var imageControl = new System.Windows.Controls.Image { Source = bitmapImage, Width = bitmapImage.PixelWidth * scaleRatio, Height = bitmapImage.PixelHeight * scaleRatio, Stretch = Stretch.Uniform, Margin = new Thickness(0, 5, 0, 5) }; // 创建容器 Border imageBorder = new Border { Child = imageControl, BorderBrush = Brushes.LightGray, BorderThickness = new Thickness(1), CornerRadius = new CornerRadius(4), Background = Brushes.White, Padding = new Thickness(2) }; // 创建InlineUIContainer InlineUIContainer container = new InlineUIContainer(imageBorder) { BaselineAlignment = BaselineAlignment.Center // 确保垂直居中 }; // 获取当前段落 Paragraph currentParagraph = rtbImages3.CaretPosition.Paragraph ?? new Paragraph(); // 如果是空文档则添加新段落 if (rtbImages3.Document.Blocks.Count == 0) { rtbImages3.Document.Blocks.Add(currentParagraph); } // 添加图片到段落 currentParagraph.Inlines.Add(container); // 设置新光标位置 rtbImages3.CaretPosition = container.ElementEnd; //将路径关联到当前选中的行后保存图片 if (pfDataGrid.SelectedItem != null) { var selectedItem = pfDataGrid.SelectedItem as ProofreadListModel; if (selectedItem != null) { selectedItem.ImagePath = filePath; // 使用高保真方式保存原始图片 using (FileStream fileStream = new FileStream(filePath, FileMode.Create)) { PngBitmapEncoder encoder = new PngBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create(clipboardImage)); //使用原始剪贴板图片 encoder.Save(fileStream); } // 检查ImagePath是否存在 if (!string.IsNullOrEmpty(selectedItem.ImagePath) && File.Exists(selectedItem.ImagePath)) { foreach (var item in pfDataGrid.ItemsSource) { var model = item as ProofreadListModel; if (model != null && model.ImagePath == selectedItem.ImagePath) { Dispatcher.Invoke(() => LoadImageIntoRichTextBox(selectedItem.ImagePath)); } else//没有符合model的需要重新截图 { //Dispatcher.Invoke(() => PasteImageToRichTextBox()); } } } else { // 如果没有图片,清空RichTextBox Dispatcher.Invoke(() => rtbImages3.Document.Blocks.Clear()); } } } else { rtbImages3.Document.Blocks.Clear(); MessageBox.Show("请先选择列表内相应的意见内容以关联截图"); } } catch (Exception ex) { MessageBox.Show($"图片粘贴失败: {ex.Message}"); } }); } /// <summary> /// 读取截图到富文本 /// </summary> /// <param name="imagePath"></param> private void LoadImageIntoRichTextBox(string imagePath) { try { // 创建BitmapImage BitmapImage bitmap = new BitmapImage(); bitmap.BeginInit(); bitmap.CacheOption = BitmapCacheOption.OnLoad; // 缓存图片,关闭流后仍可用 bitmap.UriSource = new Uri(imagePath); bitmap.EndInit(); // 计算缩放比例(与之前粘贴图片时的逻辑一致) double scaleRatio = Math.Min( MaxImageWidth / bitmap.PixelWidth, MaxImageHeight / bitmap.PixelHeight ); scaleRatio = Math.Min(scaleRatio, 1.0); // 确保不放大 // 创建图像控件 var imageControl = new System.Windows.Controls.Image { Source = bitmap, Width = bitmap.PixelWidth * scaleRatio, Height = bitmap.PixelHeight * scaleRatio, Stretch = Stretch.Uniform, Margin = new Thickness(0, 5, 0, 5) }; // 创建容器 Border imageBorder = new Border { Child = imageControl, BorderBrush = Brushes.LightGray, BorderThickness = new Thickness(1), CornerRadius = new CornerRadius(4), Background = Brushes.White, Padding = new Thickness(2) }; // 创建InlineUIContainer InlineUIContainer container = new InlineUIContainer(imageBorder) { BaselineAlignment = BaselineAlignment.Center }; // 创建段落并添加图片 Paragraph para = new Paragraph(); para.Inlines.Add(container); // 添加到RichTextBox rtbImages3.Document.Blocks.Add(para); } catch (Exception ex) { MessageBox.Show($"图片加载失败: {ex.Message}"); } } /// <summary> /// 修改后-加载图片 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void lstImages4_MouseDoubleClick(object sender, MouseButtonEventArgs e) { var openFileDialog4 = new Microsoft.Win32.OpenFileDialog { Filter = "图片文件|*.png;*.jpg;*.jpeg;*.bmp", Multiselect = true, }; if (openFileDialog4.ShowDialog() == true) { var _imageCollection4 = new ObservableCollection<BitmapImage>(); foreach (var screenshotPath in openFileDialog4.FileNames) { try { var bitmap = new BitmapImage(new Uri(screenshotPath)); bitmap.CacheOption = BitmapCacheOption.OnLoad; _imageCollection4.Add(bitmap); } catch { System.Windows.MessageBox.Show($"加载文件失败"); } lstImages4.ItemsSource = _imageCollection4; } } } /// <summary> /// 模型实体Model,程序数据和业务逻辑。 /// </summary> public class ProofreadListModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged;//2.属性改变的事件 protected void OnPropertyChanged(string propertyName)//3.激活事件的方法 { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } //标题样式声明(序列、意见内容、批注时间、修改状态、批注人员、问题性质) #region /// <summary> /// 序号 /// </summary> private int _serialNumber; public int SerialNumber { get { return _serialNumber; } set { _serialNumber = value; OnPropertyChanged(nameof(SerialNumber)); } } /// <summary> /// 意见内容 /// </summary> private string _opinionContent; public string OpinionContent { get { return _opinionContent; } set { _opinionContent = value; OnPropertyChanged(nameof(OpinionContent)); } } /// <summary> /// 批注时间 /// </summary> private string _annotationTime; public string AnnotationTime { get { return _annotationTime; } set { _annotationTime = value; OnPropertyChanged(nameof(AnnotationTime)); } } /// <summary> /// 修改状态 /// </summary> private string _modifyStatus; public string ModifyStatus { get { return _modifyStatus; } set { _modifyStatus = value; OnPropertyChanged(nameof(ModifyStatus)); } } /// <summary> /// 批注人员 /// </summary> private string _annotator; public string Annotator { get { return _annotator; } set { _annotator = value; OnPropertyChanged(nameof(Annotator)); } } /// <summary> /// 问题性质 /// </summary> private string _problemNature; public string ProblemNature { get { return _problemNature; } set { _problemNature = value; OnPropertyChanged(nameof(ProblemNature)); } } /// <summary> /// 图片路径 /// </summary> private string _imagePath; public string ImagePath { get { return _imagePath; } set { _imagePath = value; OnPropertyChanged(nameof(ImagePath)); } } #endregion } /// <summary> /// ViewModle中间参数桥梁 /// </summary> public class ProofreadListViewModel { public ObservableCollection<ProofreadListModel> DataItems { get; set; } = new ObservableCollection<ProofreadListModel>(); public ProofreadListViewModel() { } public void AddRange(List<ProofreadListModel> plms) { foreach (ProofreadListModel item in plms) { DataItems.Add(item); } } } } }上述为后台代码,现在我想让点击对应行就可以显示行所对应的图片。怎么实现
最新发布
09-11
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值