在面板内部的控件上绘图(C#WinForms)

时间:2008-11-12 02:37:24

标签: c# .net winforms

我知道这个问题被问了好几次,但到目前为止我还没有找到一个好的解决方案。

我有一个有其他控制权的小组。
我想在它上面和在面板中的所有控件上绘制一条线

我遇到了3种类型的解决方案(不是按照我想要的方式工作):

  1. 获取桌面DC并在屏幕上绘图。
    如果它们与表格重叠,这将吸引其他应用程序。

  2. 覆盖面板的“CreateParams”:

  3. =

    protected override CreateParams CreateParams {  
      get {  
        CreateParams cp;  
        cp = base.CreateParams;  
        cp.Style &= ~0x04000000; //WS_CLIPSIBLINGS
        cp.Style &= ~0x02000000; //WS_CLIPCHILDREN
        return cp;  
      }  
    }           
    

    //注意我也尝试过禁用WS_CLIPSIBLINGS

    然后绘制OnPaint()行。 但是......由于面板的OnPaint在其中的控件的OnPaint之前被调用, 内部控件的绘制只是在线上绘制。
    我见过有人建议使用消息过滤器来收听WM_PAINT消息,并使用计时器,但我不认为这个解决方案要么是“良好做法”,要么是有效的。
    你会怎么做 ?确定内部控件在X ms后完成绘制,并将计时器设置为X ms?


    此屏幕截图显示WS_CLIPSIBLINGS和WS_CLIPCHILDREN关闭的面板。
    蓝线在Panel的OnPaint上绘制,只是被文本框和标签涂上 红色线条仅涂在上面,因为它没有从面板的OnPaint上绘制(它实际上是由于点击了按钮而绘制的)
    alt text


    第3步:创建透明图层并在该图层的顶部绘图 我用:

    创建了一个透明控件
    protected override CreateParams CreateParams {  
      get {  
        CreateParams cp = base.CreateParams;  
        cp.ExStyle |= 0x00000020; //WS_EX_TRANSPARENT  
        return cp;  
      }  
    }
    

    问题仍然存在,将透明控件置于面板及其所有控件之上 我尝试使用“BringToFront()”将它带到前面,但它似乎没有帮助。
    我把它放在Line控件的OnPaint()处理程序中 我应该尝试把它放在其他地方吗? - 这也会在面板顶部设置另一个控件时产生问题。 (抓住鼠标点击等..)

    非常感谢任何帮助!

    **编辑: 黑线是我试图做的样本。 (使用窗户油漆来涂漆)

    alt text

10 个答案:

答案 0 :(得分:17)

事实证明这比我想象的容易得多。谢谢你不接受我的任何其他答案。以下是创建 Fline 的两步流程( f 缓动 - 抱歉,已经晚了):

alt text

第1步:将UserControl添加到项目中并将其命名为“Fline”。将以下内容添加到using语句中:

using System.Drawing.Drawing2D;

第2步:将以下内容添加到Fline的Resize事件中:

int wfactor = 4; // half the line width, kinda
// create 6 points for path
Point[] pts = {
    new Point(0, 0), 
    new Point(wfactor, 0), 
    new Point(Width, Height - wfactor),
    new Point(Width, Height) ,
    new Point(Width - wfactor, Height),
    new Point(0, wfactor) };
// magic numbers! 
byte[] types = {
    0, // start point
    1, // line
    1, // line
    1, // line
    1, // line
    1 }; // line 
GraphicsPath path = new GraphicsPath(pts, types);
this.Region = new Region(path);

编译,然后将Fline拖到表单或面板上。重要提示:默认的BackColor与表单相同,因此将Fline的BackColor更改为Red 或显而易见的(在设计器中)。关于这一点的一个奇怪的怪癖是,当你在设计器中拖动它时,它会显示为一个坚实的块,直到你释放它 - 这不是一件大事。

此控件可以出现在任何其他控件的前面或后面。如果将Enabled设置为false,它仍然可见,但不会干扰下面控件上的鼠标事件。

当然,你会想要为你的目的增强这一点,但这显示了基本原则。您可以使用相同的技术来创建您喜欢的任何形状的控件(我对此的初始测试形成了一个三角形)。

更新:这也是一个很好的密集单行。只需将它放在UserControl的Resize事件中:

this.Region=new Region(new System.Drawing.Drawing2D.GraphicsPath(new Point[]{new Point(0,0),new Point(4,0),new Point(Width,Height-4),new Point(Width,Height),new Point(Width-4,Height),new Point(0,4)},new byte[]{0,1,1,1,1,1}));

答案 1 :(得分:10)

如果您希望线条只是一条简单的水平线或垂直线,请在主面板上放置另一个面板(禁用它不会拾取任何鼠标事件),将其高度(或宽度)设置为3或4像素(或任何你想要的),并把它带到前面。如果您需要在运行期间更改线的位置,则只需移动面板并使其可见且不可见。以下是它的外观:

alt text

您甚至可以点击任何您喜欢的地方,这些线条根本不会干扰。这条线完全被绘制在任何类型的控件上(尽管ComboBox或DatePicker的下拉部分仍显示在该行的上方,无论如何都是好的)。蓝线是同样的东西,但发送回来。

答案 2 :(得分:6)

是的,这可以做到。问题是面板和它上面的控件都是独立的窗口(在API意义上),因此所有单独的绘图表面。没有一个绘图表面可以用来获得这种效果(除了顶层屏幕表面,并且它被认为是不礼貌的)。

(咳嗽 - 黑客 - 咳嗽)技巧是在控件下方的面板上绘制线条,并在每个控件本身上绘制它,导致这个(这将持续存在)当你单击按钮并移动鼠标时:)

