C# 在背景控件中的其他控件上绘制时,如何使背景控件可编辑

C# 在背景控件中的其他控件上绘制时,如何使背景控件可编辑,c#,windows,winforms,C#,Windows,Winforms,我们必须为RichTextBox提供选择支持,因此我创建了单独的控件,并使用Paint()方法对其进行绘制。问题是,我无法编辑RichTextBox,一旦在其上完成绘图。请找到下面所附的简单示例并分享您的想法 注意:由于将“选择控件停靠样式”设置为“填充”,我们怀疑存在问题,但如果我删除或更改了该选项,则不会绘制该选项 部分类表单1 { /// ///必需的设计器变量。 /// private System.ComponentModel.IContainer components=null

我们必须为
RichTextBox
提供选择支持,因此我创建了单独的控件,并使用
Paint()
方法对其进行绘制。问题是,我无法编辑
RichTextBox
,一旦在其上完成绘图。请找到下面所附的简单示例并分享您的想法

注意:由于将“选择控件停靠样式”设置为“填充”,我们怀疑存在问题,但如果我删除或更改了该选项,则不会绘制该选项

部分类表单1
{
/// 
///必需的设计器变量。
/// 
private System.ComponentModel.IContainer components=null;
/// 
///清理所有正在使用的资源。
/// 
///如果应释放托管资源,则为true;否则为false。
受保护的覆盖无效处置(布尔处置)
{
if(处理和(组件!=null))
{
组件。Dispose();
}
基地。处置(处置);
}
#区域Windows窗体设计器生成的代码
专用graphiccell控制graphiccell;
/// 
///设计器支持所需的方法-不修改
///此方法的内容与代码编辑器一起使用。
/// 
私有void InitializeComponent()
{
#区域图片盒
this.BackColor=Color.Aquamarine;
var selectBtn=新建按钮();
选择BTN.Size=新尺寸(100,30);
选择BTN.Location=新点(10,10);
选择btn.Text=“单击”;
选择BTN。单击+=选择BTN\u单击;
//var picturebox=新的picturebox();
//picturebox.Size=新尺寸(140110);
//picturebox.Location=新点(4,4);
//picturebox.SizeMode=PictureBoxSizeMode.StretchImage;
//picturebox.Image=新位图(@.\..\Data\picture.png);
var richtextbox=新的richtextbox();
richtextbox.Size=新的大小(140110);
richtextbox.Location=新点(4,4);
richtextbox.Text=“文本信息”;
graphiccell=新的GraphicCellControl();
graphiccell.Location=新点(50200);
graphiccell.Size=新的大小(150120);
graphiccell.Controls.Add(richtextbox);
this.Controls.Add(graphiccell);
this.Controls.Add(选择BTN);
#端区
}
void selectBtn\u单击(对象发送者,事件参数e)
{
graphiccell.IsSelected=!graphiccell.IsSelected;
}
#端区
}
公共类GraphicCellControl:控件
{
私人选择控制选择控制;
公共图形控制()
{
selectionControl=新建selectionControl();
}
私人布尔当选;
公选学校
{
获取{return isselected;}
设置
{
isselected=值;
if(isselected&!this.Controls.Contains(selectionControl))
{
this.Controls.Add(selectionControl);
selectionControl.BringToFront();
}
如果(!isselected&&this.Controls.Contains(selectionControl))
this.Controls.Remove(selectionControl);
}
}
}
公共类SelectionControl:Control
{
公共选择控制()
{
设置样式(ControlStyles.AllPaintingInWmPaint|
ControlStyles.UserPaint | ControlStyles.不透明|
ControlStyles.SupportsTransparentBackColor,true);
Dock=DockStyle.Fill;
//锚点=锚点样式。左|锚点样式。顶部;
背景色=颜色。透明;
}
受保护的覆盖无效OnPaint(PaintEventArgs e)
{
基础漆(e);
e、 Graphics.SmoothingMode=SmoothingMode.AntiAlias;
e、 Graphics.DrawRectangle(新笔(Color.Gray,1),4,4,this.Size.Width-10,this.Size.Height-10);
e、 图形。填充椭圆(画笔。白色,0,0,8,8);
e、 图形.填充椭圆(画笔.White,0,(this.Size.Height-10)/2,8,8);
e、 Graphics.FillEllipse(画笔.White,0,this.Size.Height-10,8,8);
e、 图形.FillEllipse(画笔.White,(this.Size.Width-10)/2,0,8,8);
e、 Graphics.FillEllipse(笔刷.White,(this.Size.Width-10)/2,this.Size.Height-10,8,8);
e、 图形.FillEllipse(画笔.White,this.Size.Width-10,0,8,8);
e、 Graphics.FillEllipse(画笔.White,this.Size.Width-10,(this.Size.Height-10)/2,8,8);
e、 Graphics.FillEllipse(画笔.White,this.Size.Width-10,this.Size.Height-10,8,8);
e、 图形学.抽屉式(新钢笔(彩色暗灰色,2),0,0,8,8);
e、 Graphics.Dropellipse(新笔(Color.DarkGray,2),0,(this.Size.Height-10)/2,8,8);
e、 Graphics.Dropellipse(新笔(Color.DarkGray,2),0,this.Size.Height-10,8,8);
e、 Graphics.Dropellipse(新钢笔(Color.DarkGray,2),(this.Size.Width-10)/2,0,8,8);
e、 Graphics.Dropellipse(新笔(Color.DarkGray,2),(this.Size.Width-10)/2,this.Size.Height-10,8,8);
e、 Graphics.Dropellipse(新钢笔(Color.DarkGray,2),this.Size.Width-10,0,8,8);
e、 Graphics.Dropellipse(新笔(Color.DarkGray,2),this.Size.Width-10,(this.Size.Height-10)/2,8,8);
e、 Graphics.Dropellipse(新钢笔(Color.DarkGray,2),this.Size.Width-10,this.Size.Height-10,8,8);
}
}

