C# 具有透明背景色问题的自定义列表框

C# 具有透明背景色问题的自定义列表框,c#,winforms,listbox,custom-controls,transparent,C#,Winforms,Listbox,Custom Controls,Transparent,我创建了一个从ListBox继承的自定义多行ListBox控件。在表单中,ListBox位置位于ElementHost中承载的WPF圆形透明面板上方。现在,我想要的是,ListBox的背景色是透明的。显然,这在Winforms中是不允许的,列表框不能是透明的。然后,我尝试了一些事情,但总有一个问题 我想要实现的是: 正如你所看到的,这非常有效,但实际上我有两个问题 第一个是当我选择一个项目时。这些信变得很难看。只需将下一张图像与第一张图像进行比较。您可以看到它们看起来都很丑,因为它们都被选中了

我创建了一个从ListBox继承的自定义多行ListBox控件。在表单中,ListBox位置位于ElementHost中承载的WPF圆形透明面板上方。现在,我想要的是,ListBox的背景色是透明的。显然,这在Winforms中是不允许的,列表框不能是透明的。然后,我尝试了一些事情,但总有一个问题

我想要实现的是:

正如你所看到的,这非常有效,但实际上我有两个问题

第一个是当我选择一个项目时。这些信变得很难看。只需将下一张图像与第一张图像进行比较。您可以看到它们看起来都很丑,因为它们都被选中了

我遇到的第二个问题是当我向下/向上滚动列表框时。透明的颜色消失了,我得到了黑色

我记得在表单中有一个可滚动的面板。面板是透明的,解决方法是在面板滚动事件中调用Invalidate方法。但我的列表框中没有该事件

另外,我想隐藏滚动条,但可以滚动

我附加CustomListBox代码,以便您可以看到我所做的操作。如果你也想要一个简单的多行列表框,你可以随意使用它

以防万一,我用来将ListBox设置为透明的方法是重写CreateParams

公共类多列表框:System.Windows.Forms.ListBox { 公共多列表框 { this.DrawMode=DrawMode.OwnerDrawVariable; this.ScrollAlwaysVisible=true; }

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

    protected override void OnMeasureItem(MeasureItemEventArgs e)
    {
        if(Site!=null)
            return;
        if(e.Index > -1)
        {
            string s = Items[e.Index].ToString();
            SizeF sf = e.Graphics.MeasureString(s,Font,Width);
            int htex = (e.Index==0) ? 15 : 10;
            e.ItemHeight = (int)sf.Height + htex;           
            e.ItemWidth = Width;
        }
    }

    protected override void OnDrawItem(DrawItemEventArgs e)
    {
        if(Site!=null)
            return;
        if(e.Index > -1)
        {
            string s = Items[e.Index].ToString();                           

            if((e.State & DrawItemState.Focus)==0)
            {
                e.Graphics.DrawString(s,Font,new SolidBrush(Color.White),e.Bounds);             
                e.Graphics.DrawRectangle(new Pen(Color.FromArgb(255, 26, 36, 41)),e.Bounds);                
            }
            else
            {
                e.Graphics.DrawRectangle(new Pen(Color.FromArgb(255, 0, 185, 57)), e.Bounds);
                //e.Graphics.DrawString(s,Font,new SolidBrush(Color.FromArgb(255, 0, 161, 47)),e.Bounds);
            }
        }
    }
}   
哦,我差点忘了。我尝试重写OnPaintBackGround,它通过将SetStyle设置为userPaint来工作。但它更不受欢迎,因为我不仅遇到了与其他解决方案相同的问题,而且文本也没有显示,因此,我坚持使用第一个解决方案

希望有人能帮我!你可以试试这个

protected override void OnPaintBackground(PaintEventArgs pevent)
{
    IntPtr hdc = pevent.Graphics.GetHdc();
    Rectangle rect = this.ClientRectangle;
    NativeMethods.DrawThemeParentBackground(this.Handle, hdc, ref rect);
    pevent.Graphics.ReleaseHdc(hdc);
}


internal static class NativeMethods
{
    [DllImport("uxtheme", ExactSpelling = true)]
    public extern static Int32 DrawThemeParentBackground(IntPtr hWnd, IntPtr hdc, ref Rectangle pRect);
}

当我需要为不支持它的控件绘制透明背景色时,它对我很有用。我将它与TabControl一起使用。

winforms不支持任何这些。你已经在使用ElementHost了,为什么不创建一个带有适当ItemTemplate的WPF列表框和带有透明效果的漂亮样式?…你需要0行C代码为了在WPF中实现这一点,需要10到20行XAML。@HighCore可以在Winforms中完成许多事情。它只是更复杂。我知道我可以在WPF中更轻松地完成这项工作,但我对它了解不多。列表框中的每一项都有一个contextmenu。所有这些要求使我远离WPF。contextmenu只是一个图形化的菜单列表的表示。我不认为这有多复杂。在WPF中,一切都更简单,性能也更好。当你完成这个winforms应用程序时,你会发现它因为性能差而无法使用,并且无论如何都必须完全在WPF中重新做。另外,我对ABC支持XYZ的技术或框架的想法是,你可以实现XYZ在正常的时间内使用ABC,而不必求助于一堆黑客,比如必须调用非托管代码来做一些与UI相关的事情。因此,winforms不支持任何这些东西。我认为@HighCore Winform很慢,它与WPF的互操作无关。正如我告诉你的,我对WPF知之甚少。这就是我使用winforms的原因。因为我知道。这个应用程序快完成了。我无法将它全部迁移到我不掌握的技术上。很好。必须借助WinAPI在WPF中做一些等效的事情。我会在几分钟后尝试。以防万一,在滚动时这能正常工作吗?@Andres你还想要WPF解决方案吗?我可以帮你创建ItemTemplate,t他使用ViewModel及其命令作为ContextMenu,如果您愿意,还可以使用ListBox样式。@HighCore谢谢您,但我认为如果我使用一种技术,该应用程序将更易于维护。我只是使用WPF作为美观的控件,因为我几个月前才知道该技术。如果无法在wirforms中实现,我将离开b背景为黑色。@Andres UserPaint、AllPaintInWmPaint、ResizerDraw和OptimizedDoubleBuffer是ControlStyles枚举的成员。在开始绘图之前,通常在构造函数/初始化方法中使用SetStyle设置它们。至于Invalidatethis.ClientRectangle;Update;