Using .net RichTextEdit, but filtering data types?
https://stackoverflow.com/questions/932575
Question
The RichTextEdit
control in .NET does 99% of what I need to do for my application, except for a few little things:
- I want to disallow pasting/dragging images into the control
- When text is pasted/dragged into the control, I want to reset its style to the control's default
As far as I can work out, Microsoft hasn't provided any type of "no images" property on this control that you can use, which would be ideal.
My thought was that I could respond to the "textChanged
" event then remove the image and/or reset the text style before it gets rendered to the screen. Of course this would be a total hack. For one thing, the user's drag&drop mouse icon would indicate that images are droppable and they really aren't.
To make a long question short, is there a way to set a filter on what type of data types a RichTextEdit
control can import via Copy&Paste and Drag&Drop?
No correct solution
OTHER TIPS
This is possible; however, you'll have to leave the confines of the .NET RichTextBox interface to do it, as the callback needed lives in the IRichEditOleCallback COM interface.
To give you an idea of what's involved, in ATL C++ (no guarantees that this will work though, and you'll have to adapt it to however you create a Plain Ol' COM Object in whatever language you're working in):
#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);
}
}