据我所知,问题的核心是覆盖控件将拦截所有用户交互

这不仅仅适用于鼠标操作。它还包括键盘操作、设置焦点和在任何更改后更新显示

通过重定向所有相关的
WndProc
消息,可以解决所有这些问题,但这将相当复杂

这里有一个更简单的解决方案:不是用选择框覆盖RTB,而是将该框置于RTB下方。我已经创建了一个修改过的类,它工作得相当好,尽管有人可能会调整
partial class Form1
{
    /// <summary>
    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.IContainer components = null;

    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    #region Windows Form Designer generated code

    private GraphicCellControl graphiccell;

    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {

        #region picturebox

        this.BackColor = Color.Aquamarine;

        var selectBtn = new Button();
        selectBtn.Size = new Size(100, 30);
        selectBtn.Location = new Point(10, 10);
        selectBtn.Text = "Click";
        selectBtn.Click += selectBtn_Click;

        //var picturebox = new PictureBox();
        //picturebox.Size = new Size(140, 110);
        //picturebox.Location = new Point(4, 4);
        //picturebox.SizeMode = PictureBoxSizeMode.StretchImage;
        //picturebox.Image = new Bitmap(@"..\..\Data\picture.png");

        var richtextbox = new RichTextBox();
        richtextbox.Size = new Size(140, 110);
        richtextbox.Location = new Point(4, 4);
        richtextbox.Text = "Texting information";

        graphiccell = new GraphicCellControl();
        graphiccell.Location = new Point(50, 200);
        graphiccell.Size = new Size(150, 120);
        graphiccell.Controls.Add(richtextbox);
        this.Controls.Add(graphiccell);
        this.Controls.Add(selectBtn);

        #endregion

    }

    void selectBtn_Click(object sender, EventArgs e)
    {
        graphiccell.IsSelected = !graphiccell.IsSelected;
    }

    #endregion
}

public class GraphicCellControl : Control
{
    private SelectionControl selectionControl;
    public GraphicCellControl()
    {
        selectionControl = new SelectionControl();
    }

    private bool isselected;
    public bool IsSelected
    {
        get { return isselected; }
        set
        {
            isselected = value;
            if (isselected && !this.Controls.Contains(selectionControl))
            {
                this.Controls.Add(selectionControl);
                selectionControl.BringToFront();
            }
            else if (!isselected && this.Controls.Contains(selectionControl))
                this.Controls.Remove(selectionControl);
        }
    }
}