alt text

创建一个winforms项目(默认情况下应该包含Form1)。在面板上添加一个面板(名为“panel1”)和两个按钮(“button1”和“button2”),如图所示。在表单的构造函数中添加此代码:

panel1.Paint += PaintPanelOrButton;
button1.Paint += PaintPanelOrButton;
button2.Paint += PaintPanelOrButton;

然后将此方法添加到表单的代码中:

private void PaintPanelOrButton(object sender, PaintEventArgs e)
{
    // center the line endpoints on each button
    Point pt1 = new Point(button1.Left + (button1.Width / 2),
            button1.Top + (button1.Height / 2));
    Point pt2 = new Point(button2.Left + (button2.Width / 2),
            button2.Top + (button2.Height / 2));

    if (sender is Button)
    {
        // offset line so it's drawn over the button where
        // the line on the panel is drawn
        Button btn = (Button)sender;
        pt1.X -= btn.Left;
        pt1.Y -= btn.Top;
        pt2.X -= btn.Left;
        pt2.Y -= btn.Top;
    }

    e.Graphics.DrawLine(new Pen(Color.Red, 4.0F), pt1, pt2);
}

需要在每个控件的Paint事件中绘制类似这样的内容,以便该行保持不变。直接在.NET中的控件上绘制很容易,但是当有人单击按钮或将鼠标移到它上面时,无论你绘制什么都会被擦掉(除非它在Paint事件中永久重绘,如此处所示)。

请注意,要使其工作,任何绘制的控件都必须具有Paint事件。我相信你必须修改这个样本才能达到你的需要。如果您想出一个很好的广义功能,请发布。

更新:此方法不适用于滚动条,文本框,组合框,列表视图,或基本上任何文本框类型的东西作为其中的一部分(并不是因为它只偏移上面示例中的按钮 - 你可以' t根据文本框绘制,至少不是从它的Paint事件中绘制,至少不是如果你是我的话。希望这不会成为问题。

答案 3 :(得分:5)

Windows窗体面板是控件的容器。如果你想在面板中的其他控件之上绘制一些东西,那么你需要的是另一个控件(在z顺序的顶部)。

幸运的是,您可以创建具有非矩形边框的窗体控件。看看这种技巧:http://msdn.microsoft.com/en-us/library/aa289517(VS.71).aspx

要在屏幕上绘制内容,请使用标签控件,然后关闭AutoSize。然后附加到Paint事件并设置Size和Region Properties。

以下是代码示例:

private void label1_Paint(object sender, PaintEventArgs e)
{
    System.Drawing.Drawing2D.GraphicsPath myGraphicsPath = new  System.Drawing.Drawing2D.GraphicsPath();
    myGraphicsPath.AddEllipse(new Rectangle(0, 0, 125, 125));
    myGraphicsPath.AddEllipse(new Rectangle(75, 75, 20, 20));
    myGraphicsPath.AddEllipse(new Rectangle(120, 0, 125, 125));
    myGraphicsPath.AddEllipse(new Rectangle(145, 75, 20, 20));
    //Change the button's background color so that it is easy
    //to see.
    label1.BackColor = Color.ForestGreen;
    label1.Size = new System.Drawing.Size(256, 256);
    label1.Region = new Region(myGraphicsPath);
}

答案 4 :(得分:3)

我能想到的唯一简单的解决方案是为要在其上绘制的每个控件创建Paint事件处理程序。然后协调这些处理程序之间的线条图。这不是最方便的解决方案,但是这将使您能够在控件的 top 上绘制。

假设按钮是面板的子控件:

panel.Paint += new PaintEventHandler(panel_Paint);
button.Paint += new PaintEventHandler(button_Paint);

protected void panel_Paint(object sender, PaintEventArgs e)
{
    //draw the full line which will then be partially obscured by child controls
}

protected void button_Paint(object sender, PaintEventArgs e)
{
    //draw the obscured line portions on the button
}

答案 5 :(得分:3)

制作一个新的LineControl:像这样控制:

然后在InitializeComponent

之后调用BringToFront()
public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
            this.simpleLine1.BringToFront();
        }
    }



