3

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

  1. 我想禁止将图像粘贴/拖动到控件中
  2. 将文本粘贴/拖动到控件中时,我想将其样式重置为控件的默认值

据我所知,微软没有在这个控件上提供任何类型的“无图像”属性,你可以使用,这将是理想的。

我的想法是我可以响应“ textChanged”事件,然后在图像呈现到屏幕之前删除图像和/或重置文本样式。当然,这将是一个彻头彻尾的黑客攻击。一方面,用户的拖放鼠标图标表明图像是可拖放的,而实际上不是。

RichTextEdit长话短说,有没有办法对控件可以通过复制粘贴和拖放操作导入的数据类型设置过滤器?

4

1 回答 1

0

这个有可能; 但是,您必须离开 .NET RichTextBox 接口的限制才能执行此操作,因为所需的回调位于IRichEditOleCallback COM 接口中。

为了让您了解所涉及的内容,在 ATL C++ 中(但不能保证这会起作用,并且您必须适应它,但是您可以使用您正在使用的任何语言创建一个普通的 Ol' 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);
  }
}
于 2015-04-17T21:07:59.723 回答