Problems with custom canvas - c#

I tried to write my own custom Canvas and wanted to draw a little labyrinth which consist of little rectangles. My Problem is, that I just get 4 little points on my screen and not 4 Rectangles (when trying it with a 2 X 2 field).
Here is some Code:
public class LabyrinthCanvas : System.Windows.Controls.Canvas
{
public static readonly int RectRadius = 60;
public ObservableCollection<ObservableCollection<Rect>> Rectangles;
public LabyrinthCanvas()
{
Rectangles = new ObservableCollection<ObservableCollection<Rect>>();
}
public void AddRectangles(int Height, int Width)
{
for (int iHeight = 0; iHeight < Height; iHeight++)
{
ObservableCollection<Rect> newRects = new ObservableCollection<Rect>();
newRects.CollectionChanged += RectanglesChanged;
Rectangles.Add(newRects);
for (int iWidth = 0; iWidth < Width; iWidth++)
{
Rect rect = new Rect(iHeight * RectRadius, iWidth * RectRadius);
Rectangles[iHeight].Add(rect);
}
}
}
public void RectanglesChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
{
foreach (object rect in e.NewItems)
{
if (rect is Rect)
{
this.Children.Add(((Rect)rect).innerRectangle);
System.Windows.Controls.Canvas.SetTop(((Rect)rect).innerRectangle, ((Rect)rect).YPos);
System.Windows.Controls.Canvas.SetLeft(((Rect)rect).innerRectangle, ((Rect)rect).XPos);
}
}
}
else if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
{
foreach (Rect rect in e.OldItems)
{
this.Children.Remove(rect.innerRectangle);
}
}
}
}
public class Rect : INotifyPropertyChanged
{
public Rect(int YPos, int XPos)
{
innerRectangle.Stroke = System.Windows.Media.Brushes.Black;
innerRectangle.Fill = System.Windows.Media.Brushes.Blue;
this.YPos = YPos;
this.XPos = XPos;
}
public System.Windows.Shapes.Rectangle innerRectangle = new System.Windows.Shapes.Rectangle();
public int YPos;
public int XPos;
}
I think the important thing is that:
this.Children.Add(((Rect)rect).innerRectangle);
System.Windows.Controls.Canvas.SetTop(((Rect)rect).innerRectangle, ((Rect)rect).YPos);
System.Windows.Controls.Canvas.SetLeft(((Rect)rect).innerRectangle, ((Rect)rect).XPos);
Im using a own Class "Rect" because i need some extra properties which i removed from the shown code and I cant inherit from Rectangle.

I'm not entirely sure what you want your end result to look like, so I probably won't be able to suggest the exact solution you're after.
That said, the reason you're obtaining small points on your screen, rather than rectangles, is because the canvas is rendering the innerRectangle of your Rect object, at the specified coordinates, but you're never initialising setting the dimensions of that innerRectangle.
The dots you're seeing are those width/heightless rectangles, which are having the Black stroke rendered (the dot).
You can see what's going on if you try something along these lines:
public System.Windows.Shapes.Rectangle innerRectangle = new System.Windows.Shapes.Rectangle() { Width = 10, Height = 10 };

Related

Drag Over PictureBox over other PictureBox with transparency

