博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

解决SplitContainer的Click事件不能正确执行的问题

Posted on 2008-06-17 21:39  暴风雪  阅读(786)  评论(0)    收藏  举报

苦思冥想快2天的SplitContainer的Click事件控制SplitterDistance的问题,终于让我查出是什么问题!哈哈哈!

这个按说可以说是个微软的bug了,或者说是设计的时候没有考虑太多。有些东西他们设计也不是很精致亚,嘿嘿。

看张图可能你就明白了。

当鼠标按下的时候,splitContainer会响应自己的MouseDown事件,在这个事件里,他会生成一个新的层从而盖住了下面真正的Splitter。从而会影响到Click时间的执行情况,具体是啥情况就说不清楚了,我猜是:本来Click能好好的执行,可偏偏半路杀出一个MouseDown,这个MouseDown新产生的阴影层挡住了MouseUp的执行(不能算是一次Click操作)。从而使得界面闪了一下就又恢复原状了。

后来的实验也能证实,分别在MouseDown、MouseUp、MouseClick中实验。只有MouseDown可以完全正常执行。

解决方法:
其中一些思路来自于CollapsibleSplitter from codeproject
在Spliter中间画出一部分,点击这部分的时候进行快速切换操作,而点击其它部分的时候,就是控件默认调整

新建class继承自SplitContainer,然后覆盖OnPaint方法

    protected override void OnPaint(PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            Rectangle r = this.SplitterRectangle;
            g.FillRectangle(new SolidBrush(Color.Aqua), r);
            if (Orientation == Orientation.Vertical)
            {
                rr = new Rectangle(r.X, (int)r.Y + ((r.Height - 115) / 2), 8, 115);
                this.SplitterWidth = 8;
  g.FillRectangle(new SolidBrush(hotColor), new Rectangle(rr.X + 1, rr.Y, 6, 115));                
                g.DrawLine(new Pen(SystemColors.ControlDark, 1), rr.X + 1, rr.Y, rr.X + rr.Width - 2, rr.Y);
                g.DrawLine(new Pen(SystemColors.ControlDark, 1), rr.X + 1, rr.Y + rr.Height, rr.X + rr.Width - 2, rr.Y + rr.Height);

                if (this.Enabled)
                {
                    // draw the arrows for our control image
                    // the ArrowPointArray is a point array that defines an arrow shaped polygon
                    g.FillPolygon(new SolidBrush(SystemColors.ControlDarkDark), ArrowPointArray(rr.X + 2, rr.Y + 3));
                    g.FillPolygon(new SolidBrush(SystemColors.ControlDarkDark), ArrowPointArray(rr.X + 2, rr.Y + rr.Height - 9));
                }

            }

     //do not Dispose,is it Ok???
            //g.Dispose();
        }

 

然后在MouseMove中进行判断当前鼠标是否在所画的区域即可,然后分别调用不同的事件处理。

private void OnMouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            // check to see if the mouse cursor position is within the bounds of our control
            System.Console.WriteLine(e.X.ToString() + " " + e.Y.ToString());
            if (e.X >= rr.X && e.X <= rr.X + rr.Width && e.Y >= rr.Y && e.Y <= rr.Y + rr.Height)
            {
                if (!this.hot)
                {
                    this.hot = true;
                    this.Cursor = Cursors.Hand;
                    this.Invalidate();
                }

            }

            else
            {
                if (this.hot)
                {
                    this.hot = false;
                    this.Invalidate(); ;
                }


                this.Cursor = Cursors.Default;

                if (controlToHide != null)
                {
                    if (!controlToHide.Visible)
                        this.Cursor = Cursors.Default;
                    else // Changed in v1.2 to support Horizontal Splitters
                    {
                        if (this.Orientation == Orientation.Vertical)
                        {
                            this.Cursor = Cursors.VSplit;
                        }

                        else
                        {
                            this.Cursor = Cursors.HSplit;
                        }

                    }

                }

            }

        }

 

另外还要覆盖MouseDown事件。如果MouseDown的时候是在所画的区域则不调用base的MouseDown

protected override void OnMouseDown(MouseEventArgs e)
        {
            if (!this.hot)
                base.OnMouseDown(e);
        }