Disable image paste in RichTextBox in Winforms - c#

We have an UserControls which herits from the RichTextBox. We would like to forbid the user to enter any image(with copy paste) in this user control.
I found several places where speaking of this:
This doesn't work with Winforms
This will not work when doing a right-click -> Paste
Currently I've this solution:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == (Keys)Shortcut.CtrlV || keyData == (Keys)Shortcut.ShiftIns)
{
if (Clipboard.ContainsImage())
{
return false;
}
}
return base.ProcessCmdKey(ref msg, keyData);
}
Which works for copy paste with CTRL+C-CTRL+V, but not with the contextual menu.
EDIT
I tried the given proposition:
public class CustomRichBox : RichTextBox
{
private const int WM_PASTE = 0x0302;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_PASTE )
{
if (Clipboard.ContainsImage())
{
return;
}
}
base.WndProc(ref m);
}
}
But when I do the CTRL+V, I don't receive this message

Sadly there is no global Paste-Event, on which you can subscribe like in WPF. But maybe this is a solution for you:
hook on default "Paste" event of WinForms TextBox control
This worked for me.

You could try to override the WndProc method to filter the WM_PASTE message:
protected override void WndProc(ref Message m)
{
// Trap WM_PASTE with image:
if (m.Msg == 0x302 && Clipboard.ContainsImage())
{
return;
}
base.WndProc(ref m);
}
EDIT
Unfortunatly, this approach won't work because the RichTextBox control doesn't send the WM_PAINT message to itself. See also: Detecting if paste event occurred inside a rich text box.

As a quick workaround, I tried to copy only the Text (using RichTextBox.Text) in another RichTextBox, then copy the Rtf string in the first RichTextBox, all of that in the "TextChanged" event. However there are a lot of downsides for this workaround. First: is not optimized, second and most important: you lose all text formatting, which might be the reason you chose RichTextBox in the first place, and third: you can still see the image for one or two frames in the RTB until it disappears, and if the user is writing a large text it isn't working very smoothly (but fortunately you can fix this if you copy-paste the code in paste events). However, it turned out to be very useful in my app, which is the reason I posted this answer here.
So here is all the code (assuming you have a RichTextBox named RTB and an auxiliary RichTextBox named auxRTB):
private void RTB_TextChanged(object sender, EventArgs e)
{
int selStart = RTB.SelectionStart;
int selLenght = RTB.SelectionLength;
auxRTB.Text = RTB.Text;
RTB.TextChanged -= RTB_TextChanged;
RTB.Rtf = string.Copy(auxRTB.Rtf);
RTB.TextChanged += RTB_TextChanged;
try
{
RTB.SelectionStart = selStart;
RTB.SelectionLength = selLenght;
}
catch (Exception) { }
}
Now, if you are interested, here I'm going to explain how is that useful in my app. So I built a command system, and the only reason I chose RichTextBox insted of normal TextBox is because I wanted to give different colors to each type of thing from a command. The commands are not meant to be long so I don't have any optimiziation problems, and I don't care about losing formatting, since I always change the colors automatically.
Edit: by the way, here are some links to the same problem on other sites, which might actually help you:
Link 1: https://social.msdn.microsoft.com/Forums/en-US/0f762cb8-7383-4937-8ee8-f8df5d3a9852/disable-image-paste-in-richtextbox?forum=wpf
Link 2: C# / WPF: Richtextbox: Find all Images
Link 3: https://thomaslevesque.com/2015/09/05/wpf-prevent-the-user-from-pasting-an-image-in-a-richtextbox/

Related

C# - Fix linklabel hand-cursor

I have two link labels in my windows forms program which links to my website.
I got rid of the underlines and the ugly blue colour and tried to fix them up a little bit.
But the biggest problem still remains and It's just so disturbing for me, I don't know why.
The hand cursor when you hover over them is that old Windows 98 hand/link cursor.
Is there any way to change it to the system cursor?
I've checked some other links about this problem, but I couldn't get it to work so I decided to ask here.
Here's my code to get rid of the underline btw:
linkLabel1.LinkBehavior = System.Windows.Forms.LinkBehavior.NeverUnderline;
Unfortunately the LinkLabel class is hard-coded to use Cursors.Hand as the hover cursor.
However, you can work around it by adding a class like this to your project:
public class MyLinkLabel : LinkLabel
{
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseEnter(e);
OverrideCursor = Cursors.Cross;
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
OverrideCursor = null;
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
OverrideCursor = Cursors.Cross;
}
}
and using that instead of LinkLabel on your form. (This sets the cursor to a cross for testing purposes, but you can change it to whatever you want.)
I should say that the real LinkLabel code has much more complex logic to do with changing the cursor according to whether or not the link is enabled, but you might not care about that.
Set the Cursor property to Arrow in the properties pane of the LinkLabel in Visual Studio
Update
I prefer Hamido-san's answer here. His solution works properly when the LinkLabel is set to AutoSize = false and works with a LinkArea.
Old solution:
public class LnkLabel : LinkLabel
{
const int WM_SETCURSOR = 32,
IDC_HAND = 32649;
[DllImport("user32.dll")]
public static extern int LoadCursor(int hInstance, int lpCursorName);
[DllImport("user32.dll")]
public static extern int SetCursor(int hCursor);
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_SETCURSOR)
{
int cursor = LoadCursor(0, IDC_HAND);
SetCursor(cursor);
m.Result = IntPtr.Zero; // Handled
return;
}
base.WndProc(ref m);
}
}

C# Detecting a Click in WndProc and calling a function after click happened