using System;
using System.Windows.Forms;
using System.Drawing;
using System.Collections.Generic;

public class SimpleLine : Control
{
    private Control parentHooked;   
    private List<Control> controlsHooked;

    public enum LineType
    {
        Horizontal,
        Vertical,
        ForwardsDiagonal,
        BackwardsDiagonal
    }

    public event EventHandler AppearanceChanged;
    private LineType appearance;
    public virtual LineType Appearance
    {
        get
        {
            return appearance;
        }
        set
        {
            if (appearance != value)
            {
                this.SuspendLayout();
                switch (appearance)
                {
                    case LineType.Horizontal:
                        if (value == LineType.Vertical)
                        {
                            this.Height = this.Width;
                        }

                        break;
                    case LineType.Vertical:
                        if (value == LineType.Horizontal)
                        {
                            this.Width = this.Height;
                        }
                        break;
                }
                this.ResumeLayout(false);

                appearance = value;
                this.PerformLayout();
                this.Invalidate();
            }
        }
    }
    protected virtual void OnAppearanceChanged(EventArgs e)
    {
        if (AppearanceChanged != null) AppearanceChanged(this, e);
    }

    public event EventHandler LineColorChanged;
    private Color lineColor;
    public virtual Color LineColor
    {
        get
        {
            return lineColor;
        }
        set
        {
            if (lineColor != value)
            {
                lineColor = value;
                this.Invalidate();
            }
        }
    }
    protected virtual void OnLineColorChanged(EventArgs e)
    {
        if (LineColorChanged != null) LineColorChanged(this, e);
    }

    public event EventHandler LineWidthChanged;
    private float lineWidth;
    public virtual float LineWidth
    {
        get
        {
            return lineWidth;
        }
        set
        {
            if (lineWidth != value)
            {
                if (0 >= value)
                {
                    lineWidth = 1;
                }
                lineWidth = value;
                this.PerformLayout();
            }
        }
    }
    protected virtual void OnLineWidthChanged(EventArgs e)
    {
        if (LineWidthChanged != null) LineWidthChanged(this, e);
    }

    public SimpleLine()
    {
        base.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.Selectable, false);
        base.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
        base.BackColor = Color.Transparent;

        InitializeComponent();

        appearance = LineType.Vertical;
        LineColor = Color.Black;
        LineWidth = 1;
        controlsHooked = new List<Control>();

