在富文本框中的光标位置插入图像

我知道有这样的各种问题,但我问,因为我无法理解所有的答案。 我有RichTextBox ,我希望用户能够在当前光标位置插入图像。

我尝试使用Clipboard设置图像,然后将其粘贴到富文本框中。 这可行,但我被告知其不良做法,因为它在不通知用户的情况下更改cliboard中的数据。

这就是我尝试过的

  private bool CheckIfImage(string filename) { if (filename.EndsWith(".jpeg")) { return true; } else if (filename.EndsWith(".jpg")) { return true; } else if (filename.EndsWith(".png")) { return true; } else if (filename.EndsWith(".ico")) { return true; } else if (filename.EndsWith(".gif")) { return true; } else if (filename.EndsWith(".bmp")) { return true; } else if (filename.EndsWith(".emp")) { return true; } else if (filename.EndsWith(".wmf")) { return true; } else if (filename.EndsWith(".tiff")) { return true; } else { return false; } } private void openFileDialog2_FileOk(object sender, CancelEventArgs e) { if (CheckIfImage(openFileDialog2.FileName.ToLower()) == true) { Image img = Image.FromFile(openFileDialog2.FileName); string setData = (String)Clipboard.GetData(DataFormats.Rtf); Clipboard.SetImage(img); rtbType.Paste(); Clipboard.SetData(DataFormats.Rtf, setData); } else { MessageBox.Show("Invalid Image File Selected"); } } 

请问还有更好的方法吗?

我已经为您使用此处发布的利用RTFfunction的解决方案准备了一个function齐全的示例。

正如Hans Passant写道:解决方案非常棘手,并且有一些有效的替代方案可以实现它。

顺便说一句,这是你的代码(重写):

 private bool CheckIfImage(string filename) { var valids = new[] {".jpeg", ".jpg", ".png", ".ico", ".gif", ".bmp", ".emp", ".wmf", ".tiff"}; return valids.Contains(System.IO.Path.GetExtension(filename)); } private void openFileDialog2_FileOk(object sender, CancelEventArgs e) { if (CheckIfImage(openFileDialog2.FileName.ToLower()) == true) embedImage(Image.FromFile(openFileDialog2.FileName)); else MessageBox.Show("Invalid Image File Selected"); } 