I am trying to detect a click and preform calling a function only after the click actually happened.
[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
protected override void WndProc(ref Message m) {
//Detect a Click
if (m.Msg == 0x210 && m.WParam.ToInt32() == 513){
lastClick = DateTime.Now;
clickedHappened();
Debug.Print("Click Detected!");
}
base.WndProc(ref m);
}
private void clickedHappened(){
MessageBox.Show("Click Already Happened");
}
I think that WndProc happens way before the actual click takes place.
I was wondering if there was a way to solve this with out using a timer? or sleep(400);
The only solution I can come up with is using a timer, but I want to get rid of some of my existing timers. It seems that the click actually happens 200 - 350 ms after it was detected in WndProc.
WndProc is short for Window Procedure, its the procedure that handles everything for the window, drawing, mouse capture, keyboard capture, resizing...
There are also several ways you can capture the mouse for varying results
[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
protected override void WndProc(ref Message m)
{
switch(m.Msg)
{
case 0x201:
//left button down
break;
case 0x202:
clickedHappened(); //left button up, ie. a click
break;
case 0x203:
//left button double click
break;
}
base.WndProc(ref m);
}
The thing is, windows forms in C# already handles all of these for you and from the WndProc, fires events there is no real need to handle WndProc yourself for this type of thing.
For a full list of mouse notification messages, see MSDN: Mouse Input Notifications and for a list of all wndproc messages, see MSDN System Defined Messages
Probably, you can handle WM_LBUTTONUP message that occured after click.
You can do it like this:
const int WM_LBUTTONUP = 0x202;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_LBUTTONUP)
{
clickedHappened();
}
base.WndProc(ref m);
}

C#: How to deselect and defocus textbox?

I'm writing a simple calc-based app in C# WinForms. My issue is that I have textbox to display results which cannot be clicked/focused because buttons are binded to keyboard. Textbox has to have ContextMenuStrip, but only this action should be handled within textbox. Also this app requirement is that it cannot have any focusable controls. Something like Windows' Calc result box. Any advice?
Create custom text box:
public class TextBoxWithoutFocus : TextBox
{
private const int WM_SETFOCUS = 0x7;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_SETFOCUS)
return;
base.WndProc(ref m);
}
}
That's all. Text box will never receive a focus (actually it will receive focus, but it will not change its look). Also consider suppress WM_CHAR message (0x102) if you want to disable user input.
UPDATE (trick you can use with buttons):
public class ButtonWithoutFocus : Button
{
public ButtonWithoutFocus()
{
SetStyle(ControlStyles.Selectable, false);
}
}
Make it a label, not a textBox. You can set dimensions and background so it looks like a textBox, and it has ContextMenuStrip.
Try both TextBox.Enabled = False; and TextBox1.ReadOnly = True;
Does TextBox.Enabled = false meet your needs?
Try this
TextBox1.ReadOnly = True;
to defocus simply do this:
TextBox.Select(0, 0);

How to override PASTE operations in ScintillaNet?

I am using the Scintilla control from ScintillaNet, and I need to have some control over the paste operations (in order to be able to check some things and/or update the text to be pasted).
I've tried to create a subclass of the Scintilla control and override the WndProc method.
Then, I intercept the WM_PASTE message (0x0302), no luck. I never catch it.
Here is the code I use:
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_PASTE)
{
MessageBox.Show("Paste");
}
base.WndProc(ref m);
}
Any idea?
You could remove ScintillaNET's built in CTRL+V handler with:
scintilla.Commands.RemoveBinding(Keys.V, Keys.Control, ScintillaNet.BindableCommand.Paste);
And add your own CTRL+V handler (menu item?) to do a:
ScintillaNet.Selection.Text = your_processed_clipboard_data;
That would insert at the current cursor position, or replace the current selection.

How to handle Form caption right click

I'd like a context menu on the caption bar right click
any tips/samples pref in c# ?
UPDATE - for various reasons, right click on the form won't work because the form is not empty and the form is composited dynamically so....
You can do this by trapping the WM_NCRBUTTONDOWN notification that Windows sends when the user right-clicks the title bar. The control class does not have an event for it, you'll need to override WndProc(). Here's an example form, you'll need to add a ContextMenuStrip:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
protected void OnTitlebarClick(Point pos) {
contextMenuStrip1.Show(pos);
}
protected override void WndProc(ref Message m) {
const int WM_NCRBUTTONDOWN = 0xa4;
if (m.Msg == WM_NCRBUTTONDOWN) {
var pos = new Point(m.LParam.ToInt32());
OnTitlebarClick(pos);
return;
}
base.WndProc(ref m);
}
}
MSDN explains how to handle right-clicks on Windows Forms controls. Controls, including Forms, inherit the MouseClick event.
MouseEventArgs will tell you what button was clicked through the Button property. Have a look at the MouseButtons Enumeration.
if you handle the form mouse-click, you can then use the following code:
private void Dialog_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
this.Text = "new caption text";
}
}
But you'll have to make sure that you generate this event for the top-level control on a form. For instance if you have a group box on the form, it will receive the mouse-click events rather than the form itself, for the areas of the form that are under the group box.
There is already a menu managed by Windows when you right-click the titlebar.
Do you want to replace it completely?
If you want to add to it you will have to use the Win32 API and interop and you will have to subclass the form.
See the AppendMenu() function.
Basically you need to use p-invoke to do this. There is a really great example at Here
You can see from the example you will need to manually mimic the event handlers, but this is pretty straight forward.
You can override WndProc of the form and capture the WM_NCRBUTTONDOWN message:
protected override void WndProc(ref Message m)
{
const int WM_NCRBUTTONDOWN = 0xA4;
if (m.Msg == WM_NCRBUTTONDOWN)
{
MessageBox.Show("Caption right clicked!");
}
else
{
base.WndProc(ref m);
}
}
This code will suppress the window's context menu, however. You may not wish this. The WM_NCRBUTTONDOWN message will also be sent if you right click the window borders as well. You may not desire this either.

Categories