Reputation: 195
I have a display that customizes text and as the user customizes it, I want the text to display. One of the customizations available is an "x-out" which should draw a large "X" over all 5 characters of the text. So when the checkbox "X-Out" is checked, it should update the text from this:
To this:
The box itself is a RichTextBox contained within a Panel. I have tried using the Paint event in the panel, but it draws it underneath the RichTextBox (that's the little red lines on the corners). I have also tried using a custom RichTextBox control like at this website. This code does work, but only if I do not set text and color in the RichTextBox. If I set text and color and then check the checkbox, the WndProc method is not called. How do I trigger the WndProc method with Message.msg 15? Here is the code:
Form
public partial class ButtonDataForm : Form
{
CustomRichTextBox button1;
public ButtonDataForm()
{
InitializeComponent()
}
void OnFormLoad(object sender, EventArgs e)
{
cstmRichTextBox = new CustomRichTextBox(richTextBox1);
}
void OnXOutChecked()
{
cstmRichTextBox.IsChecked = xoutCheckbox.Checked;
cstmRichTextBox.ParentTex.Refresh(); // This does not trigger the WndProc message on cstmRichTextBox
}
}
CustomRichTextBox
public class CustomRichTextBox : NativeWindow
{
public RichTextBox ParentTextBox { get; private set; }
Graphics textBoxGraphics;
public bool IsChecked { get; set; }
public CustomRichTextBox(RichTextBox tb)
{
ParentTextBox = tb;
textBoxGraphics = Graphics.FromHwnd(tb.Handle);
AssignHandle(ParentTextBox.Handle);
}
protected override void WndProc(ref Message m}
{
switch(m.Msg)
{
case 15:
parentTextBox.Invalidate();
base.WndProc(ref m);
DrawXOut();
break;
default:
base.WndProc(ref m);
break;
}
}
void DrawXOut()
{
if (IsChecked)
{
Pen xpen = new Pen(ParentTextBox.ForeColor, 3);
Point topLeft = ParentTextBox.Location;
int x1 = topLeft.X + ParentTextBox.Width;
int y1 = topLeft.Y + ParentTextBox.Height;
Point topRight = new Point(x1, topLeft.Y);
Point bottomLeft = new Point(topLeft.X, y1);
Point bottomRight = new Point(x1, y1);
textBoxGraphics.DrawLine(xpen, topLeft, bottomRight);
textBoxGraphics.DrawLine(xpen, bottomLeft, topRight);
}
}
}
EDIT:
I tried placing a transparent panel on the bottom panel and drawing inside it when the Paint event fired. The event fires, but nothing showed up in the panel. Am I calculating the location incorrectly?
void OnXOutChecked()
{
panel1.Refresh();
}
void OnPanel1Paint(object sender, PaintEventArgs e)
{
Pen xpen = new Pen(Color.Red, 3);
Point topLeft = panel1.Location;
int x1 = topLeft.X + panel1.Width;
int y1 = topLeft.Y + panel1.Height;
Point topRight = new Point(x1, topLeft.Y);
Point bottomLeft = new Point(topLeft.X, y1);
Point bottomRight = new Point(x1, y1);
e.Graphics.DrawLine(xpen, topLeft, bottomRight);
e.Graphics.DrawLine(xpen, bottomLeft, topRight);
}
Upvotes: 0
Views: 148
Reputation: 18013
I just modified your CustomRichTextBox
a bit:
public class CustomRichTextBox : RichTextBox
{
private bool xOut;
public bool XOut
{
get => xOut;
set
{
xOut = value;
Invalidate();
}
}
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case 15:
base.WndProc(ref m);
if (xOut)
DrawXOut();
break;
default:
base.WndProc(ref m);
break;
}
}
private void DrawXOut()
{
using var g = Graphics.FromHwnd(Handle);
g.DrawLine(Pens.Red, 0, 0, Width, Height);
g.DrawLine(Pens.Red, 0, Height, Width, 0);
}
protected override void OnHScroll(EventArgs e)
{
base.OnHScroll(e);
Invalidate();
}
protected override void OnVScroll(EventArgs e)
{
base.OnVScroll(e);
Invalidate();
}
}
Upvotes: 2
Reputation: 94
To be honest, I don't think this is something you want to be doing. You are abusing the richtextbox for something it wasn't intended to. I don't know your true intentions, but maybe a strike-through might be a valid solution?
My experiences tell me it's better to use the components as-is and don't change them too much.
If you really want to, you could do something like this: (Based on Nicks answer.)
public class MyTextbox : RichTextBox
{
PictureBox pictureBox = new PictureBox();
public MyTextbox()
{
this.Controls.Add(pictureBox);
pictureBox.Dock = DockStyle.Fill;
pictureBox.BackColor = Color.Transparent;
pictureBox.Paint += PictureBox_Paint;
pictureBox.BringToFront();
}
private void PictureBox_Paint(object? sender, PaintEventArgs e)
{
var pen = new Pen(this.ForeColor);
e.Graphics.DrawLine(pen, 0, 0, this.Width, this.Height);
e.Graphics.DrawLine(pen, 0, this.Height, this.Width, 0);
}
}
Upvotes: 0
Reputation: 5042
This is a very unreliable approach, drawing on top of the control and expecting it to work in all possible scenarios (and there can be many!).
You can just place a transparent picture box on top of the text box with a transparent bitmap that has two crossed red lines.
Upvotes: 0