跨线程选项卡绘图

时间:2012-03-14 04:10:01

标签: c#

基本上,我有一个TabControl。 我自己绘制标题的文本,以便在需要时可以着色。 更改颜色的调用与TabControl所在的线程不同,因此我使用委托等进行跨线程操作。 不幸的是,我的方法并不完全可靠。

以下是交叉线程部分:

delegate TabControl getTabDelegate();
private TabControl getTab()
{
    if (this.channelTabs.InvokeRequired)
    {
        getTabDelegate d = new getTabDelegate(getTab);
        this.Invoke(d);
        return null;
    }
    else
    {
        return channelTabs;
    }
}

这是绘图代码:

private void channelTabs_DrawItem(object sender, DrawItemEventArgs e)
{
    try
    {
        TabControl ct = getTab();
        using (Brush br = new SolidBrush(TabColors[ct.TabPages[e.Index]]))
        {
            e.Graphics.FillRectangle(br, e.Bounds);
            SizeF sz = e.Graphics.MeasureString(ct.TabPages[e.Index].Text, e.Font);
            e.Graphics.DrawString(ct.TabPages[e.Index].Text, e.Font, Brushes.Black, e.Bounds.Left + (e.Bounds.Width - sz.Width) / 2, e.Bounds.Top + (e.Bounds.Height - sz.Height) / 2 + 1);

            Rectangle rect = e.Bounds;
            rect.Offset(0, 1);
            rect.Inflate(0, -1);
            e.Graphics.DrawRectangle(Pens.DarkGray, rect);
            e.DrawFocusRectangle();
        }
    }
    catch(Exception err)
    {
        MessageBox.Show(err.Message, "1");
    }
}

如您所见,在某些情况下getTab();返回null,这不是很有用。 还有......可靠的方法吗?

以下是从第二个线程调用以更改标题颜色的方法:

private void SetTabHeader(TabPage page, Color color)
{
    TabColors[page] = color;
    channelTabs.Invalidate();
}

当然没有交叉线程部分,我会抛出异常。

正如您可能想象的那样,channelTabs是GUI选项卡控件。

感谢任何帮助,谢谢!

- 哦,是的,如果它真的有用:     私人词典TabColors =新词典();

3 个答案:

答案 0 :(得分:0)

无论如何,你的所有绘图都需要在UI线程中完成,所以我要做的就是像这样修改channelTabs_DrawItem(object sender, DrawItemEventArgs e)

channelTabs_DrawItem(object sender, DrawItemEventArgs e)
{
    if(this.InvokeRequired)
    {
        this.BeginInvoke(() => channelTabs_DrawItem(sender,e));
        return;
    }
    TabControl ct = channelTabs;
    ...

这将确保您始终在正确的线程中运行,并避免使用对Invoke的潜在危险调用。 如果你真的想修复你正在使用的代码,你需要做的是从Invoke返回值,如下所示:

private TabControl getTab()
{
    if (this.channelTabs.InvokeRequired)
    {
        getTabDelegate d = new getTabDelegate(getTab);
        return (TabControl)this.Invoke(d);
    }
    else
    {
        return channelTabs;
    }
}

答案 1 :(得分:0)

你过于复杂 - 你需要使用Invoke来设置SetTabHeader函数,不是绘图事件或getTab。只要你不做任何愚蠢的事情就像在不同的线程中调用Invalidate一样,这些只会自然地从UI线程调用。

private void SetTabHeader(TabPage page, Color color)
{
    if(this.InvokeRequired) {
        this.Invoke(new Action<TabPage,Color>(SetTabHeader),page,color);
    } else {
        TabColors[page] = color;
        channelTabs.Invalidate();
    }
}

答案 2 :(得分:0)

因为这个而失败......

delegate TabControl getTabDelegate(); 
private TabControl getTab() 
{ 
    if (this.channelTabs.InvokeRequired) 
    { 
        getTabDelegate d = new getTabDelegate(getTab); 
        this.Invoke(d); 
        return null; // <-- The return from your invoke is ignored
    } 
    else 
    { 
        return channelTabs; 
    } 
}

而是这样做:

delegate TabControl getTabDelegate(); 
private TabControl getTab() 
{ 
    if (this.channelTabs.InvokeRequired) 
    { 
        getTabDelegate d = new getTabDelegate(getTab); 
        return this.Invoke(d); // Don't lose the return value from the invoked call
        //return null; 
    } 
    else 
    { 
        return channelTabs; 
    } 
}