I would like to design a chess board and drag over pieces (shown in pictureBox Controls) all child of the main board (pictureBox1).
Problem I encounter is the transparency is only set to the Parent pictureBox1.
Which shows this effect: The square is showing.
private void CommonPiece_Mouse_Move(object sender, MouseEventArgs e)
{
if (Piece_Selected)
{
int MousePositionX = pictureBox1.PointToClient(Cursor.Position).X;
int MousePositionY = pictureBox1.PointToClient(Cursor.Position).Y;
(sender as PictureBox).Left = MousePositionX - 35;
(sender as PictureBox).Top = MousePositionY - 25;
}
}
What would be a good way to go about it?
There are several solutions for this problem. The one in the following screen recording, is based on drawing png images as movable shapes; it uses the idea that I've explained in How to drag and move shapes in C#. Basically there's only one control -the drawing surface, and all the other stuff are movable drawings.
You can use any image for the pieces by passing an Image to the ImageShape
You can modify the size of the Pieces by setting Height of the shape
It supports snapping to the grid
You can customize the texture, easily by setting the BackgroundImage of the drawing surface
You can change the grid size, by setting GridSize property of the drawing surface
You can change the Color of White and Grid grids, by assigning the color to WhiteColor and BlackColor
It's of course a quick example showing how to draw movable objects, including png images keeping their transparency. You know how to improve it :)
Drawing and moving shapes - Chess pieces
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Linq;
using System.Windows.Forms;
public interface IShape
{
bool HitTest(Point p);
void Draw(Graphics g);
void Move(int dx, int dy);
Point Location { get; set; }
}
public class ImageShape : IShape
{
public int Height { get; set; } = 100;
public Point Location { get; set; }
private Image _image;
public ImageShape(Image image)
{
_image = image;
}
public void Draw(Graphics g)
{
var r = new Rectangle(Location, new Size(Height, Height));
r.Inflate(-5, -5);
g.DrawImage(_image, r);
}
public bool HitTest(Point p)
{
return new Rectangle(Location, new Size(Height, Height)).Contains(p);
}
public void Move(int dx, int dy)
{
Location = new Point(Location.X + dx, Location.Y + dy);
}
}
public class DrawingSurface : Control
{
public List<IShape> Shapes { get; private set; }
public int GridSize { get; set; } = 100;
public Color WhiteColor = Color.FromArgb(200, Color.White);
public Color BlackColor = Color.FromArgb(120, Color.Black);
IShape selectedShape;
bool moving;
Point previousPoint = Point.Empty;
public DrawingSurface()
{
DoubleBuffered = true;
ResizeRedraw = true;
Shapes = new List<IShape>();
}
protected override void OnMouseDown(MouseEventArgs e)
{
for (var i = Shapes.Count - 1; i >= 0; i--)
if (Shapes[i].HitTest(e.Location))
{
selectedShape = Shapes[i];
break;
}
if (selectedShape != null)
{
moving = true;
previousPoint = e.Location;
Invalidate();
}
base.OnMouseDown(e);
}
protected override void OnMouseMove(MouseEventArgs e)
{
if (moving)
{
var dx = e.X - previousPoint.X;
var dy = e.Y - previousPoint.Y;
selectedShape.Move(dx, dy);
previousPoint = e.Location;
this.Invalidate();
}
base.OnMouseMove(e);
}
protected override void OnMouseUp(MouseEventArgs e)
{
if (moving)
{
int i = (e.X / GridSize) * GridSize;
int j = (e.Y / GridSize) * GridSize;
selectedShape.Location = new Point(i, j);
selectedShape = null;
moving = false;
this.Invalidate();
}
base.OnMouseUp(e);
}
protected override void OnPaint(PaintEventArgs e)
{
var g = e.Graphics;
g.InterpolationMode = InterpolationMode.High;
g.SmoothingMode = SmoothingMode.HighQuality;
g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
g.CompositingQuality = CompositingQuality.HighQuality;
foreach (var shape in Shapes.Except(new[] { selectedShape }))
shape.Draw(g);
if (selectedShape != null)
selectedShape.Draw(g);
}
protected override void OnPaintBackground(PaintEventArgs e)
{
base.OnPaintBackground(e);
var g = e.Graphics;
using (var w = new SolidBrush(WhiteColor))
using (var b = new SolidBrush(BlackColor))
for (int i = 0; i < 8; i++)
for (int j = 0; j < 8; j++)
g.FillRectangle((i + j) % 2 == 0 ? b : w,
i * GridSize, j * GridSize, GridSize, GridSize);
}
}
To add pieces:
private void Form1_Load(object sender, EventArgs e)
{
this.drawingSurface1.Shapes.Add(new ImageShape(
Properties.Resources.KingWhite) { Location = new Point(0, 0) });
this.drawingSurface1.Shapes.Add(
new ImageShape(Properties.Resources.kingBlack) { Location = new Point(0, 100) });
}
Here's an example that makes the PictureBox Non-Rectangular. The PB will literally not exist where the transparent areas were:
using System.Runtime.InteropServices;
namespace CS_Scratch_WindowsFormsApp2
{
public partial class Form1 : Form
{
public const int HT_CAPTION = 0x2;
public const int WM_NCLBUTTONDOWN = 0xA1;
[System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
public static extern bool ReleaseCapture();
[System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
public Form1()
{
InitializeComponent();
pbChessPiece.MouseMove += PbChessPiece_MouseMove;
}
private void PbChessPiece_MouseMove(object sender, MouseEventArgs e)
{
PictureBox pb = (PictureBox)sender;
if (!DesignMode && e.Button == MouseButtons.Left)
{
ReleaseCapture();
SendMessage(pb.Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
}
}
private void button1_Click(object sender, EventArgs e)
{
Bitmap bmp = (Bitmap)pbChessPiece.Image;
Region rgn = new Region();
rgn.Union(new Rectangle(0, 0, bmp.Width, bmp.Height));
for(int x=0; x<bmp.Width; x++)
{
for(int y=0; y<bmp.Height; y++)
{
if (bmp.GetPixel(x, y).A == 0)
{
rgn.Exclude(new Rectangle(x, y, 1, 1));
}
}
}
pbChessPiece.Region = rgn;
}
}
}
Example run:
I did something similar, but I did not use Drag & Drop events
On MouseDown I assumed a drag operation started, I've opened a translucent unfocused window on top of the drop area, and started drawing dragged image on that form. Since the form is translucent it can show images with transparency on top of everything. I did not use images, but instead draw rectangles where users could drop. If my memory serves me correct, MouseMove events are forwarded to the dragged component, the original chess piece in your case, or the opened but unfocused form, so I can easily track the location. On MouseUp event I wrapped everything.
Since you can draw the image on the new form you can tilt image chess piece image to the left or right for a nice touch.
I developed a very strict forms designer application using this technique.
You can use the panel instead of using the pictureBox and display the image in the background of the controls. Remember that your images must be "png" and the surrounding of the image must be completely transparent. Also, the background color of the controls of the panels Set by events so that it becomes transparent during drag and returns to the cell color after drag and drop.
Good luck.

DrawLine method doesn't work when using inside a loop

I'm trying to make a program that is able to read a dxf file and plot it's contents but when I try to draw the figures in the window's paint event, nothing is drawn unless I use this.Invalidate(); and this doesn't completely work because the objects appear to blink on the screen. The coordinates to draw the lines are stored in a list declared in the window class.
private void InitialWindow_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
Pen blackPen = new Pen(Color.Black, 1);
if (entities.Count != 0)
{
for (int i = 0; i < entities.Count; i++)
{
for (int k = 0; k < entities[i].path.Count - 1; k++)
{
g.DrawLine(blackPen, D2F(entities[i].path[k]), D2F(entities[i].path[k + 1]));
}
g.DrawLine(blackPen, D2F(entities[i].path[0]), D2F(entities[i].path.Last()));
}
}
}
2DF is a function that converts a point-like type of data to PointF so it can be used in DrawLine. If I try to draw outside the for loops the lines are displayed correctly on the screen. Thanks in advance for any help with it.
I suggest you create a class to handle the model-to-pixel conversions (and in reverse) instead of a function D2F(). A class it going to give you a lot more flexibility and it will retain a state of the current scaling values
public class Canvas
{
public Canvas()
{
Target = new Rectangle(0, 0, 1, 1);
Scale = 1;
}
public Rectangle Target { get; set; }
public float Scale { get; set; }
public void SetModelBounds(float width, float height)
{
Scale = Math.Min(Target.Width / width, Target.Height / height);
}
public PointF ToPixel(Vector2 point)
{
var center = new PointF(Target.Left + Target.Width / 2, Target.Top + Target.Height / 2);
return new PointF(center.X + Scale * point.X, center.Y - Scale * point.Y);
}
public Vector2 FromPixel(Point pixel)
{
var center = new PointF(Target.Left + Target.Width / 2, Target.Top + Target.Height / 2);
return new Vector2((pixel.X - center.X) / Scale, -(pixel.Y - center.Y) / Scale);
}
}
This is setup for each paint event by calling for example
Canvas.Target = this.ClientRectangle;
Canvas.SetModelBounds(2f, 2f);
The above code is going to place coordinates (-1,-1) on the bottom left of the form surface, and (1,1) on the top right. The pixels per model unit are kept the same for x-axis and y-axis (see Canvas.Scale).
Now for the drawing, also use am Entity class to hold the drawing geometry, and various other properties such as color, and if the shape is closed or not. Note that if it defines a Render(Graphics g, Canvas canvas) method, then it can be called by the form and each entity can handle its own drawing (for the most modular design)
Here is an example:
public class Entity
{
Entity(bool closed, Color color, params Vector2[] path)
{
Color = color;
Path = new List<Vector2>(path);
Closed = closed;
}
public Color Color { get; set; }
public List<Vector2> Path { get; }
public bool Closed { get; set; }
public void Render(Graphics g, Canvas canvas)
{
using (Pen pen = new Pen(Color, 1))
{
var points = Path.Select(pt => canvas.ToPixel(pt)).ToArray();
if (Closed)
{
g.DrawPolygon(pen, points);
}
else
{
g.DrawLines(pen, points);
}
}
}
public static Entity Triangle(Color color, Vector2 center, float width, float height)
{
return new Entity(true, color, new Vector2[] {
new Vector2(center.X-width/2, center.Y - height/3),
new Vector2(center.X+width/2, center.Y - height/3),
new Vector2(center.X, center.Y+2*height/3) });
}
public static Entity Rectange(Color color, Vector2 center, float width, float height)
{
return new Entity(true, color, new Vector2[] {
new Vector2(center.X-width/2, center.Y-height/2),
new Vector2(center.X+width/2, center.Y-height/2),
new Vector2(center.X+width/2, center.Y+height/2),
new Vector2(center.X-width/2, center.Y+height/2) });
}
public static Entity Polygon(Color color, params Vector2[] path)
=> new Entity(true, color, path);
public static Entity Polyline(Color color, params Vector2[] path)
=> new Entity(false, color, path);
}
The above is used in the form as follows
public partial class Form1 : Form
{
public Canvas Canvas { get; }
public List<Entity> Entities { get; }
public Form1()
{
InitializeComponent();
Entities = new List<Entity>();
Canvas = new Canvas();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.Resize += (s, ev) => Invalidate();
this.Paint += (s, ev) =>
{
ev.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
Canvas.Target = ClientRectangle;
Canvas.SetModelBounds(2f, 2f);
foreach (var item in Entities)
{
item.Render(ev.Graphics, Canvas);
}
};
Entities.Add( .. )
}
}
As you can see the Paint event calls the Render() method for each entity.
In fact, you can generalize this model using an interface IRender. In the example below besides Entity that implements the interface, I define a class to draw the coordinate axis called Axes.
public interface IRender
{
void Render(Graphics g, Canvas canvas);
}
public class Axes : IRender
{
public void Render(Graphics g, Canvas canvas)
{
PointF origin = canvas.ToPixel(Vector2.Zero);
PointF xpoint = canvas.ToPixel(Vector2.UnitX);
PointF ypoint = canvas.ToPixel(Vector2.UnitY);
using (Pen pen = new Pen(Color.Black, 0))
{
pen.CustomEndCap = new AdjustableArrowCap(2f, 5f);
g.DrawLine(pen, origin, xpoint);
g.DrawLine(pen, origin, ypoint);
}
}
}
public class Entity : IRender
{
...
}
and now you can draw with quite a bit of varying things on the screen with the above framework. Here is an example that draws the axis (of unit size) and a few sample entities.
Entities.Add(Entity.Polygon(Color.Orange, Vector2.Zero, -Vector2.UnitX, -Vector2.One));
Entities.Add(Entity.Rectange(Color.Blue, new Vector2(0.5f, 0.5f), 0.25f, 0.25f));
Entities.Add(Entity.Triangle(Color.Red, new Vector2(0.5f, 0.75f), 0.25f, 0.25f));
Entities.Add(Entity.Polyline(Color.Magenta,
new Vector2(0f, -0.2f), new Vector2(0f, -0.4f), new Vector2(0.2f, -0.4f),
new Vector2(0.2f, -0.2f), new Vector2(0.4f, -0.2f), new Vector2(0.4f, -0.4f)));

Cannot modify the return value of a collection of rectangles

Here's what I used to solve this problem:
public class Snake {
List<Rectangle> bodyParts = new List<Rectangle>();
}
Snake snk = new Snake();
snk.bodyParts.Add(new Rectangle(760,25,8,8))
//the Exception Occurs here
//snk.bodyParts[0].Y = snk.bodyPArts[0].Y-10;
//Here's my approach
snk.bodyParts[0] = new Rectangle(bodyParts[0].X,bodyParts[0].Y-10,8,8);
Exception: Cannot modify the return value of 'System.Collections.Generic.List.this[int]'
My question is: Are they any alternative/better ways to manage this exception ?
Thanks.
EDIT: I got my answer, can you please close this question.
Rather than working directly with Rectangles, how about adding a BodyPart class, with some manipulation methods:
public class BodyPart
{
private Rectangle rectangle;
public BodyPart(Rectangle rectangle)
{
this.rectangle = rectangle;
}
public void MoveY(int value)
{
rectangle.Y += value;
}
public void MoveX(int value)
{
rectangle.X += value;
}
}
public class Snake
{
public List<BodyPart> Parts = new List<BodyPart>();
}
public class AppSnake
{
public void Run()
{
var snake = new Snake();
snake.Parts.Add(new BodyPart(new Rectangle(760, 25, 8, 8)));
snake.Parts[0].MoveY(-10);
}
}
Rectangle, RectangleF, Point, PointF, Size and SizeF are value types (struct type). This means that you can not/should not change an individual part of the structure.
The reason is that unlike classes each variable keeps its own copy of the structure. When you type list[0].X = 10, the indexer list[0] returns a copy of the rectangle and not the original value. The correct way is to assign a new rectangle list[0] = A which copies all the values from A into the array.
Please read more on value types and structs before attempting to write code that uses them.
The quickest way to fix your code without completely changing it around is by adding methods that manipulate all the body parts in predefined ways:
public class Snake
{
public List<Rectangle> Parts { get; } = new List<Rectangle>();
public void MoveX(int delta)
{
for(int i = 0; i < Parts.Count; i++)
{
// Read the current rectangle from the list
var rect = Parts[i];
// Change the coordinate.
rect.X += delta;
// Write the modified rectangle back into the list
Parts[i] = rect;
}
}
public void MoveY(int delta)
{
for(int i = 0; i < Parts.Count; i++)
{
// Read the current rectangle from the list
var rect = Parts[i];
// Change the coordinate.
rect.Y += delta;
// Write the modified rectangle back into the list
Parts[i] = rect;
}
}
}
Use Rectangle.Location and Rectanagle.Size properties e.g.:
snk.bodyParts[0].Location = new Point(newX, newY);
snk.bodyParts[0].Size = new Size(newWidth, newHeight);

Control not drawn on panel

I'm trying to add a control to my Panel. At mouseDown on the panel the point is saved and at mouseUp the point is saved. But at panel mouseUp nothing is drawn. How to solve it?
Ellipse class:
class Ellipse : Control
{
private int x;
private int y;
private int width;
private int height;
public Ellipse(int x, int y, int width, int height)
{
setY(y);
setX(x);
setWidth(width);
setHeight(height);
}
public int getX() { return x;}
public int getY() { return y; }
public int getWidth() { return width; }
public int getHeight() { return height; }
public void setX(int newx) { x = newx; }
public void setY(int newy) { y = newy; }
public void setWidth(int newwidth) { width = newwidth; }
public void setHeight(int newheight) { height = newheight; }
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
// Call methods of the System.Drawing.Graphics object.
// Declare and instantiate a new pen.
System.Drawing.Pen myPen = new System.Drawing.Pen(Color.Aqua);
// Draw an aqua rectangle in the rectangle represented by the control.
e.Graphics.FillEllipse(Brushes.Black,x,y,width,height);
}
}
Form1 class
private void panel_MouseDown(object sender, MouseEventArgs e)
{
draw = true;
x = e.X;
y = e.Y;
}
private void panel_MouseUp(object sender, MouseEventArgs e)
{
draw = false;
xe = e.X;
ye = e.Y;
Item item;
Enum.TryParse<Item>(menuComboBoxShape.ComboBox.SelectedValue.ToString(), out item);
switch (item)
{
case Item.Pencil:
using (Graphics g = panel.CreateGraphics())
using (var pen = new Pen(System.Drawing.Color.Black)) //Create the pen used to draw the line (using statement makes sure the pen is disposed)
{
g.DrawLine(pen,new Point(x, y), new Point(xe, ye));
}
break;
case Item.Rectangle:
break;
case Item.Ellipse:
Ellipse el = new Ellipse(x,y,xe-x,ye-y);
panel.Controls.Add(el);
break;
default:
break;
}
}
You are inheriting your Ellipse class from Control, but in fact you're not using it as a control - you're not adding it in Controls collection of form, so in fact it is invisible, inactive and not receiving any events from form.
Also painting the control from outer code looks like a bad design. Control should paint itself, and you should set it bounds from outer code.
Here is snippet to drive you to the right way:
class Ellipse : Control
{
Point mDown { get; set; }
public Ellipse()
{
MouseDown += shape_MouseDown;
MouseMove += shape_MouseMove;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.FillEllipse(Brushes.Black, this.Bounds);
}
private void shape_MouseDown(object sender, MouseEventArgs e)
{
mDown = e.Location;
}
private void shape_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Location = new Point(e.X + Left - mDown.X, e.Y + Top - mDown.Y);
}
}
}
And in the form you should create it like:
el = new Ellipse();
el.Bounds = new Rectangle(0, 0, 100, 100);
Controls.Add(el);
Update
Based on your updated code, I can see a couple of issues:
You actually don't need x, y, width, height properties of your Ellipse class and according getter/setter methods, since it's Control, and it has its own Location and Width, Height public properties.
You are drawing your ellipse incorrectly. Assuming it should fill all the area, painting should be e.Graphics.FillEllipse(Brushes.Black,0,0,Width,Height) (here I assuming using Control.Width instead of your width and so on). Otherwise you're additionally shifting your painted ellipse.
Code in panel_MouseUp concerning ellipse creation should be something like
var el = new Ellipse();
panel.Controls.Add(el);
el.Location = new Point(x, y);
el.Width = (xe - x);
el.Height = (ye - y);
Or, if it should be one single ellipse (right now you're creating new one each time) - create this one outside of mouseUp handler and inside of handler just change it's size and location.

Can't paint 2 of the same control on winForm

I'm making a simple game in winform (tic-tac-toe), and I'm having some problem to paint block control.
Here is the class I made, that represent a block in the game (without game logic, is only UI).
public class UI_Block : Control
{
private Rectangle block;
private SIGNS sign;
public SIGNS Sign
{
get {return sign;}
set
{
if (sign == SIGNS.EMPTY)
sign = value;
}
}
public UI_Block( ) {
sign = SIGNS.EMPTY;
}
public void SetBlockOnBoard(int x, int y)
{
this.Location = new Point( x , y );
this.Size = new Size(Parent.Width /3, Parent.Height / 3);
block = new Rectangle(this.Location, this.Size);
}
public void DrawSign(Graphics g)
{
Pen myPen = new Pen(Color.Red);
if (sign == SIGNS.O)
{
drawO(g,new Pen(Brushes.Black));
}
if (sign == SIGNS.X)
{
drawX(g, new Pen(Brushes.Red));
}
}
protected override void OnPaint(PaintEventArgs e)
{
DrawSign(e.Graphics);
base.OnPaint(e);
}
//Draw X
private void drawX(Graphics g, Pen myPen)
{
//draw first daignol
Point daignolStart = new Point { X = this.Location.X , Y = this.Location.Y };
Point daignolEnd = new Point { X = this.Size.Width , Y = this.Size.Height };
g.DrawLine(myPen, daignolStart, daignolEnd);
//draw second daignol
daignolStart = new Point { X = Size.Width , Y = this.Location.Y };
daignolEnd = new Point { X = Location.X, Y = Size.Height };
g.DrawLine(myPen, daignolEnd, daignolStart);
}
//Draw O
private void drawO(Graphics g, Pen myPen)
{
g.DrawEllipse(myPen, block);
}
}
I added them both to the winForm class and to see how it looks like when I paint them:
public partial class Form1 : Form
{
UI.UI_Block block;
UI.UI_Block blockX;
public Form1()
{
InitializeComponent();
block = new UI.UI_Block();
blockX = new UI.UI_Block();
Controls.Add(block);
Controls.Add(blockX);
}
protected override void OnLoad(EventArgs e)
{
block. SetBlockOnBoard(0, 0);
blockX.SetBlockOnBoard(0, block.Height);
block.Sign = SIGNS.X;
blockX.Sign = SIGNS.O;
base.OnLoad(e);
}
protected override void OnPaint(PaintEventArgs e)
{
//block.DrawSign(e.Graphics);
//block.DrawSign(e.Graphics);
base.OnPaint(e);
}
}
I tried few things, like not using the onPaint event and I still get the same result.
Here what I see when I run it:
Any idea why I can't paint both of them?
You are not drawing the contents of your control in it's visible area, so it is drawing fine but you can't see it.
Every control has it's own coordinate space (client coords), which starts at 0,0 regardless of where it is positioned within the parent control. You are placing the control in it's parent correctly by setting its Location, but then you are also using the Location to offset the graphics, so they are essentially offset twice.
(If you make your control bigger you'll be able to see the X being drawn further down the screen)
To fix this, do all your drawing in the client coordinate space of your control, i.e. draw in the area (0, 0, width, height)
(P.S. You could just draw all 9 tiles in the parent control, which is a more efficient approach than creating 9 child controls. But what you are doing will work fine)

Categories

Resources