Click here to Skip to main content
15,890,512 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
I'm trying to use StreamGeometry in WPF to create a bunch of random shapes on the fly. I read that this was supposed to give the best performance. Unfortunately, I can't figure out how to change the color on each shape independtly. For example, int the code below:

C#
private void CreateGraphics(){
     int NUM_SHAPES = 100;
     int RECT_MAX_WIDTH = 100;
     int RECT_MAX_HEIGHT = 100;

     StackPanel mainPanel = new StackPanel();

     // Create a StreamGeometry to use to specify myPath.
     StreamGeometry geometry = new StreamGeometry();
     geometry.FillRule = FillRule.EvenOdd;


     using (StreamGeometryContext context = geometry.Open())
     {

         for (int i = 0; i < NUM_SHAPES; i++)
         {

             // Create a path to draw a geometry with.
             Path myPath = new Path();

             // Get random height, width, position, and color.
             double width = RECT_MAX_WIDTH * RAND.NextDouble();
             double height = RECT_MAX_HEIGHT * RAND.NextDouble();
             int x = (int)(SCREEN_WIDTH * RAND.NextDouble());
             int y = (int)(SCREEN_HEIGHT * RAND.NextDouble());

             // Create a color.
             int fill_color_num = RAND.Next(1, MAX_COLORS);
             Color fill_color = Color.FromArgb(0xFF, //alpha
                             (byte)(fill_color_num & 0xFF), //red
                             (byte)((fill_color_num >> 8) & 0xFF), //green
                             (byte)((fill_color_num >> 16) & 0xFF)); //blue
             int edge_color_num = RAND.Next(1, MAX_COLORS);
             Color edge_color = Color.FromArgb(0xFF, //alpha
                             (byte)(edge_color_num & 0xFF), //red
                             (byte)((edge_color_num >> 8) & 0xFF), //green
                             (byte)((edge_color_num >> 16) & 0xFF)); //blue

             myPath.StrokeThickness = 2;
             //myPath.Stroke = Brushes.Black;
             //myPath.Fill = Brushes.Yellow;
             myPath.Stroke = new SolidColorBrush(edge_color);
             myPath.Fill = new SolidColorBrush(fill_color);

             // Set Edges.
             int left_edge = x - (int)(width / 2);
             int right_edge = x + (int)(width / 2);
             int top_edge = y - (int)(height / 2);
             int bottom_edge = y + (int)(height / 2);
             if (left_edge < 0) { left_edge = 0; }
             if (right_edge > SCREEN_WIDTH) { right_edge = SCREEN_WIDTH; }
             if (top_edge < 0) { top_edge = 0; }
             if (bottom_edge > SCREEN_HEIGHT) { bottom_edge = SCREEN_HEIGHT; }

             // Begin the triangle at the point specified. Notice that the shape is set to
             // be closed so only two lines need to be specified below to make the triangle.
             context.BeginFigure(new Point(left_edge, bottom_edge), true /*isFilled*/, true /*isClosed*/);

             // Draw a line to the next specified point.
             //context.LineTo(new Point(left_edge, top_edge), true /* is stroked */, false /* is smooth join */);
             context.LineTo(new Point(left_edge, top_edge), true /*isStroked*/, true /*isSmoothJoin*/);

             // Draw another line to the next specified point.
             //context.LineTo(new Point(right_edge, top_edge), true /* is stroked */, false /* is smooth join */);
             context.LineTo(new Point(right_edge, top_edge), true /*isStroked*/, true /*isSmoothJoin*/);

             // Draw another line to the next specified point.
             //context.LineTo(new Point(right_edge, bottom_edge), true /* is stroked */, false /* is smooth join */);
             context.LineTo(new Point(right_edge, bottom_edge), true /*isStroked*/, true /*isSmoothJoin*/);

             // Freeze the geometry (make it unmodifiable)
             // for additional performance benefits.
             geometry.Freeze();

             // Specify the shape (triangle) of the Path using the StreamGeometry.
             myPath.Data = geometry;

             // Add path shape to the UI.
             mainPanel.Children.Add(myPath);
         }
     }

    this.Content = mainPanel;
}


I was expecting that by setting the Path.Fill and Path.Stroke properties, that I would get different colors for each rectangle. It seems that I only get the last defined color applied to all the rectangles. Does anyone know how to set unique colors for each rectangle?

EDIT: I tried placing the StreamGeometry object declaration inside the for loop, as one user suggested. For some reason I only get 2 shapes. Here is the code:

