C# 显示部分用户控件的工具提示

C# 显示部分用户控件的工具提示,c#,.net,C#,.net,我正在构建自定义控件,该控件将显示瓷砖,如彩色网格。 我已经完成了绘图、滚动和基本逻辑,但在为每个互动程序创建工具提示时遇到了问题。 每个磁贴颜色取决于“绑定”到该磁贴的数据 我将试着描述我的想法: 上图显示了我的控件,我在这里画了4个正方形,当用户悬停在控件的不同部分时,我想显示不同的工具提示。 下面是我的工具提示(红色小矩形),下面是标准的WinForms图表组件。 我希望在我的控件中获得这种行为(工具提示不受控制,因此长文本可以正确显示) 以下是我的控件代码,仅包含基本功能: publ

我正在构建自定义控件,该控件将显示瓷砖,如彩色网格。 我已经完成了绘图、滚动和基本逻辑,但在为每个互动程序创建工具提示时遇到了问题。
每个磁贴颜色取决于“绑定”到该磁贴的数据

我将试着描述我的想法:
上图显示了我的控件,我在这里画了4个正方形,当用户悬停在控件的不同部分时,我想显示不同的工具提示。 下面是我的工具提示(红色小矩形),下面是标准的WinForms图表组件。
我希望在我的控件中获得这种行为(工具提示不受控制,因此长文本可以正确显示)

以下是我的控件代码,仅包含基本功能:

public sealed class UC1 : UserControl
{
    private bool _showTooltip;
    private string _tooltipText;
    private Point _mousePosition;

    public UC1()
    {
        MinimumSize = new Size(100, 100);
        Size = new Size(100, 100);
        SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.ResizeRedraw | ControlStyles.OptimizedDoubleBuffer, true);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        e.Graphics.FillRectangle(Brushes.LightGoldenrodYellow, 0, 0, Width/2, Height/2);
        e.Graphics.FillRectangle(Brushes.LightGray, Width/2, 0, Width, Height/2);
        e.Graphics.FillRectangle(Brushes.LightSlateGray, 0, Height/2, Width/2, Height);
        e.Graphics.FillRectangle(Brushes.LightSteelBlue, Width/2, Height/2, Width, Height);

        using (var p = new Pen(Color.Black, 2))
        {
            e.Graphics.DrawLine(p, Width/2, 0, Width/2, Height);
            e.Graphics.DrawLine(p, 0, Height/2, Width, Height/2);
        }

