//如果这样写就不会有图形
private void updateImage()
{
   graph.DrawLine(pen,0,2,20,50);
   this.BackgroundImage=bitmap;
}这样有可能会报错:未将对象引用到对象实例。我想楼主还没有找着对象吧。

解决方案 »

  1.   

    你断点调试下:
    1)看看第一次调用createImage时,this.Width,this.Height具体的值是多少,可能是0或者很小的值;
    其实是画了,只是根本看不见;
    2)你调用updateImage时,this.Width,this.Height已经变成非0或者肉眼能看到的值了;只不过需要重新给bitmap赋值!
      

  2.   

    你不new 哪里来的对象呢?虽然有这个方法createImage,你确定他不会被GC回收?
      

  3.   


    你都不仔细看我的帖子的。
    我先调用的CreateImage()这个方法,这个方法里已经对bitmap创建实例了,为什么创建了还要再创建?
      

  4.   


    我断点调了,在updateImage里即使没有重新New Bitmap,graph的Width是150,Height是300,正好是我那个控件的大小,奇怪的是为啥就是画不出图来。
      

  5.   


    我也想是不是这个原因,但是Bitmap我是申明为类成员的,并不是局部变量,而且奇怪的是,如果在UpdateImage里没有对bitmap重新new,断点调试时,可以看到graph是有大小,好苦恼这是为什么
      

  6.   

    如果你createImage()执行后立刻调用updateImage(),应该效果和重新new一样的,因为代码之间没有任何其它干预,你说的是什么特殊情况?
      

  7.   


    你都不仔细看我的帖子的。
    我先调用的CreateImage()这个方法,这个方法里已经对bitmap创建实例了,为什么创建了还要再创建?
    贴完整代码吧,这么两句话说不清你到底怎么写的。
      

  8.   


    先调用createImage(),并且这个过程中是不会释放 bitmap的,我把这个控件封装好,然后在外部调用这些方法,详细代码贴在下楼
      

  9.   


    详细代码大致如下, 这是自定义的控件private Bitmap bitmap;
    private Graphics graph;
    private Pen penWave = new Pen(Color.Lime);
    private Pen penGrid = new Pen(Color.Gray); protected override void OnLoad(EventArgs e)
    {
                //打开双缓冲,防止闪烁
                DoubleBuffered = true;
                canvas_height = base.ClientSize.Height;
                canvas_width = base.ClientSize.Width;
                bitmap = new Bitmap(this.Width, this.Height);
                graph = Graphics.FromImage(bitmap);
                DrawGrids(ref graph);
                this.BackgroundImage = bitmap;
     }protected override void OnResize(EventArgs e)
     {
                canvas_height = base.ClientSize.Height;
                canvas_width = base.ClientSize.Width;
                bitmap = new Bitmap(this.Width, this.Height);
                graph = Graphics.FromImage(bitmap);
                DrawGrids(ref graph);
                DrawDot(ref graph);
                this.BackgroundImage = bitmap;
           
    } private void DrawGrids(ref Graphics g)
    {//画网格
      //pos,canvas_height都是变量,不重复贴了,不影响整体
       g.DrawLine(penGrid, pos, 0, pos, canvas_height);//基本上都是这种代码,不重复贴,没做别的处理
    }private void DrawWave(ref Graphics g)
    {
      graph.DrawLine(penWave,0,2,20,50);//基本上都是这种,两点之间连线的,不重复贴代码了
    }//调用的时候,会先调用这个CreateImage()方法,再调用UpdateImage
    //CreateImage只调用一次,UpdateImage会调用多次
    public void CreateImage()

      bitmap=new Bitmap(this.Width,this.Height);
       graph=new Graphics.FromImage(bitmap);
    }
     public void UpdateImage()
     {//经过反复试验,在这个方法里必须要对bitmap重新new,否则看不到两点间的连线
           
                bitmap = new Bitmap(this.Width, this.Height);
                graph = Graphics.FromImage(bitmap);
                DrawDot(ref graph);
                this.BackgroundImage = bitmap;
    }本来是想在bitmap上先画好格子,然后再调用UpdateImage只画点,不用重复画格子,但是现在的问题是每次都要对bitmap重新new,于是只能每次都要重新画格子,这样影响效率,所以才问这么个问题。为什么之前对bitmap创建过实例了,然后进行画图看不到图形?
      

  10.   

    上面写错一行代码在UpdateImage()里的DrawDot(ref graph)要改成DrawWave(ref graph)
      

  11.   

    你上面给的代码里面CreateImage和UpdateImage压根没用到,你应该把不起作用的代码贴出来,把能作用的代码贴出来分析什么啊?
      

  12.   


    囧死了,我文字部分做出说明了,那我就再把怎么使用的贴出来好了。。
    这个类的实例名字叫gridCanvas,在Form1里使用
     private void Form1_Load(object sender, EventArgs e)
    {
         gridCanvas.CreateImage();//调用的是类里的方法
    }//以下方法被执行
    private void receive()
    {
       gridCanvas.UpdateImage();
    }
      

  13.   


    我在代码里有问题的地方都提了问题。做了文字说明
    问题在于如果UpdateImage里如果不对bitmap进行重新new,就显示不出后来画的图形
      

  14.   


    你看下我贴出来的代码,至于receive()方法执行,是在一个按钮的事件里,我可以肯定它被执行了
      

  15.   


    private Bitmap bitmap;
    private Graphics graph;
    private Pen penWave = new Pen(Color.Lime);
    private Pen penGrid = new Pen(Color.Gray);
     
     protected override void OnLoad(EventArgs e)
    {
                //打开双缓冲,防止闪烁
                DoubleBuffered = true;
                canvas_height = base.ClientSize.Height;
                canvas_width = base.ClientSize.Width;
               CreateImage();
                DrawGrids(ref graph);
                this.BackgroundImage = bitmap;
     }
     
    protected override void OnResize(EventArgs e)
     {
                canvas_height = base.ClientSize.Height;
                canvas_width = base.ClientSize.Width;
               
                this.Refresh();
            
    }
     
     private void DrawGrids()
    {//画网格
      //pos,canvas_height都是变量,不重复贴了,不影响整体
       graph.DrawLine(penGrid, pos, 0, pos, canvas_height);//基本上都是这种代码,不重复贴,没做别的处理
    }
     
    private void DrawWave()
    {
      graph.DrawLine(penWave,0,2,20,50);//基本上都是这种,两点之间连线的,不重复贴代码了
    }
     
    //调用的时候,会先调用这个CreateImage()方法,再调用UpdateImage
    //CreateImage只调用一次,UpdateImage会调用多次
    public void CreateImage()

      bitmap=new Bitmap(this.Width,this.Height);
       graph=new Graphics.FromImage(bitmap);
    }
     
     
     public void UpdateImage()
     {//经过反复试验,在这个方法里必须要对bitmap重新new,否则看不到两点间的连线
            
           
                DrawDot();
                this.Refresh();
    }
    改成酱紫应该没问题了。
      

  16.   

    设定背景颜色的时候,重新new一下就好了。
    原因就出在this.BackgroundImage和graph使用了同一个bitmap对象。
            public void UpdateImage()
            {//经过反复试验,在这个方法里必须要对bitmap重新new,否则看不到两点间的连线
                DrawWave(ref graph);
                this.BackgroundImage = new Bitmap(bitmap);
            }
      

  17.   

    谢谢你的解答,你的方法可行。
    是因为当Bitmap作为背景图像的时候,再对这个Bitmap进行操作,等到更新之前无法显示吗?yuwenge提供的办法也行,要Reflesh才能显示图形
    请教下这是为什么呢,为啥this.BackgroundImage和graph使用了同一个bitmap对象,然后再重新设置BackgroundImage的时候需要重新new呢
      

  18.   

    谢谢你的解答,调用Refresh是可以显示出图像的,请教下这是为什么呢,对同一个bitmap进行操作,这个bitmap已经作为背景图像了,再次操作的时候为啥设置BackgroundImage为bitmap不管用,要调用Reflesh才行呢?
      

  19.   

    因为你的
      this.BackgroundImage = bitmap;
    bitmap是一个引用类型。当你再次设置 this.BackgroundImage = bitmap;的时候,其实什么都没做,因为 this.BackgroundImage所指向的内存地址已经是bitmap了。这个时候不会自动触发窗体print事件。当你在
    this.BackgroundImage = bitmap;之前加了bitmap=new Bitmap()之后,bitmap的内存地址发生了重新分配,这样
    BackgroundImage发现接收的内存地址发生了变化,于是触发了窗体print事件。最终的原因还是因为:你没有找着对象。
      

  20.   

    因为你的
      this.BackgroundImage = bitmap;
    bitmap是一个引用类型。当你再次设置 this.BackgroundImage = bitmap;的时候,其实什么都没做,因为 this.BackgroundImage所指向的内存地址已经是bitmap了。这个时候不会自动触发窗体print事件。当你在
    this.BackgroundImage = bitmap;之前加了bitmap=new Bitmap()之后,bitmap的内存地址发生了重新分配,这样
    BackgroundImage发现接收的内存地址发生了变化,于是触发了窗体print事件。最终的原因还是因为:你没有找着对象。
    好吧,意思就是说BackgroundImage指向了bitmap的引用地址,但是再次设置BackgroundImage的时候,编译器检测到指向的内存地址不变,即使bitmap里的东西发生了变化,也不会更新UI,大致是这个意思吧?感觉有点像是编译优化,在C里可以用volatile进行修饰防止编译器优化,对Bitmap用volatile修饰,发现不管用。还是得刷新才行
      

  21.   

    因为你的
      this.BackgroundImage = bitmap;
    bitmap是一个引用类型。当你再次设置 this.BackgroundImage = bitmap;的时候,其实什么都没做,因为 this.BackgroundImage所指向的内存地址已经是bitmap了。这个时候不会自动触发窗体print事件。当你在
    this.BackgroundImage = bitmap;之前加了bitmap=new Bitmap()之后,bitmap的内存地址发生了重新分配,这样
    BackgroundImage发现接收的内存地址发生了变化,于是触发了窗体print事件。最终的原因还是因为:你没有找着对象。
    好吧,意思就是说BackgroundImage指向了bitmap的引用地址,但是再次设置BackgroundImage的时候,编译器检测到指向的内存地址不变,即使bitmap里的东西发生了变化,也不会更新UI,大致是这个意思吧?感觉有点像是编译优化,在C里可以用volatile进行修饰防止编译器优化,对Bitmap用volatile修饰,发现不管用。还是得刷新才行
    就是这个意思,因为.net中认为bitmap是一个非托管对象,所以不管是不是优化,都不会对bitmap进行检查。另外你的代码里面 ref Graphics也是没有意义的,因为Graphics本身就是一个引用对象,不需要ref也是ref了。
      

  22.   

    private void updateImage()
    {
       graph.DrawLine(pen,0,2,20,50);
       this.BackgroundImage=bitmap;
    }
    改为:
    private void updateImage()
    {
       graph.DrawLine(pen,0,2,20,50);
       this.BackgroundImage=bitmap;
       OnBackgroundImageChanged(new EventArgs());
    }
    控件的BackgroundImage属性在设置值的时候,有一段判断语句:
    if(this.BackgroundImage != value)
    因此对于第二次的this.BackgroundImage=bitmap;操作是没有任何动作的。不过你可以人为地引发那个事件。