这是embedImage方法:

  private void embedImage(Image img) { var rtf = new StringBuilder(); // Append the RTF header rtf.Append(@"{\rtf1\ansi\ansicpg1252\deff0\deflang1033"); // Create the font table using the RichTextBox's current font and append // it to the RTF string rtf.Append(GetFontTable(this.Font)); // Create the image control string and append it to the RTF string rtf.Append(GetImagePrefix(img)); // Create the Windows Metafile and append its bytes in HEX format rtf.Append(getRtfImage(img)); // Close the RTF image control string rtf.Append(@"}"); richTextBox1.SelectedRtf = rtf.ToString(); } 

这里有所有必要的方法:

  private enum EmfToWmfBitsFlags { EmfToWmfBitsFlagsDefault = 0x00000000, EmfToWmfBitsFlagsEmbedEmf = 0x00000001, EmfToWmfBitsFlagsIncludePlaceable = 0x00000002, EmfToWmfBitsFlagsNoXORClip = 0x00000004 }; private struct RtfFontFamilyDef { public const string Unknown = @"\fnil"; public const string Roman = @"\froman"; public const string Swiss = @"\fswiss"; public const string Modern = @"\fmodern"; public const string Script = @"\fscript"; public const string Decor = @"\fdecor"; public const string Technical = @"\ftech"; public const string BiDirect = @"\fbidi"; } [DllImport("gdiplus.dll")] private static extern uint GdipEmfToWmfBits(IntPtr _hEmf, uint _bufferSize, byte[] _buffer, int _mappingMode, EmfToWmfBitsFlags _flags); private string GetFontTable(Font font) { var fontTable = new StringBuilder(); // Append table control string fontTable.Append(@"{\fonttbl{\f0"); fontTable.Append(@"\"); var rtfFontFamily = new HybridDictionary(); rtfFontFamily.Add(FontFamily.GenericMonospace.Name, RtfFontFamilyDef.Modern); rtfFontFamily.Add(FontFamily.GenericSansSerif, RtfFontFamilyDef.Swiss); rtfFontFamily.Add(FontFamily.GenericSerif, RtfFontFamilyDef.Roman); rtfFontFamily.Add("UNKNOWN", RtfFontFamilyDef.Unknown); // If the font's family corresponds to an RTF family, append the // RTF family name, else, append the RTF for unknown font family. fontTable.Append(rtfFontFamily.Contains(font.FontFamily.Name) ? rtfFontFamily[font.FontFamily.Name] : rtfFontFamily["UNKNOWN"]); // \fcharset specifies the character set of a font in the font table. // 0 is for ANSI. fontTable.Append(@"\fcharset0 "); // Append the name of the font fontTable.Append(font.Name); // Close control string fontTable.Append(@";}}"); return fontTable.ToString(); } private string GetImagePrefix(Image _image) { float xDpi, yDpi; var rtf = new StringBuilder(); using (Graphics graphics = CreateGraphics()) { xDpi = graphics.DpiX; yDpi = graphics.DpiY; } // Calculate the current width of the image in (0.01)mm var picw = (int)Math.Round((_image.Width / xDpi) * 2540); // Calculate the current height of the image in (0.01)mm var pich = (int)Math.Round((_image.Height / yDpi) * 2540); // Calculate the target width of the image in twips var picwgoal = (int)Math.Round((_image.Width / xDpi) * 1440); // Calculate the target height of the image in twips var pichgoal = (int)Math.Round((_image.Height / yDpi) * 1440); // Append values to RTF string rtf.Append(@"{\pict\wmetafile8"); rtf.Append(@"\picw"); rtf.Append(picw); rtf.Append(@"\pich"); rtf.Append(pich); rtf.Append(@"\picwgoal"); rtf.Append(picwgoal); rtf.Append(@"\pichgoal"); rtf.Append(pichgoal); rtf.Append(" "); return rtf.ToString(); } private string getRtfImage(Image image) { // Used to store the enhanced metafile MemoryStream stream = null; // Used to create the metafile and draw the image Graphics graphics = null; // The enhanced metafile Metafile metaFile = null; try { var rtf = new StringBuilder(); stream = new MemoryStream(); // Get a graphics context from the RichTextBox using (graphics = CreateGraphics()) { // Get the device context from the graphics context IntPtr hdc = graphics.GetHdc(); // Create a new Enhanced Metafile from the device context metaFile = new Metafile(stream, hdc); // Release the device context graphics.ReleaseHdc(hdc); } // Get a graphics context from the Enhanced Metafile using (graphics = Graphics.FromImage(metaFile)) { // Draw the image on the Enhanced Metafile graphics.DrawImage(image, new Rectangle(0, 0, image.Width, image.Height)); } // Get the handle of the Enhanced Metafile IntPtr hEmf = metaFile.GetHenhmetafile(); // A call to EmfToWmfBits with a null buffer return the size of the // buffer need to store the WMF bits. Use this to get the buffer // size. uint bufferSize = GdipEmfToWmfBits(hEmf, 0, null, 8, EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault); // Create an array to hold the bits var buffer = new byte[bufferSize]; // A call to EmfToWmfBits with a valid buffer copies the bits into the // buffer an returns the number of bits in the WMF. uint _convertedSize = GdipEmfToWmfBits(hEmf, bufferSize, buffer, 8, EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault); // Append the bits to the RTF string foreach (byte t in buffer) { rtf.Append(String.Format("{0:X2}", t)); } return rtf.ToString(); } finally { if (graphics != null) graphics.Dispose(); if (metaFile != null) metaFile.Dispose(); if (stream != null) stream.Close(); } } 

我建议你将它包装到你自己的UserControl

RichTextBox对OLE(对象链接和嵌入)的支持是一个历史性的事故。 OLE是一种死技术,多年来一直被大量弃用。 它的死亡肯定是.NET完全不支持它。 从本机RichEdit控件中删除OLE支持本来是明智的,但它会破坏太多古老的应用程序。 .NET RichTextBox类本身只是本机组件的一个小包装器,不会添加或减少该组件的function。

因此,没有任何简单的方法可以在.NET中使用OLE api。 通过剪贴板复制/粘贴仍然有效的事实只是一个意外,.NET不参与该操作,因此无法阻止它。

所以是的,它仍然可以通过剪贴板工作,是使用该function的唯一正确方法。 当然有更好的替代方案,比如WebBrowser或Word interop可以提供更多的灵活性。 PDF包装很受欢迎。 WPF很好地支持复合文档。 等等。

您可以尝试使用WPF RichTextBox并将其托管在WinForms窗口中。 您将能够非常轻松地使用WPF在光标位置插入图像。