        if (_showTooltip)
        {
            SizeF c = e.Graphics.MeasureString(_tooltipText, DefaultFont);
            int width = (int) c.Width;
            int height = (int) c.Height;
            const int offset = 12;

            var x = _mousePosition.X + width + offset > Width ? _mousePosition.X - width : _mousePosition.X + offset;
            var y = _mousePosition.Y + height + offset > Height ? _mousePosition.Y - height : _mousePosition.Y + offset;

            e.Graphics.FillRectangle(Brushes.Red, x, y, width, height);
            e.Graphics.DrawString(_tooltipText, DefaultFont, Brushes.Black, x, y);
        }
    }

    protected override void OnMouseMove(MouseEventArgs e)
    {
        base.OnMouseMove(e);
        if (e.X > 0 && e.X < Width/2 && e.Y > 0 && e.Y < Height/2)
        {
            Debug.WriteLine("1,1 square");
            _tooltipText = "1,1";
        }
        else if (e.X > Width/2 && e.X < Width && e.Y > 0 && e.Y < Height/2)
        {
            Debug.WriteLine("1,2 square");
            _tooltipText = "1,2";
        }
        else if (e.X > 0 && e.X < Width/2 && e.Y > Height/2 && e.Y < Height)
        {
            Debug.WriteLine("2,1 square");
            _tooltipText = "2,1";
        }
        else if (e.X > Width/2 && e.X < Width && e.Y > Height/2 && e.Y < Height)
        {
            Debug.WriteLine("2,2 square");
            _tooltipText = "2,2";
        }
        _mousePosition = e.Location;
        _showTooltip = true;
        Refresh();
    }

    protected override void OnMouseLeave(EventArgs e)
    {
        _showTooltip = false;
        Refresh();
        base.OnMouseLeave(e);
    }
}
公共密封类UC1:UserControl
{
私人bool\u showTooltip;
私有字符串_tooltipText;
专用点(鼠标位置),;
公共UC1()
{
最小尺寸=新尺寸(100100);
尺寸=新尺寸(100100);
设置样式(ControlStyles.UserPaint | ControlStyles.AllPaintingWimPaint | ControlStyles.ResizerDraw | ControlStyles.OptimizedDubleBuffer,true);
}
受保护的覆盖无效OnPaint(PaintEventArgs e)
{
基础漆(e);
e、 图形。填充矩形(画笔。浅黄色,0,0,宽/2,高/2);
e、 图形。填充矩形(画笔。浅灰色,宽度/2,0,宽度,高度/2);
e、 图形。填充矩形(画笔。浅灰色,0,高度/2,宽度/2,高度);
e、 图形。填充矩形(画笔。浅蓝色,宽度/2,高度/2,宽度,高度);
使用(var p=新笔(颜色:黑色,2))
{
e、 绘图线(p,宽度/2,0,宽度/2,高度);
e、 绘图线(p,0,高度/2,宽度,高度/2);
}
如果(显示工具提示)
{
SizeF c=e.Graphics.MeasureString(_tooltipText,DefaultFont);
整数宽度=(整数)c.宽度;
整数高度=(整数)c.高度;
常数int offset=12;
var x=_mousePosition.x+宽度+偏移>宽度?_mousePosition.x-宽度:_mousePosition.x+偏移;
变量y=_mousePosition.y+高度+偏移>高度?_mousePosition.y-高度:_mousePosition.y+偏移;
e、 图形。填充矩形(画笔。红色,x,y,宽度,高度);
e、 图形.抽绳(_tooltipText,DefaultFont,Brush.Black,x,y);
}
}
MouseMove上的受保护覆盖无效(MouseEventArgs e)
{
基地移动(e);
如果(e.X>0&&e.X0&&e.YWidth/2和&e.X0和&e.Y0&&e.XHeight/2&&e.YWidth/2和&e.XHeight/2和&e.Y
我发现了类似的问题:但我希望避免创建自定义工具提示,而是使用标准工具提示


如何显示将在不同平铺上悬停时更改其文本的标准工具提示。我想将所有内容添加到我的用户控件中,这样我就不必添加任何代码来承载我的控件。

为什么您要尝试自己绘制工具提示而不是使用系统提示

只需在UC类中添加一个

// private bool _showTooltip;      ?? probably not needed any more..
private string _tooltipText;   
// private Point _mousePosition;   ??..
ToolTip ttip = new ToolTip();
设置如下:

// _mousePosition = e.Location; ??..
// _showTooltip = true;         ??..

ttip.SetToolTip(this, _tooltipText);  // use this in the mousemove
Refresh();
当然,现在你可以跳过整个绘画部分

如果要控制显示
工具提示的位置,请使用
ShowToolTip()
重载之一,而不是
SetToolTip()

当两者都还在的时候,这就是结果,越过UC的边界并显示一个漂亮的阴影

如果你真的想让你的
工具提示
看起来与通常的不同,你可以将它的
OwnerDraw
设置为
true
,并像使用
GDI+
图形方法的任何其他控件一样对它的
Draw
事件进行编码

更新:

存在固有的闪烁问题;有关解释,请参见;他的建议#2和其中一个答案很有帮助:

记住最后一个鼠标位置,并仅在鼠标移动时设置工具提示 位置改变

因此,我们需要添加最后一个工具提示位置:

  Point tipLoc = Point.Empty;
我们在鼠标移动中测试并设置:

if (tipLoc != e.Location )
{
    tipLoc = e.Location;
    ttip.SetToolTip(this, _tooltipText);
}

我试图避免在我的控件中添加工具提示,我想在发布问题之前表明我已经尝试了一些东西。我会更新我的代码。当我将鼠标移到控制之外时,是否必须在工具提示上调用
Show()
Hide()
?在处理我的控件时,我必须处理Tolltip吗?您只创建一个,默认情况下它将隐藏一个。因此,在我看来,不需要其他任何东西。显示和隐藏只是为了在必要时强制使用工具提示;我认为你不需要它;移动将自动执行。感谢您的澄清:)我知道我应该只创建一个。我马上就去试试!工作几乎完美。我在MouseMove中设置工具提示文本,工具提示会显示,但当我移动鼠标时,工具提示会闪烁,可能是因为
SetToolTip
正在刷新工具提示。我怎样才能消除闪烁?我已经让它工作了。我在MouseMove中创建了局部变量,我正在计算新文本,只是它与我调用的前一个变量不同