Non-overlapped transparent control

2019-07-11 19:41发布

问题:

I'm trying to make a tooltip for my video player. I use a windows media player embedded into my winform's app on c# (AxWMPLib.AxWindowsMediaPlayer) for playing video. And I have created a control that shows a current position of a media. This control is transparent. Control's code is below:

namespace player.Controls
{
public partial class TransparentToolTip : System.Windows.Forms.UserControl
{
    public enum PointerLocation : byte { ... }

    #region Private data
     // ...
    #endregion

    Timer Wriggler = new Timer();
    int iInterval = 100;
    protected void TickHandler(object sender, EventArgs e)
    {
        this.InvalidateEx();
    } 

    private void _SetStyle()
    {
        this.SetStyle((ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.ResizeRedraw | ControlStyles.CacheText | ControlStyles.ContainerControl), true);
        this.SetStyle(ControlStyles.Selectable, false);
        this.SetStyle(ControlStyles.SupportsTransparentBackColor | ControlStyles.Opaque, true);            
        this.UpdateStyles();
    }
    private void _SetTimer(int _Interval)
    {
        Wriggler.Tick += new EventHandler(TickHandler);
        this.Wriggler.Interval = _Interval;
        this.Wriggler.Enabled = true;
    }    

    public TransparentToolTip()
    {            
        InitializeComponent();
        _SetStyle();
        _SetTimer(iInterval);                    
    }
    public TransparentToolTip(System.ComponentModel.IContainer container)
    {               
        container.Add(this);             
        InitializeComponent();            
        _SetStyle();
        _SetTimer(iInterval); 
    }        

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;
            cp.ExStyle |= (0x00000020 | 0x00000008); // WS_EX_TRANSPARENT  = 0x00000020, WS_EX_TOPMOST = 0x00000008              
            return cp;
        }
    }
    #region Extra Properties
    // ...
    #endregion

    // Drawing            
    protected void InvalidateEx()
    {
        if (Parent == null)
            return;
        Rectangle rc = new Rectangle(this.Location, this.Size);
        Parent.Invalidate(rc, true);
    }
    protected override void OnPaintBackground(PaintEventArgs pevent)
    {

    }
    protected override void OnPaint(PaintEventArgs pe)
    {           
        pe.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
        pe.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
        pe.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
        pe.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;

        Rectangle rect = new Rectangle(this.ClientRectangle.X, this.ClientRectangle.Y, this.ClientRectangle.Width - 1, this.ClientRectangle.Height - 1);            
        SolidBrush brushBackground = new SolidBrush(ColorBackground);
        SolidBrush brushBorder = new SolidBrush(ColorBorder);
        using (GraphicsPath graphicsPath = ToolTipBody(...))
        {
            using (Pen p = new Pen(brushBorder, BorderSize))
            {
                pe.Graphics.FillPath(brushBackground, graphicsPath); // background
                pe.Graphics.DrawPath(p, graphicsPath); // borders
            }
        }            

        TextFormatFlags flags = // some flags;
        TextRenderer.DrawText(pe.Graphics, ToolTipText, Font, new Rectangle(this.ClientRectangle.X, this.ClientRectangle.Y, this.ClientRectangle.Width, this.ClientRectangle.Height - TriangleSizeSide), ToolTipColor, System.Drawing.Color.Transparent, flags);
        brushBorder.Dispose();
        brushBackground.Dispose();

        base.OnPaint(pe);
    }
    // Form mapping tips
    private GraphicsPath ToolTipBody(...)
    { 
        // some code
        return graphicsPath;
    }
}

I try to show this tooltip over the axWindowsMediaPlayer object. But my control is overlapped by the media player. I've tried to use SetWindowPos but this does not work:

static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
const int SWP_NOSIZE = 0x0001;
const int SWP_NOMOVE = 0x0002;
const int SWP_SHOWWINDOW = 0x0040;
//...
 [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
 [return: MarshalAs(UnmanagedType.Bool)]
  public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, int flags);
//...
SetWindowPos(transparentToolTip1.Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);

Note: If do not change CreateParams of a new control it draws over the media player. But it becomes opaque.

Is any ideas to do it correct using winforms?

回答1:

My guess is that the transparent thing is happening because you're defining the control style as ControlStyles.Opaque. Then, setting the flag to WS_EX_TRANSPARENT you're setting it to transparent style again.

About the overlapped issue: If you designed the form using the Visual Studio Windows Forms designer, maybe your control is zOrdered down the AxWMPLib.AxWindowsMediaPlayer component. Try to bring to front or control the ChildrenIndex in your control collection before show it.

Hope it helps.