2013-08-02 12 views
5

Ich weiß, dass es verschiedene Fragen wie diese gibt, aber ich frage, weil ich nicht alle Antworten verstehen konnte. Ich habe RichTextBox und ich möchte, dass der Benutzer ein Bild an der aktuellen Cursorposition einfügen kann.Bild an Cursorposition im Rich Textfeld einfügen

Ich habe versucht, die Clipboard verwenden, um das Bild und Einfügen dann in die Rich Textbox. Das funktioniert, aber mir wurde gesagt, dass es eine schlechte Übung ist, wenn Daten in einem Cliboard geändert werden, ohne den Benutzer zu benachrichtigen.

Dies ist, was ich habe versucht

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"); 
     } 
    } 

Pls ist es ein besserer Weg, dies zu tun?

+0

möglich duplicate: http://stackoverflow.com/questions/542850/how-can-i-insert-an-image-into-a-richtextbox –

+0

@DmitryBychenko Dieser Link ist für 'vb.net' ... –

Antwort

5

Ich habe ein voll funktionsfähiges Beispiel für Sie mit der Lösung here unter Ausnutzung der RTF-Leistung vorbereitet.

Wie Hans Passant schrieb: Die Lösung ist ziemlich schwierig und es gibt einige gültige Alternativen, um es zu erreichen. BTW

, das ist der Code (rewrited):

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"); 
} 

Dies ist die embedImage Methode:

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(); 
    } 

Hier gibt es alle notwendigen Methoden:

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(); 
     } 
    } 

I schlage vor, dass Sie dies in Ihre eigenen UserControl wickeln.

+0

Ziemlich komplex Danke tho. Es funktionierte.Ich werde bald verstehen –

+0

Das war fast meine Antwort, aber die Bilder scheinen Qualität an den Rändern zu verlieren, wenn ich sie auf diese Weise hinzufüge. Nicht sicher, ob Sie sagen könnten, warum das passieren könnte. Beispiel http://imgur.com/6TCzKkv – Natzely

2

Die Unterstützung von RichTextBox für OLE (Object Linking and Embedding) ist ein historischer Unfall. OLE ist eine tote Technologie und wird seit vielen Jahren stark veraltet. Es war definitiv tot. Es war .NET, das es nicht vollständig unterstützte. Das Entfernen der OLE-Unterstützung aus dem nativen RichEdit-Steuerelement wäre sinnvoll gewesen, hätte jedoch zu viele alte Apps zerstört. Die .NET RichTextBox-Klasse selbst ist nur ein kleiner Wrapper für die native Komponente und fügt keine Features von dieser Komponente hinzu oder subtrahiert sie.

Dementsprechend gibt es keine einfache Möglichkeit, die OLE-API in .NET zu verwenden. Die Tatsache, dass Kopieren/Einfügen durch die Zwischenablage immer noch funktioniert, ist nur ein Zufall. .NET ist nicht an dieser Operation beteiligt, so dass es sonst machtlos ist, es zu stoppen.

Also ja, es funktioniert immer noch über die Zwischenablage und ist der einzige vernünftige Weg, um die Funktion zu verwenden. Es gibt sicherlich bessere Alternativen, etwas wie WebBrowser oder Word-Interop gibt Ihnen viel mehr Flexibilität. PDF-Wrapper sind beliebt. WPF unterstützt Verbunddokumente gut. Und so weiter.

+0

Also im Grunde sollte er seinen eigenen TextBox (oder RichTextBox) Wrapper erstellen. – KappaG3

+0

Ok .. danke für die Info –

+1

@ Precious1tj in der Tat, was Sie wollen, kann gelöst werden, aber es ist ziemlich kompliziert, hier ist der Link für Sie, mehr zu erforschen http://www.codeproject.com/Articles/4544/Insert- Klartext-und-Bilder-in-RichTextBox-at-R –

0

Sie können versuchen, die WPF RichTextBox zu verwenden und sie in Ihrem WinForms-Fenster zu hosten. Sie können ein Bild an der Cursorposition mit WPF sehr einfach einfügen.

Verwandte Themen