在C#Winforms中有一种方法可以在所有控件周围放置虚线边框,并在运行时选择特定控件时显示夹点吗?

Gan*_*zy' 8 c# user-controls border visual-studio-2010 winforms

我在一个类似于Visual Studio的IDE上工作,为我们的本地客户开发自定义Winform代码.在我们的代码中,我们覆盖了用户控件以使我们的任务更容易,但我们的大多数控件都是从基本的C#Winform控件派生的.

我目前需要帮助实现所有控件周围的虚线边框,以及Visual Studio提供的抓点类型.

未选择的控件

在此输入图像描述

选定的控件

在此输入图像描述

此功能非常需要,因为它可以帮助对齐而无需补偿视觉指导.

我们目前在所有控件周围实现了一个黑色边框

this.BackColor = Color.Black;
this.Height = ComboBox.Height + 4;
Run Code Online (Sandbox Code Playgroud)

这会在生成的控件周围放置一个黑色边框,在上面的代码片段中是一个ComboBox.

一位成员指出我们使用边缘和填充,如Microsoft文档中所示:https://msdn.microsoft.com/library/3z3f9e8b(v=vs.110)

但这主要是理论,并没有多大帮助.到目前为止,解决此问题的最接近的事情是在线CodeProject链接:

public class MyGroupBox : GroupBox
{
    protected override void OnPaint(PaintEventArgs e)
    {
    base.OnPaint(e);
    ControlPaint.DrawBorder(e.Graphics, ClientRectangle,
        Color.Black, BORDER_SIZE, ButtonBorderStyle.Inset,
        Color.Black, BORDER_SIZE, ButtonBorderStyle.Inset,
        Color.Black, BORDER_SIZE, ButtonBorderStyle.Inset,
        Color.Black, BORDER_SIZE, ButtonBorderStyle.Inset);
    } 
}
Run Code Online (Sandbox Code Playgroud)

到目前为止,我惊讶地发现我的搜索没有找到一个匹配的匹配,也许我使用了错误的术语,因为我最近进入了这个领域的编程.

我相信,如果这个问题得到解决,未来的在线搜索将会受益.期待指针形成那些有这个问题经验的人.非常感谢这方面的任何帮助.

Rez*_*aei 6

我在一个团队中工作,开发类似于 Visual Studio 的 IDE ....

开发自定义表单设计器并非易事,需要大量知识和大量时间,我相信您可以使用的最佳解决方案是托管 Windows 表单设计器。

这不仅仅是绘制选择边界:

  • 每个控件都有自己的具有特定功能的设计器,例如,某些控件MenuStrip具有自己的设计器,使您可以在设计器上添加/删除项目。
  • 控件可能有一些特定的大小和定位规则。例如,其中一些是自动调整大小的,TextBox或者停靠的控件不能通过鼠标重新定位等等。
  • 组件在您的表单上不可见,您可能需要对其进行编辑。
  • 某些属性是设计时属性。
  • 某些属性是使用扩展程序提供程序添加的,您需要执行其他任务以提供在自定义设计器中更改它们的方法。
  • 还有很多其他的考虑。

解决方案 1 - 托管 Windows 窗体设计器

要了解有关设计时架构的更多信息,请查看设计时架构。要在应用程序中托管 Windows 窗体设计器,您需要实现一些接口,如IDesignerHostIContainerIComponentChangeServiceIExtenderProviderITypeDescriptorFilterServiceIExtenderListServiceIExtenderProviderService

对于一些很好的例子,你可以看看:

您可能会发现这篇文章很有用:

该帖子包含有关如何在运行时托管 Windows 窗体设计器并生成代码的工作示例:

解决方案 2 - 在透明面板上绘制选择边框

虽然我强烈建议使用第一种解决方案,但只是为了学习目的,如果您想在控件周围绘制选择边框,您可以将要编辑的表单作为控件添加到宿主表单中,然后在表单上方放置一个透明面板. 处理Click透明面板的事件并找到鼠标位置下的控件并在透明面板上围绕它绘制一个选择边框,如下所示:

在此处输入图片说明

在示例中,我刚刚创建了一个透明面板并绘制了选择边框。这只是一个示例,执行大小调整和定位超出了示例的范围。这只是为了向您展示如何在控件周围绘制选择边框。你也可以用这个想法创建一个SelctionBorder控件,在控件中封装大小定位逻辑,而不是绘制边框,而是SelectionBorder在透明面板中添加一个控件实例,并在其大小和定位事件中改变相应的控件坐标。