public class SelectionControl : Control
{
    public SelectionControl()
    {
        SetStyle(ControlStyles.AllPaintingInWmPaint |
                 ControlStyles.UserPaint | ControlStyles.Opaque |
                 ControlStyles.SupportsTransparentBackColor, true);
        Dock = DockStyle.Fill;
       // Anchor = AnchorStyles.Left | AnchorStyles.Top;
        BackColor = Color.Transparent;
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
        e.Graphics.DrawRectangle(new Pen(Color.Gray, 1), 4, 4, this.Size.Width - 10, this.Size.Height - 10);

        e.Graphics.FillEllipse(Brushes.White, 0, 0, 8, 8);
        e.Graphics.FillEllipse(Brushes.White, 0, (this.Size.Height - 10) / 2, 8, 8);
        e.Graphics.FillEllipse(Brushes.White, 0, this.Size.Height - 10, 8, 8);
        e.Graphics.FillEllipse(Brushes.White, (this.Size.Width - 10) / 2, 0, 8, 8);
        e.Graphics.FillEllipse(Brushes.White, (this.Size.Width - 10) / 2, this.Size.Height - 10, 8, 8);
        e.Graphics.FillEllipse(Brushes.White, this.Size.Width - 10, 0, 8, 8);
        e.Graphics.FillEllipse(Brushes.White, this.Size.Width - 10, (this.Size.Height - 10) / 2, 8, 8);
        e.Graphics.FillEllipse(Brushes.White, this.Size.Width - 10, this.Size.Height - 10, 8, 8);

        e.Graphics.DrawEllipse(new Pen(Color.DarkGray, 2), 0, 0, 8, 8);
        e.Graphics.DrawEllipse(new Pen(Color.DarkGray, 2), 0, (this.Size.Height - 10) / 2, 8, 8);
        e.Graphics.DrawEllipse(new Pen(Color.DarkGray, 2), 0, this.Size.Height - 10, 8, 8);
        e.Graphics.DrawEllipse(new Pen(Color.DarkGray, 2), (this.Size.Width - 10) / 2, 0, 8, 8);
        e.Graphics.DrawEllipse(new Pen(Color.DarkGray, 2), (this.Size.Width - 10) / 2, this.Size.Height - 10, 8, 8);
        e.Graphics.DrawEllipse(new Pen(Color.DarkGray, 2), this.Size.Width - 10, 0, 8, 8);
        e.Graphics.DrawEllipse(new Pen(Color.DarkGray, 2), this.Size.Width - 10, (this.Size.Height - 10) / 2, 8, 8);
        e.Graphics.DrawEllipse(new Pen(Color.DarkGray, 2), this.Size.Width - 10, this.Size.Height - 10, 8, 8);
    }
}
Point oldLocation = Point.Empty;
Control oldParent = null;
BorderStyle oldBorder = BorderStyle.None;

public void Select(Control ctl, bool selected)
{
    if (selected)
    {
        Parent = ctl.Parent;
        oldLocation = ctl.Location;
        ctl.Location = new Point(8, 8);
        Location = Point.Subtract(oldLocation, new Size(8, 8));
        Size = new Size(ctl.Width + 16, ctl.Height + 16);
        oldParent = ctl.Parent;
        oldBorder = (ctl as RichTextBox).BorderStyle;        // optional
        (ctl as RichTextBox).BorderStyle = BorderStyle.None; // optional
        ctl.Parent = this;
        this.Show();
    }
    else
    {
        ctl.Location = oldLocation;
        ctl.Parent = oldParent;
        (ctl as RichTextBox).BorderStyle = oldBorder;   // optional
        this.Hide();
    }
}
if (Controls.Count > 0)
    using (SolidBrush brush = new SolidBrush(Controls[0].BackColor))
           e.Graphics.FillRectangle(brush, 4, 4, Width - 10, Height - 10);
protected override CreateParams CreateParams
        {
            get
            {
                var cp = base.CreateParams;
                cp.ExStyle |= 0x20;
                return cp;
            }
        }