Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. Array of Regions. Elements seem to disappear. [modified]

Array of Regions. Elements seem to disappear. [modified]

Scheduled Pinned Locked Moved C#
questiondata-structures
5 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • H Offline
    H Offline
    hain
    wrote on last edited by
    #1

    Weird... unless I'm not understanding something about Regions. I build an array of Region objects (constructed from GraphicsPath objects). When I access any array element (to set the Region property of a control), it works fine the first time, but if I try to access that same element a second time, it gives me an Invalid Parameter exception. It's as if the array is read-once. I work around this by saving an array of RegionData objects, and constructing Regions on-the-fly from elements of this array. Clutzy at best. Does anyone have any insight on what is going on? (Or what I'm doing wrong?) Thanks! Tom -- modified at 17:36 Monday 10th September, 2007

    G 1 Reply Last reply
    0
    • H hain

      Weird... unless I'm not understanding something about Regions. I build an array of Region objects (constructed from GraphicsPath objects). When I access any array element (to set the Region property of a control), it works fine the first time, but if I try to access that same element a second time, it gives me an Invalid Parameter exception. It's as if the array is read-once. I work around this by saving an array of RegionData objects, and constructing Regions on-the-fly from elements of this array. Clutzy at best. Does anyone have any insight on what is going on? (Or what I'm doing wrong?) Thanks! Tom -- modified at 17:36 Monday 10th September, 2007

      G Offline
      G Offline
      Giorgi Dalakishvili
      wrote on last edited by
      #2

      Have you tried debugging? Perhaps you should post some code.

      #region signature my articles #endregion

      H 1 Reply Last reply
      0
      • G Giorgi Dalakishvili

        Have you tried debugging? Perhaps you should post some code.

        #region signature my articles #endregion

        H Offline
        H Offline
        hain
        wrote on last edited by
        #3

        Here's a simple project with a form having one button, and a UserControl. Initially, control looks like a blue circle (as expected). Click the button, sets currRegionIndex to 1, and the control is a blue square (as expected). Click the button again sets currRegionIndex back to 0, and ArgumentException ("Parameter is not valid") results. Weird, huh? ------------------------------------- // Form1.cs using System; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; namespace RegionTest { public partial class Form1 : Form { private Region[] region = new Region[2]; private int currRegionIndex = 1; private MyControl myControl = new MyControl(); public Form1() { InitializeComponent(); GraphicsPath gp0 = new GraphicsPath(); gp0.AddEllipse(myControl.ClientRectangle); region[0] = new Region(gp0); GraphicsPath gp1 = new GraphicsPath(); gp1.AddRectangle(myControl.ClientRectangle); region[1] = new Region(gp1); myControl.Region = region[1]; Controls.Add(myControl); } private void button1_Click(object sender, EventArgs e) { currRegionIndex = (currRegionIndex + 1) % 2; myControl.Region = region[currRegionIndex]; myControl.Refresh(); } } } ------------------------------------- // Mycontrol.cs using System; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; namespace RegionTest { public partial class MyControl : UserControl { public MyControl() { InitializeComponent(); BackColor = Color.Blue; } } } ------------------------------------------------------ Incidentally, I'm using VS2005 Thanks for your help, Tom -- modified at 18:33 Monday 10th September, 2007

        P 1 Reply Last reply
        0
        • H hain

          Here's a simple project with a form having one button, and a UserControl. Initially, control looks like a blue circle (as expected). Click the button, sets currRegionIndex to 1, and the control is a blue square (as expected). Click the button again sets currRegionIndex back to 0, and ArgumentException ("Parameter is not valid") results. Weird, huh? ------------------------------------- // Form1.cs using System; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; namespace RegionTest { public partial class Form1 : Form { private Region[] region = new Region[2]; private int currRegionIndex = 1; private MyControl myControl = new MyControl(); public Form1() { InitializeComponent(); GraphicsPath gp0 = new GraphicsPath(); gp0.AddEllipse(myControl.ClientRectangle); region[0] = new Region(gp0); GraphicsPath gp1 = new GraphicsPath(); gp1.AddRectangle(myControl.ClientRectangle); region[1] = new Region(gp1); myControl.Region = region[1]; Controls.Add(myControl); } private void button1_Click(object sender, EventArgs e) { currRegionIndex = (currRegionIndex + 1) % 2; myControl.Region = region[currRegionIndex]; myControl.Refresh(); } } } ------------------------------------- // Mycontrol.cs using System; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; namespace RegionTest { public partial class MyControl : UserControl { public MyControl() { InitializeComponent(); BackColor = Color.Blue; } } } ------------------------------------------------------ Incidentally, I'm using VS2005 Thanks for your help, Tom -- modified at 18:33 Monday 10th September, 2007

          P Offline
          P Offline
          Patrick Etc
          wrote on last edited by
          #4

          A little smart debugging and a glance in Reflector exposes the problem. If you place a breakpoint at this line: myControl.Region = region[currRegionIndex]; and examine the region array, each Region object has a Non-Public member called "nativeRegion". This is an IntPtr handle to a Win32 Rgn object. The first time you use the region, that IntPtr value is not zero - that is, item != IntPtr.Zero. Once you assign the region to the control, that same value becomes 0. Looking at the code for Control.Region in Reflector exposes why:

          IntPtr zero = IntPtr.Zero;
          try
          {
              if (value != null)
              {
                  zero = this.GetHRgn(value);
              }
              if (this.IsActiveX)
              {
                  zero = this.ActiveXMergeRegion(zero);
              }
              if (UnsafeNativeMethods.SetWindowRgn(new HandleRef(this, this.Handle), new HandleRef(this, zero), SafeNativeMethods.IsWindowVisible(new HandleRef(this, this.Handle))) != 0)
              {
                  zero = IntPtr.Zero;
              }
          }
          finally
          {
              if (zero != IntPtr.Zero)
              {
                  SafeNativeMethods.DeleteObject(new HandleRef(null, zero));
              }
          }
          

          You see what's going on. The region is being deleted once it is used successfully. The solution, then, is to assign a copy of each region instead, using the Region.Clone method:

                  public Form1()
                  {
                      InitializeComponent();
          
                      GraphicsPath gp0 = new GraphicsPath();
                      gp0.AddEllipse(myControl.ClientRectangle);
                      region[0] = new Region(gp0);
          
                      GraphicsPath gp1 = new GraphicsPath();
                      gp1.AddRectangle(myControl.ClientRectangle);
                      region[1] = new Region(gp1);
          
                      myControl.Region = region[1].Clone();
                      Controls.Add(myControl);
                  }
          
                  private void button1_Click(object sender, EventArgs e)
                  {
                      currRegionIndex = (currRegionIndex + 1) % 2;
          
                      myControl.Region = region[currRegionIndex].Clone();
          
                      myControl.Refresh();
                  }
          
          H 1 Reply Last reply
          0
          • P Patrick Etc

            A little smart debugging and a glance in Reflector exposes the problem. If you place a breakpoint at this line: myControl.Region = region[currRegionIndex]; and examine the region array, each Region object has a Non-Public member called "nativeRegion". This is an IntPtr handle to a Win32 Rgn object. The first time you use the region, that IntPtr value is not zero - that is, item != IntPtr.Zero. Once you assign the region to the control, that same value becomes 0. Looking at the code for Control.Region in Reflector exposes why:

            IntPtr zero = IntPtr.Zero;
            try
            {
                if (value != null)
                {
                    zero = this.GetHRgn(value);
                }
                if (this.IsActiveX)
                {
                    zero = this.ActiveXMergeRegion(zero);
                }
                if (UnsafeNativeMethods.SetWindowRgn(new HandleRef(this, this.Handle), new HandleRef(this, zero), SafeNativeMethods.IsWindowVisible(new HandleRef(this, this.Handle))) != 0)
                {
                    zero = IntPtr.Zero;
                }
            }
            finally
            {
                if (zero != IntPtr.Zero)
                {
                    SafeNativeMethods.DeleteObject(new HandleRef(null, zero));
                }
            }
            

            You see what's going on. The region is being deleted once it is used successfully. The solution, then, is to assign a copy of each region instead, using the Region.Clone method:

                    public Form1()
                    {
                        InitializeComponent();
            
                        GraphicsPath gp0 = new GraphicsPath();
                        gp0.AddEllipse(myControl.ClientRectangle);
                        region[0] = new Region(gp0);
            
                        GraphicsPath gp1 = new GraphicsPath();
                        gp1.AddRectangle(myControl.ClientRectangle);
                        region[1] = new Region(gp1);
            
                        myControl.Region = region[1].Clone();
                        Controls.Add(myControl);
                    }
            
                    private void button1_Click(object sender, EventArgs e)
                    {
                        currRegionIndex = (currRegionIndex + 1) % 2;
            
                        myControl.Region = region[currRegionIndex].Clone();
            
                        myControl.Refresh();
                    }
            
            H Offline
            H Offline
            hain
            wrote on last edited by
            #5

            Wow... thanks, Patrick. Hmm, this is not the behaviour one would expect, but who says life should be predictable :sigh:. My workaround was: ----------------------------- using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; namespace RegionTest { public partial class Form1 : Form { RegionData[] regionData = new RegionData[2]; int currRegionIndex = 0; MyControl myControl = new MyControl(); public Form1() { InitializeComponent(); GraphicsPath gp0 = new GraphicsPath(); gp0.AddEllipse(myControl.ClientRectangle); regionData[0] = (new Region(gp0)).GetRegionData(); GraphicsPath gp1 = new GraphicsPath(); gp1.AddRectangle(myControl.ClientRectangle); regionData[1] = (new Region(gp1)).GetRegionData(); myControl.Region = new Region(region[0]); Controls.Add(myControl); } private void button1_Click(object sender, EventArgs e) { currRegionIndex = (currRegionIndex + 1) % 2; myControl.Region = new Region(regionData[currRegionIndex]); myControl.Refresh(); } } } ----------------------------- which in the end is similar to yours in efficiency (I guess) but yours is more elegant. Tom

            1 Reply Last reply
            0
            Reply
            • Reply as topic
            Log in to reply
            • Oldest to Newest
            • Newest to Oldest
            • Most Votes


            • Login

            • Don't have an account? Register

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • World
            • Users
            • Groups