请注意这只是一个例子,在真正的设计师环境中,你应该考虑很多重要的事情。

透明面板

using System.Windows.Forms;
public class TransparentPanel : Panel
{
    const int WS_EX_TRANSPARENT = 0x20;
    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;
            cp.ExStyle = cp.ExStyle | WS_EX_TRANSPARENT;
            return cp;
        }
    }
    protected override void OnPaintBackground(PaintEventArgs e)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

主机形式

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
public partial class HostForm : Form
{
    private Panel containerPanel;
    private TransparentPanel transparentPanel;
    private PropertyGrid propertyGrid;
    public HostForm()
    {
        this.transparentPanel = new TransparentPanel();
        this.containerPanel = new Panel();
        this.propertyGrid = new PropertyGrid();
        this.SuspendLayout();
        this.propertyGrid.Width = 200;
        this.propertyGrid.Dock = DockStyle.Right;
        this.transparentPanel.Dock = System.Windows.Forms.DockStyle.Fill;
        this.transparentPanel.Name = "transparentPanel";
        this.containerPanel.Dock = System.Windows.Forms.DockStyle.Fill;
        this.containerPanel.Name = "containerPanel";
        this.ClientSize = new System.Drawing.Size(450, 210);
        this.Controls.Add(this.transparentPanel);
        this.Controls.Add(this.propertyGrid);
        this.Controls.Add(this.containerPanel);
        this.Name = "HostForm";
        this.Text = "Host";
        this.Load += this.HostForm_Load;
        this.transparentPanel.MouseClick += this.transparentPanel_MouseClick;
        this.transparentPanel.Paint += this.transparentPanel_Paint;
        this.ResumeLayout(false);
    }
    private void HostForm_Load(object sender, EventArgs e)
    {
        this.ActiveControl = transparentPanel;
        /**************************************/
        /*Load the form which you want to edit*/
        /**************************************/   
        var f = new Form(); 
        f.Location = new Point(8, 8);
        f.TopLevel = false;
        this.containerPanel.Controls.Add(f);
        SelectedObject = f;
        f.Show();
    }
    Control selectedObject;
    Control SelectedObject
    {
        get { return selectedObject; }
        set
        {
            selectedObject = value;
            propertyGrid.SelectedObject = value;
            this.Refresh();
        }
    }
    void transparentPanel_MouseClick(object sender, MouseEventArgs e)
    {
        if (this.Controls.Count == 0)
            return;
        SelectedObject = GetAllControls(this.containerPanel)
            .Where(x => x.Visible)
            .Where(x => x.Parent.RectangleToScreen(x.Bounds)
                .Contains(this.transparentPanel.PointToScreen(e.Location)))
            .FirstOrDefault();
        this.Refresh();
    }
    void transparentPanel_Paint(object sender, PaintEventArgs e)
    {
        if (SelectedObject != null)
            DrawBorder(e.Graphics, this.transparentPanel.RectangleToClient(
                SelectedObject.Parent.RectangleToScreen(SelectedObject.Bounds)));
    }
    private IEnumerable<Control> GetAllControls(Control control)
    {
        var controls = control.Controls.Cast<Control>();
        return controls.SelectMany(ctrl => GetAllControls(ctrl)).Concat(controls);
    }
    void DrawBorder(Graphics g, Rectangle r)
    {
        var d = 4;
        r.Inflate(d, d);
        ControlPaint.DrawBorder(g, r, Color.Black, ButtonBorderStyle.Dotted);
        var rectangles = new List<Rectangle>();
        var r1 = new Rectangle(r.Left - d, r.Top - d, 2 * d, 2 * d); rectangles.Add(r1);
        r1.Offset(r.Width / 2, 0); rectangles.Add(r1);
        r1.Offset(r.Width / 2, 0); rectangles.Add(r1);
        r1.Offset(0, r.Height / 2); rectangles.Add(r1);
        r1.Offset(0, r.Height / 2); rectangles.Add(r1);
        r1.Offset(-r.Width / 2, 0); rectangles.Add(r1);
        r1.Offset(-r.Width / 2, 0); rectangles.Add(r1);
        r1.Offset(0, -r.Height / 2); rectangles.Add(r1);
        g.FillRectangles(Brushes.White, rectangles.ToArray());
        g.DrawRectangles(Pens.Black, rectangles.ToArray());
    }
    protected override bool ProcessTabKey(bool forward)
    {
        return false;
    }
    protected override void OnResize(EventArgs e)
    {
        base.OnResize(e);
        this.Refresh();
    }
}
Run Code Online (Sandbox Code Playgroud)