        this.ParentChanged += new EventHandler(OnSimpleLineParentChanged);
    }

    private void RemoveControl(Control control)
    {
        if (controlsHooked.Contains(control))
        {
            control.Paint -= new PaintEventHandler(OnControlPaint);
            if (control is TextboxX)
            {
                TextboxX text = (TextboxX)control;
                text.DoingAPaint -= new EventHandler(text_DoingAPaint);
            }
            controlsHooked.Remove(control);
        }
    }

    void text_DoingAPaint(object sender, EventArgs e)
    {
        this.Invalidate();
    }

    private void AddControl(Control control)
    {
        if (!controlsHooked.Contains(control))
        {
            control.Paint += new PaintEventHandler(OnControlPaint);
            if (control is TextboxX)
            {
                TextboxX text = (TextboxX)control;
                text.DoingAPaint += new EventHandler(text_DoingAPaint);
            }
            controlsHooked.Add(control);
        }
    }

    private void OnSimpleLineParentChanged(object sender, EventArgs e)
    {
        UnhookParent();

        if (Parent != null)
        {

            foreach (Control c in Parent.Controls)
            {
                AddControl(c);
            }
            Parent.ControlAdded += new ControlEventHandler(OnParentControlAdded);
            Parent.ControlRemoved += new ControlEventHandler(OnParentControlRemoved);
            parentHooked = this.Parent;
        }
    }

    private void UnhookParent()
    {
            if (parentHooked != null)
            {
                foreach (Control c in parentHooked.Controls)
                {
                    RemoveControl(c);
                }
                parentHooked.ControlAdded -= new ControlEventHandler(OnParentControlAdded);
                parentHooked.ControlRemoved -= new ControlEventHandler(OnParentControlRemoved);
                parentHooked = null;
            }
    }

    private void OnParentControlRemoved(object sender, ControlEventArgs e)
    {
        RemoveControl(e.Control);
    }   

    private void OnControlPaint(object sender, PaintEventArgs e)
    {
        int indexa =Parent.Controls.IndexOf(this) , indexb = Parent.Controls.IndexOf((Control)sender);
        //if above invalidate on paint
        if(indexa < indexb)
        {
            Invalidate();
        }
    }

    private void OnParentControlAdded(object sender, ControlEventArgs e)
    {
        AddControl(e.Control);
    }

    private System.ComponentModel.IContainer components = null;
    private void InitializeComponent()
    {
        components = new System.ComponentModel.Container();
    }
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;
            cp.ExStyle |= 0x20;  // Turn on WS_EX_TRANSPARENT
            return cp;
        }
    }

    protected override void OnLayout(LayoutEventArgs levent)
    {
        switch (this.Appearance)
        {
            case LineType.Horizontal:
                this.Height = (int)LineWidth;
                this.Invalidate();
                break;
            case LineType.Vertical:
                this.Width = (int)LineWidth;
                this.Invalidate();
                break;
        }

        base.OnLayout(levent);
    }

    protected override void OnPaintBackground(PaintEventArgs pevent)
    {
        //disable background paint
    }

    protected override void OnPaint(PaintEventArgs pe)
    {
        switch (Appearance)
        {
            case LineType.Horizontal:
                DrawHorizontalLine(pe);
                break;
            case LineType.Vertical:
                DrawVerticalLine(pe);
                break;
            case LineType.ForwardsDiagonal:
                DrawFDiagonalLine(pe);
                break;
            case LineType.BackwardsDiagonal:
                DrawBDiagonalLine(pe);
                break;
        }
    }

    private void DrawFDiagonalLine(PaintEventArgs pe)
    {
        using (Pen p = new Pen(this.LineColor, this.LineWidth))
        {
            pe.Graphics.DrawLine(p, this.ClientRectangle.X, this.ClientRectangle.Bottom,
                                    this.ClientRectangle.Right, this.ClientRectangle.Y);
        }
    }

    private void DrawBDiagonalLine(PaintEventArgs pe)
    {
        using (Pen p = new Pen(this.LineColor, this.LineWidth))
        {
            pe.Graphics.DrawLine(p, this.ClientRectangle.X, this.ClientRectangle.Y,
                                    this.ClientRectangle.Right, this.ClientRectangle.Bottom);
        }
    }

    private void DrawHorizontalLine(PaintEventArgs pe)
    {
        int  y = this.ClientRectangle.Height / 2;
        using (Pen p = new Pen(this.LineColor, this.LineWidth))
        {
            pe.Graphics.DrawLine(p, this.ClientRectangle.X, y,
                                    this.ClientRectangle.Width, y);
        }
    }

    private void DrawVerticalLine(PaintEventArgs pe)
    {
        int x = this.ClientRectangle.Width / 2;
        using (Pen p = new Pen(this.LineColor, this.LineWidth))
        {
            pe.Graphics.DrawLine(p,x, this.ClientRectangle.Y,
                                   x, this.ClientRectangle.Height);
        }
    }
}

编辑:添加对角线支持

我添加了一些支持,以便在获得焦点时重新绘制。

textboxes和comboboxs不会像你需要自己做的那样工作并挂钩那样的paintish命令:

public class TextboxX : TextBox
{
    public event EventHandler DoingAPaint;
    protected override void WndProc(ref Message m)
    {
        switch ((int)m.Msg)
        {
            case (int)NativeMethods.WindowMessages.WM_PAINT:
            case (int)NativeMethods.WindowMessages.WM_ERASEBKGND:
            case (int)NativeMethods.WindowMessages.WM_NCPAINT:
            case 8465: //not sure what this is WM_COMMAND?
                if(DoingAPaint!=null)DoingAPaint(this,EventArgs.Empty);
                break;
        }           
        base.WndProc(ref m);
    }
}