C#
private void CreateGraphics()
 {
     int NUM_SHAPES = 3;
     int RECT_MAX_WIDTH = 100;
     int RECT_MAX_HEIGHT = 100;
     StackPanel mainPanel = new StackPanel();

     for (int i = 0; i < NUM_SHAPES; i++)
     {

         // Create a StreamGeometry to use to specify myPath.
         StreamGeometry geometry = new StreamGeometry();
         geometry.FillRule = FillRule.EvenOdd;

         using (StreamGeometryContext context = geometry.Open())
         {

                 // Create a path to draw a geometry with.
             Path myPath = new Path();

             // Get random height, width, position, and color.
             double width = RECT_MAX_WIDTH * RAND.NextDouble();
             double height = RECT_MAX_HEIGHT * RAND.NextDouble();
             int x = (int)(SCREEN_WIDTH * RAND.NextDouble());
             int y = (int)(SCREEN_HEIGHT * RAND.NextDouble());

             // Create a color.
             int fill_color_num = RAND.Next(1, MAX_COLORS);
             Color fill_color = Color.FromArgb(0xFF, //alpha
                             (byte)(fill_color_num & 0xFF), //red
                             (byte)((fill_color_num >> 8) & 0xFF), //green
                             (byte)((fill_color_num >> 16) & 0xFF)); //blue
             int edge_color_num = RAND.Next(1, MAX_COLORS);
             Color edge_color = Color.FromArgb(0xFF, //alpha
                             (byte)(edge_color_num & 0xFF), //red
                             (byte)((edge_color_num >> 8) & 0xFF), //green
                             (byte)((edge_color_num >> 16) & 0xFF)); //blue

             myPath.StrokeThickness = 2;
             //myPath.Stroke = Brushes.Black;
             //myPath.Fill = Brushes.Yellow;
             myPath.Stroke = new SolidColorBrush(edge_color);
             myPath.Fill = new SolidColorBrush(fill_color);

             // Set Edges.
             int left_edge = x - (int)(width / 2);
             int right_edge = x + (int)(width / 2);
             int top_edge = y - (int)(height / 2);
             int bottom_edge = y + (int)(height / 2);
             if (left_edge < 0) { left_edge = 0; }
             if (right_edge > SCREEN_WIDTH) { right_edge = SCREEN_WIDTH; }
             if (top_edge < 0) { top_edge = 0; }
             if (bottom_edge > SCREEN_HEIGHT) { bottom_edge = SCREEN_HEIGHT; }

             // Begin the triangle at the point specified. Notice that the shape is set to
             // be closed so only two lines need to be specified below to make the triangle.
             context.BeginFigure(new Point(left_edge, bottom_edge), true /*isFilled*/, true /*isClosed*/);

             // Draw a line to the next specified point.
             //context.LineTo(new Point(left_edge, top_edge), true /* is stroked */, false /* is smooth join */);
             context.LineTo(new Point(left_edge, top_edge), true /*isStroked*/, true /*isSmoothJoin*/);

             // Draw another line to the next specified point.
             //context.LineTo(new Point(right_edge, top_edge), true /* is stroked */, false /* is smooth join */);
             context.LineTo(new Point(right_edge, top_edge), true /*isStroked*/, true /*isSmoothJoin*/);

             // Draw another line to the next specified point.
             //context.LineTo(new Point(right_edge, bottom_edge), true /* is stroked */, false /* is smooth join */);
             context.LineTo(new Point(right_edge, bottom_edge), true /*isStroked*/, true /*isSmoothJoin*/);

             // Freeze the geometry (make it unmodifiable)
             // for additional performance benefits.
             geometry.Freeze();

             // Specify the shape (triangle) of the Path using the StreamGeometry.
             myPath.Data = geometry;

             // Add path shape to the UI.
             mainPanel.Children.Add(myPath);
         }
     }

    this.Content = mainPanel;
 }
Posted
Updated 16-Apr-11 12:31pm
v3

1 solution

You're using the same geometry object for all the Path objects, the last one will stay on top of the others and you will only see that one which is making you think that all the Path are using the same colour.
 
Share this answer
 
Comments
weylspinor 16-Apr-11 18:07pm    
If I try to put the StreamGeometry declaration inside the loop, so that a new StreamGeometry object is declared on every iteration of the loop, the program only shows 2 shapes. It seems like it won't allow more than 1-2 StreamGeometry objects.
Fabio V Silva 16-Apr-11 18:24pm    
Works fine for me...
Can you post your code after the editing?
weylspinor 16-Apr-11 18:42pm    
Hi, thanks. I added the edited code.
Fabio V Silva 16-Apr-11 18:51pm    
I'm using the default window size and I can only see two shapes when I load it but I can see more if I expand the window.
You are using a StackPanel which is stacking your shapes downwards in rectangles of up to RECT_MAX_HEIGHT height, if you change the mainPanel to, for example a Grid, you'll see all the Path objects inside the RECT_MAX_WIDTH x RECT_MAX_HEIGHT rectangle.
weylspinor 16-Apr-11 20:12pm    
That works! Thanks!

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900