使用.net RichTextEdit,但过滤数据类型?

时间:2009-05-31 18:16:07

标签: .net drag-and-drop richtextbox copy-paste

.NET中的RichTextEdit控件执行我需要为我的应用程序执行的操作的99%,除了一些小事情:

  1. 我想禁止将图像粘贴/拖动到控件中
  2. 当文本被粘贴/拖动到控件中时,我想将其样式重置为控件的默认值
  3. 据我所知,微软没有在你可以使用的控件上提供任何类型的“无图像”属性,这是理想的。

    我的想法是我可以回复“textChanged”事件,然后删除图像和/或重置文本样式,然后再将其渲染到屏幕上。当然这将是一个完全黑客。一方面,用户的拖放鼠标图标表示图像可以放置,而实际上并非如此。

    要简短地提一个问题,有没有办法设置一个过滤器,RichTextEdit控件可以通过复制和粘贴,拖放和拖放来导入哪种类型的数据类型?

1 个答案:

答案 0 :(得分:0)

这是可能的;但是,您必须离开.NET RichTextBox接口的范围来执行此操作,因为回调需要存在于IRichEditOleCallback COM接口中。

为了让您了解ATL C ++中涉及的内容(不保证这会起作用,但是您必须对其进行调整,但是您需要创建一个简单的OL&#COM; COM对象无论你在哪种语言中工作:

#include <windows.h>
#include <Richole.h>
#include <atlbase.h>
#include <atlcom.h>
#include <atlcomcli.h>
#include <string>

struct RattyRichEditOleCallbackImpl: public CComObjectRoot, public IRichEditOleCallback
{
  HWND* hRichEdit;
  RattyRichEditOleCallbackImpl(): hRichEdit(NULL) {}
  HRESULT SetRichEditCtl(HWND *hCtl)
  {
    hRichEdit = hCtl;
    return S_OK;
  }
  HRESULT QueryAcceptData(LPDATAOBJECT lpdataobj, CLIPFORMAT* lpcfFormat, DWORD reco, BOOL fReally, HGLOBAL hMetaPict)
  {
    // This list of image formats covers all the standard ones listed in
    // the [MSDN docs](https://msdn.microsoft.com/en-us/library/ff729168.aspx)
    // if there are more CF_blahs that correspond to images, add them here
    if (*lpcfFormat == CF_DIB || *lpcfFormat == CF_DIBV5
      || *lpcfFormat == CF_BITMAP || *lpcfFormat == CF_TIFF
      || *lpcfFormat == CF_ENHMETAFILE || *lpcfFormat == CF_METAFILEPICT
      || *lpcfFormat == CF_PALETTE || *lpcfFormat == CF_DSPBITMAP
      || *lpcfFormat == CF_DSPMETAFILEPICT || *lpcfFormat == CF_DSPENHMETAFILE
      || *lpcfFormat >= CF_GDIOBJECTFIRST || *lpcfFormat <= CF_GDIOBJECTLAST)
    {
      // Bail out with an error HRESULT because we don't want some stinkin' image in our rich edit control!
      return E_NOTIMPL;
    }
    // Try to convert anything else to plain ol' Unicode text
    else
    {
      *lpcfFormat = CF_UNICODETEXT;
      // Are we being asked to paste this?
      if (fReally)
      {
        // Insert the data as text with the default style
        FORMATETC fmt = {*lpcfFormat, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
        STGMEDIUM stg;
        HRESULT res = E_UNEXPECTED;
        if (hRichEdit && (res = lpdataobj->GetData(fmt, stg)) == S_OK)
        {
          // Lock the HGLOBAL as it might not be ordinary heap mem
          WCHAR* pText = GlobalLock(stg.hGlobal);
          if (!pText)
          {
            ReleaseStgMedium(stg);
            return res;
          }
          std::wstring text(pText);

          // Do a bit of selection trickiness to ensure we have the default text style -- we can't just EM_PASTESPECIAL due to recursion issues
          DWORD cursorPos, selPos;
          SendMessageW(hRichEdit, EM_GETSEL, &cursorPos, &selPos);
          if (cursorPos == selPos)
          {
            // No selection, so select the character after the cursor, fetch it, and append it to the text
            SendMessageW(hRichEdit, EM_SETSEL, cursorPos, cursorPos + 1);
            WCHAR buffer[2];
            TEXTRANGEW tr = {{cursorPos, cursorPos + 1}, buffer};
            SendMessageW(hRichEdit, EM_GETTEXTRANGE, 0, &tr);
            text.append(buffer[0]);
          }
          // Now that we have ourselves a selection -- we can unformat it then replace it
          CHARFORMAT2 cf;
          cf.cbSize = sizeof(CHARFORMAT2);
          SendMessageW(hRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, &cf);
          SendMessageW(hRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, &cf);
          SendMessageW(hRichEdit, EM_REPLACESEL, TRUE, text.c_str());

          GlobalUnlock(stg.hGlobal);
          ReleaseStgMedium(stg);
          // We did the work ourselves, so don't ask the control to do anything for us, unless something broke that is
          res = S_FALSE;
        }
        return res;
      }
      else
      {
        // Have the control check for us to see if it can coerce what's on the clipboard to CF_UNICODETEXT
        return S_OK;
      }
    }
  }
};

typedef CComObject<RattyRichEditOleCallbackImpl> RattyRichEditOleCallback;

inline void AttachRattyCallbackToRichEdit(HWND *hRichEdit)
{
  RattyRichEditOleCallback* pCb;
  if (RattyRichEditOleCallback::CreateInstance(&pCb) == S_OK)
  {
    CComPtr cb(pCb);
    cb->SetRichEditCtl(hRichEdit);
    SendMessage(hRichEdit, EM_SETOLECALLBACK, 0, cb);
  }
}