它没有经过测试,我相信你可以改进它

答案 6 :(得分:2)

编辑找到一种方法摆脱我的递归绘画问题。所以,现在,对我而言,这看起来非常非常接近你想要实现的目标。

这是我能想到的。它使用原始问题中概述的方法#3。代码有点冗长,因为涉及三个类:

  1. 一个名为DecorationCanvas的私有类。这来自Panel,并使用WS_EX_TRANSPARENT提供透明画布来绘制我们的东西
  2. 面板类本身,我称之为DecorativePanel,它派生自Panel
  3. 为面板设计名为DecoratedPanelDesigner的设计器类,以确保在设计时可以保留ZOrder。
  4. 基本方法是:

    • 在DecoratedPanel的构造函数中,创建一个DecorationCanvas实例并将其添加到DecoratedPanel Controls集合中。
    • 覆盖OnControlAdded和OnControlRemoved,自动挂钩/取消挂钩子控件的绘制事件,并确保DecorationCanvas保持在ZOrder之上。
    • 每当包含的控件绘制时,使相应的DecorationCanvas矩形无效。
    • 覆盖OnResize和OnSizeChanged以确保DecorationCanvas与DecorativePanel具有相同的大小。 (我尝试使用Anchor属性完成此操作,但它以某种方式失败了。)
    • 提供一个内部方法,以在DecoratedPanelDesigner中重置DecorationCanvas ZOrder。

    在我的系统上运行正常(VS2010 / .net4 / Windows XP SP3)。这是代码:

    using System;
    using System.ComponentModel;
    using System.ComponentModel.Design;
    using System.Drawing;
    using System.Windows.Forms;
    using System.Windows.Forms.Design;
    
    namespace WindowsFormsApplication3
    {
      [Designer("WindowsFormsApplication3.DecoratedPanelDesigner")]
      public class DecoratedPanel : Panel
      {
        #region decorationcanvas
    
        // this is an internal transparent panel.
        // This is our canvas we'll draw the lines on ...
        private class DecorationCanvas : Panel
        {
          public DecorationCanvas()
          {
            // don't paint the background
            SetStyle(ControlStyles.Opaque, true);
          }
    
          protected override CreateParams CreateParams
          {
            get
            {
              // use transparency
              CreateParams cp = base.CreateParams;
              cp.ExStyle |= 0x00000020; //WS_EX_TRANSPARENT
              return cp;
            }
          }
        }
    
        #endregion
    
        private DecorationCanvas _decorationCanvas;
    
        public DecoratedPanel()
        {
          // add our DecorationCanvas to our panel control
          _decorationCanvas = new DecorationCanvas();
          _decorationCanvas.Name = "myInternalOverlayPanel";
          _decorationCanvas.Size = ClientSize;
          _decorationCanvas.Location = new Point(0, 0);
          // this prevents the DecorationCanvas to catch clicks and the like
          _decorationCanvas.Enabled = false;
          _decorationCanvas.Paint += new PaintEventHandler(decoration_Paint);
          Controls.Add(_decorationCanvas);
        }
    
        protected override void Dispose(bool disposing)
        {
          if (disposing && _decorationCanvas != null)
          {
            // be a good citizen and clean up after yourself
    
            _decorationCanvas.Paint -= new PaintEventHandler(decoration_Paint);
            Controls.Remove(_decorationCanvas);
            _decorationCanvas = null;
          }
    
          base.Dispose(disposing);
        }
    
        void decoration_Paint(object sender, PaintEventArgs e)
        {
          // --- PAINT HERE ---
          e.Graphics.DrawLine(Pens.Red, 0, 0, ClientSize.Width, ClientSize.Height);
        }
    
        protected override void OnControlAdded(ControlEventArgs e)
        {
          base.OnControlAdded(e);
    
          if (IsInDesignMode)
            return;
    
          // Hook paint event and make sure we stay on top
          if (!_decorationCanvas.Equals(e.Control))
            e.Control.Paint += new PaintEventHandler(containedControl_Paint);
    
          ResetDecorationZOrder();
        }
    
        protected override void OnControlRemoved(ControlEventArgs e)
        {
          base.OnControlRemoved(e);
    
          if (IsInDesignMode)
            return;
    
          // Unhook paint event
          if (!_decorationCanvas.Equals(e.Control))
            e.Control.Paint -= new PaintEventHandler(containedControl_Paint);
        }
    
        /// <summary>
        /// If contained controls are updated, invalidate the corresponding DecorationCanvas area
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void containedControl_Paint(object sender, PaintEventArgs e)
        {
          Control c = sender as Control;
    
          if (c == null)
            return;
    
          _decorationCanvas.Invalidate(new Rectangle(c.Left, c.Top, c.Width, c.Height));
        }
    
        protected override void OnResize(EventArgs eventargs)
        {
          base.OnResize(eventargs);
          // make sure we're covering the panel control
          _decorationCanvas.Size = ClientSize;
        }
    
        protected override void OnSizeChanged(EventArgs e)
        {
          base.OnSizeChanged(e);
          // make sure we're covering the panel control
          _decorationCanvas.Size = ClientSize;
        }
    
        /// <summary>
        /// This is marked internal because it gets called from the designer
        /// to make sure our DecorationCanvas stays on top of the ZOrder.
        /// </summary>
        internal void ResetDecorationZOrder()
        {
          if (Controls.GetChildIndex(_decorationCanvas) != 0)
            Controls.SetChildIndex(_decorationCanvas, 0);
        }
    
        private bool IsInDesignMode
        {
          get
          {
            return DesignMode || LicenseManager.UsageMode == LicenseUsageMode.Designtime;
          }
        }
      }
    
      /// <summary>
      /// Unfortunately, the default designer of the standard panel is not a public class
      /// So we'll have to build a new designer out of another one. Since Panel inherits from
      /// ScrollableControl, let's try a ScrollableControlDesigner ...
      /// </summary>
      public class DecoratedPanelDesigner : ScrollableControlDesigner
      {
        private IComponentChangeService _changeService;
    
        public override void Initialize(IComponent component)
        {
          base.Initialize(component);
    
          // Acquire a reference to IComponentChangeService.
          this._changeService = GetService(typeof(IComponentChangeService)) as IComponentChangeService;
    
          // Hook the IComponentChangeService event
          if (this._changeService != null)
            this._changeService.ComponentChanged += new ComponentChangedEventHandler(_changeService_ComponentChanged);
        }
    
        /// <summary>
        /// Try and handle ZOrder changes at design time
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void _changeService_ComponentChanged(object sender, ComponentChangedEventArgs e)
        {
          Control changedControl = e.Component as Control;
          if (changedControl == null)
            return;
    
          DecoratedPanel panelPaint = Control as DecoratedPanel;
    
          if (panelPaint == null)
            return;
    
          // if the ZOrder of controls contained within our panel changes, the
          // changed control is our control
          if (Control.Equals(panelPaint))
            panelPaint.ResetDecorationZOrder();
        }
    
        protected override void Dispose(bool disposing)
        {
          if (disposing)
          {
            if (this._changeService != null)
            {
              // Unhook the event handler
              this._changeService.ComponentChanged -= new ComponentChangedEventHandler(_changeService_ComponentChanged);
              this._changeService = null;
            }
          }
    
          base.Dispose(disposing);
        }
    
        /// <summary>
        /// If the panel has BorderStyle.None, a dashed border needs to be drawn around it
        /// </summary>
        /// <param name="pe"></param>
        protected override void OnPaintAdornments(PaintEventArgs pe)
        {
          base.OnPaintAdornments(pe);
    
          Panel panel = Control as Panel;
          if (panel == null)
            return;
    
          if (panel.BorderStyle == BorderStyle.None)
          {
            using (Pen p = new Pen(SystemColors.ControlDark))
            {
              p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
              pe.Graphics.DrawRectangle(p, 0, 0, Control.Width - 1, Control.Height - 1);
            }
          }
        }
      }
    }
    

    让我知道你的想法...

答案 7 :(得分:1)

我认为最好的方法是继承你想要绘制线条的控件。重写OnPaint方法,从内部调用base.Paint(),之后使用相同的图形实例绘制线条。同时,您还可以使用一个特定参数来绘制线条,以便您可以直接从主窗体控制线条。

答案 8 :(得分:1)

原始代码应为:

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp;
            cp = base.CreateParams;
            cp.Style &= 0x7DFFFFFF; //WS_CLIPCHILDREN
            return cp;
        }
    }

这有效!!

答案 9 :(得分:1)

如何处理解决方案#1(获取桌面DC和Draw在屏幕上):

  1. 获取桌面DC和DC [Graphics.fromHDC(...)]
  2. 的图形对象
  3. 将生成的Graphics对象的Clip属性设置为表单的当前可见区域。 (我还没有研究过如何找到表格的可见区域)
  4. 进行图形渲染。