Multi-threading with TPL - Access Internal Class Properties - c#

I am using the TPL library to parallelize a 2D grid operation. I have extracted a simple example from my actual code to illustrate what I am doing. I am getting the desired results I want and my computation times are sped up by the number of processors on my laptop (12).
I would love to get some advice or opinions on my code as far as how my properties are declared. Again, it works as expected, but wonder if the design could be better. Thank you in advance.
My simplified code:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Gridding
{
public abstract class Base
{
/// <summary>
/// Values representing the mesh values where each node in the gridis assigned som value.
/// </summary>
public float[,] Values { get; set; }
public abstract void Compute();
}
public class Derived : Base
{
/// <summary>
/// Make the mesh readonly. Is this necessary?
/// </summary>
readonly Mesh MyMesh;
Derived(Mesh mesh)
{
MyMesh = mesh;
}
public override void Compute()
{
Values = new float[MyMesh.NX, MyMesh.NY];
double[] xn = MyMesh.GetXNodes();
double[] yn = MyMesh.GetYNodes();
/// Paralellize the threads along the columns of the grid using the Task Paralllel Library (TPL).
Parallel.For(0, MyMesh.NX, i =>
{
Run(i, xn, yn);
});
}
private void Run(int i, double[] xn, double[] yn)
{
/// Some long operation that parallelizes along the columns of a mesh/grid
double x = xn[i];
for (int j = 0; j < MyMesh.NY; j++)
{
/// Again, longer operation here
double y = yn[j];
double someValue = Math.Sqrt(x * y);
Values[i, j] = (float)someValue;
}
}
static void Main(string[] args)
{
int nx = 100;
int ny = 120;
double x0 = 0.0;
double y0 = 0.0;
double width = 100;
double height = 120;
Mesh mesh = new Mesh(nx, ny, x0, y0, width, height);
Base tplTest = new Derived(mesh);
tplTest.Compute();
float[,] values = tplTest.Values;
Console.Read();
}
/// <summary>
/// A simple North-South oriented grid.
/// </summary>
class Mesh
{
public int NX { get; } = 100;
public int NY { get; set; } = 150;
public double XOrigin { get; set; } = 0.0;
public double YOrigin { get; set; } = 0.0;
public double Width { get; set; } = 100.0;
public double Height { get; set; } = 150.0;
public double DX { get; }
public double DY { get; }
public Mesh(int nx, int ny, double xOrigin, double yOrigin, double width, double height)
{
NX = nx;
NY = ny;
XOrigin = xOrigin;
YOrigin = yOrigin;
Width = width;
Height = height;
DX = Width / (NX - 1);
DY = Height / (NY - 1);
}
public double[] GetYNodes()
{
double[] yNodeLocs = new double[NY];
for (int i = 0; i < NY; i++)
{
yNodeLocs[i] = YOrigin + i * DY;
}
return yNodeLocs;
}
public double[] GetXNodes()
{
double[] xNodeLocs = new double[NX];
for (int i = 0; i < NX; i++)
{
xNodeLocs[i] = XOrigin + i * DX;
}
return xNodeLocs;
}
}
}
}

With only 100 to 150 array elements, parallelism setup overhead would offset the gains. You could cache the result of GetXNodes() and GetYNodes() and invalidate the cached values when XOrigin, NX, YOrigin or NY are modified.

Related

List objects into new list that is property of an new item [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 4 years ago.
So in a few words i'm getting an error whenever i run this
System.NullReferenceException
Ball.boxContent.get returned null
i get this error on this line
box1.Content.Add(Myballs[5]);
what I'm doing is creating balls of different colors,weight and material
adding them into a list called MyBalls
then
adding them from that list into a box(that has a property that is a list called Content)
after this is done I'm supposed to call some of the box function and calculate the weight and print what is inside. Not yet reached this stage as i cannot
any help would be greatly appreciated
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
namespace Ball
{
class Ball
{
private string color;
private string material;
private double weight;
public string Color { get; set; }
public string Material { get; set; }
public double Weight { get; set; }
public Ball() { }
public Ball(string color, double weight, string material)
{
this.Color = color;
this.Material = material;
this.Weight = weight;
}
public bool changecolorbymorethanweight(string c, double w)
{
if (Weight >= w)
{
Color = c;
return true;
}
else return false;
}
public void printall()
{
Console.WriteLine("Η μπάλα είναι χρώματος {0}\nυλικού {1}\nκαι βάρους {2}", Color, Material, Weight);
}
}
-
class Box
{
private double height;
private double width;
private double length;
private string material;
public List<Ball> content = new List<Ball>();
private double weight;
public double Height { get; set; }
public double Width { get; set; }
public double Length { get; set; }
public string Material { get; set; }
public List<Ball> Content { get; set; }
public double Weight
{
get
{
double varos = 0;
for (int i = 0; i < content.Count; i++)
{
varos = varos + content[i].Weight;
}
weight = varos;
return weight;
}
set
{
Weight = weight;
}
}
public void removefirst3()
{
Content.RemoveAt(0);
Content.RemoveAt(1);
Content.RemoveAt(2);
}
public void removeall()
{
Content.Clear();
}
public void removeallbycolor(string rbc)
{
for (int i = 0; i < Content.Count; i++)
if (Content[i].Color == rbc)
Content.RemoveAt(i);
}
public int getnumberbycolor(string gnbc)
{
int counter = 0;
for (int i = 0; i < Content.Count; i++)
if (Content[i].Color == gnbc)
counter++;
return counter;
}
public bool removeallmorethanbyweight(double rbwb)
{
bool result = false;
for (int i = 0; i < Content.Count; i++)
if (Content[i].Weight >= rbwb)
{
Content.RemoveAt(i);
result = true;
}
return result;
}
public bool removealllessthanbyweight(double rbws)
{
bool result = false;
for (int i = 0; i < Content.Count; i++)
if (Content[i].Weight >= rbws)
{
Content.RemoveAt(i);
result = true;
}
return result;
}
public bool removeallbymaterial(string rabm)
{
bool result = false;
for (int i = 0; i < Content.Count; i++)
if (Content[i].Material == rabm)
{
Content.RemoveAt(i);
result = true;
}
return result;
}
public void changecolorbyposition(int p, string c)
{
for (int i = 0; i < Content.Count; i++)
if (i == p)
Content[i].Color = c;
}
public void printall()
{
Console.WriteLine("Tο κουτί μας έχει \n{0} ύψος\n{1} πλάτος\n{2} μήκος\nείναι φτιαγμένο από {3}\nτο βάρος του είναι {4}\n και μέσα του έχει:\n{5}", Height, Width, Length, Material, Weight, Content);
}
public Box() { }
public Box(double length, double width, double height, string material, double weight, List<Ball> content)
{
this.Length = length;
this.Width = width;
this.Height = height;
this.Material = material;
this.Weight = weight;
this.Content = content;
}
public Box(double length, double width, double height, string material)
{
this.Length = length;
this.Width = width;
this.Height = height;
this.Material = material;
}
}
-
class Program
{
static void Main(string[] args)
{
Box box1 = new Box(1.2, 1.3, 1.8, "χάρτινο");
Box box2 = new Box(1.2, 2.3, 2.5, "ξύλινο");
Ball b1 = new Ball("Red", 2.5, "μεταλλική");
Ball b2 = new Ball("Red", 2.5, "μεταλλική");
Ball b3 = new Ball("Red", 2.5, "μεταλλική");
Ball b4 = new Ball("Red", 1.5, "μεταλλική");
Ball b5 = new Ball("Red", 1.5, "μεταλλική");
Ball b6 = new Ball("Black", 0.5, "πλαστική");
Ball b7 = new Ball("Black", 0.5, "πλαστική");
Ball b8 = new Ball("Black", 0.5, "πλαστική");
Ball b9 = new Ball("Black", 0.5, "πλαστική");
Ball b10 = new Ball("Black", 0.5, "πλαστική");
Ball b11 = new Ball("Άσπρο", 1.1, "λαστιχένια");
Ball b12 = new Ball("Άσπρο", 1.1, "λαστιχένια");
Ball b13 = new Ball("Άσπρο", 1.1, "λαστιχένια");
Ball b14 = new Ball("Άσπρο", 1.1, "λαστιχένια");
Ball b15 = new Ball("Άσπρο", 1.1, "λαστιχένια");
List<Ball> Myballs = new List<Ball>() { b1, b2 };
Myballs.Capacity = 15;
Myballs.Add(b1);
Myballs.Add(b2);
Myballs.Add(b3);
Myballs.Add(b4);
Myballs.Add(b5);
Myballs.Add(b6);
Myballs.Add(b7);
Myballs.Add(b8);
Myballs.Add(b9);
Myballs.Add(b10);
Myballs.Add(b11);
Myballs.Add(b12);
Myballs.Add(b13);
Myballs.Add(b14);
Myballs.Add(b15);
box1.Content.Add(Myballs[5]);
box1.Content.Add(Myballs[6]);
box1.Content.Add(Myballs[7]);
box1.Content.Add(Myballs[8]);
box1.Content.Add(Myballs[9]);
box1.Content.Add(Myballs[10]);
box1.Content.Add(Myballs[11]);
box1.Content.Add(Myballs[12]);
box1.Content.Add(Myballs[13]);
box1.Content.Add(Myballs[14]);
box2.Content.Add(Myballs[0]);
box2.Content.Add(Myballs[1]);
box2.Content.Add(Myballs[2]);
box2.Content.Add(Myballs[3]);
box2.Content.Add(Myballs[4]);
Console.ReadKey();
}
}
}
Initialize the Content property, either in the Box class:
public List<Ball> Content { get; set; } = new List<Ball>();
...or in the Main method before you add any balls:
box1.Content = new List<Ball>();
box1.Content.Add(Myballs[5]);
...

Write byte array [][] to jpg

I have the following piece of code I wish to do without using the Bitmap Class
I am not sure where to start can someone give me some code samples or examples to work from
public class PgmImage
{
public int Width { get; set; }
public int Height { get; set; }
public int MaxVal { get; set; }
public byte[][] Pixels { get; private set; }
public PgmImage(int width, int height, int maxVal,
byte[][] pixels)
{
this.Width = width;
this.Height = height;
this.MaxVal = maxVal;
this.Pixels = pixels;
}
}
private static Bitmap MakeBitmap(PgmImage pgmImage, int mag)
{
int width = pgmImage.Width * mag;
int height = pgmImage.Height * mag;
Bitmap result = new Bitmap(width, height);
Graphics gr = Graphics.FromImage(result);
for (int i = 0; i < pgmImage.Height; ++i)
{
for (int j = 0; j < pgmImage.Width; ++j)
{
int pixelColor = pgmImage.Pixels[i][j];
Color c = Color.FromArgb(pixelColor, pixelColor, pixelColor);
SolidBrush sb = new SolidBrush(c);
gr.FillRectangle(sb, j * mag, i * mag, mag, mag);
}
}
return result;
}
The reason behind this is that NetStandard doesn't have the Bitmap class to use

How do i make building with levels and production?

I want to make game, like Tribal Wars, but in console and single player. I have Village class and there I have to make something, which contains building level and according to level is production of the building. I tried to do it with multidimension array, like building[level, production] but it haven't worked.
This is full code from class Village (Primary class is Program)
class Village
{
/*
private int mainBuild = 0;
private double[] mainBuildCost = new double[20];
private int woodCutter = 0;
private double[] woodCutterCost = new double[20];
private double[] woodCutterProd = new double[20];*/
public double[,] woodCutter = new double[20, 1];
private int wood = 50;
public Village()
{
woodCutter[0, 0] = 5;
for (int lvl = 1; lvl < woodCutter.GetLength(0); lvl++)
{
for (int prod = 1; prod <= woodCutter.GetLength(1); prod++)
{
woodCutter[lvl, 0] = Math.Round(woodCutter[lvl-1, prod-1])*1.3;
}
woodCutter[lvl, 0] = lvl;
Console.Write(woodCutter);
}
}
}
And yes, it's really but and doesn't work, but i have no idea, how do I make my plan.
I would do it differently. Your production here can be represented as a formula.
Here's a little example:
class Village
{
public double CurrentWood { get; private set; }
public int WoodLevel { get; private set; }
public double WoodProduction { get { return WoodLevel * 1.3; } } // Change the formula to your own
public void Update()
{
// Update all your resources in here
CurrentWood += Production;
}
}

K-means with initial centers

I'm doing K-means clustering of n points and k centers.
To start off, here's my code so far:
A class for a point:
public class Point
{
public int Id { get; set; }
public double X { get; set; }
public double Y { get; set; }
public Point()
{
Id = -1;
X = -1;
Y = -1;
}
public Point(int id, double x, double y)
{
this.Id = id;
this.X = x;
this.Y = y;
}
public static double FindDistance(Point pt1, Point pt2)
{
double x1 = pt1.X, y1 = pt1.Y;
double x2 = pt2.X, y2 = pt2.Y;
double distance = Math.Sqrt(Math.Pow(x2 - x1, 2.0) + Math.Pow(y2 - y1, 2.0));
return (distance);
}
}
A class for data:
public class PointCollection : List<Point>
{
public Point Centroid { get; set; }
public PointCollection()
: base()
{
Centroid = new Point();
}
public void AddPoint(Point p)
{
this.Add(p);
UpdateCentroid();
}
public Point RemovePoint(Point p)
{
Point removedPoint = new Point(p.Id, p.X, p.Y);
this.Remove(p);
UpdateCentroid();
return (removedPoint);
}
public void UpdateCentroid()
{
double xSum = (from p in this select p.X).Sum();
double ySum = (from p in this select p.Y).Sum();
Centroid.X = (xSum / (double)this.Count);
Centroid.Y = (ySum / (double)this.Count);
}
}
Main class:
public class KMeans
{
public static List<PointCollection> DoKMeans(PointCollection points, int clusterCount)
{
List<PointCollection> allClusters = new List<PointCollection>();
List<List<Point>> allGroups = ListUtility.SplitList<Point>(points, clusterCount);
foreach (List<Point> group in allGroups)
{
PointCollection cluster = new PointCollection();
cluster.AddRange(group);
allClusters.Add(cluster);
}
int movements = 1;
while (movements > 0)
{
movements = 0;
foreach (PointCollection cluster in allClusters)
{
for (int pointIndex = 0; pointIndex < cluster.Count; pointIndex++)
{
Point point = cluster[pointIndex];
int nearestCluster = FindNearestCluster(allClusters, point);
if (nearestCluster != allClusters.IndexOf(cluster))
{
if (cluster.Count > 1)
{
Point removedPoint = cluster.RemovePoint(point);
allClusters[nearestCluster].AddPoint(removedPoint);
movements += 1;
}
}
}
}
}
return (allClusters);
}
public static int FindNearestCluster(List<PointCollection> allClusters, Point point)
{
double minimumDistance = 0.0;
int nearestClusterIndex = -1;
for (int k = 0; k < allClusters.Count; k++)
{
double distance = Point.FindDistance(point, allClusters[k].Centroid);
if (k == 0)
{
minimumDistance = distance;
nearestClusterIndex = 0;
}
else if (minimumDistance > distance)
{
minimumDistance = distance;
nearestClusterIndex = k;
}
}
return (nearestClusterIndex);
}
}
And finally helping function for list split:
public static List<List<T>> SplitList<T>(List<T> items, int groupCount)
{
List<List<T>> allGroups = new List<List<T>>();
int startIndex = 0;
int groupLength = (int)Math.Round((double)items.Count / (double)groupCount, 0);
while (startIndex < items.Count)
{
List<T> group = new List<T>();
group.AddRange(items.GetRange(startIndex, groupLength));
startIndex += groupLength;
if (startIndex + groupLength > items.Count)
{
groupLength = items.Count - startIndex;
}
allGroups.Add(group);
}
if (allGroups.Count > groupCount && allGroups.Count > 2)
{
allGroups[allGroups.Count - 2].AddRange(allGroups.Last());
allGroups.RemoveAt(allGroups.Count - 1);
}
return (allGroups);
}
So, now I'm trying to write a second method for the main class, which would accept a predefined starting centres. I have trouble grasping that though, as I can't find anything on the internet where the k-means algorithm would use initial centers. Can someone point me in a direction of such guide or give me any ideas how to modify the code? Thanks.
Edit: Maybe something more why am I trying to do this: I try to write LBG algorithm using k-means, like so https://onlinecourses.science.psu.edu/stat557/node/67
I can access the computed centers for splitting in each of the steps with my code, however I need to find a way to feed them back to the k-means class. Like, if I calculated the starting centre, i need to put this centre and another offset by epsilon into k-means algorithm.
Edit2: Code now in English(I hope)
Found a solution, maybe someone will use:
public static List<PointCollection> DoKMeans(PointCollection points, int clusterCount, Point[] startingCentres)
{
// code...
int ctr = 0;
foreach (List<Point> group in allGroups)
{
PointCollection cluster = new PointCollection();
cluster.c.X = startingCentres[ctr].X;
cluster.c.Y = startingCentres[ctr].Y;
cluster.AddRange(group);
allClusters.Add(cluster);
}
// rest of code the same
}

Drawing a line from a dot to dot (Point to Point) on Form MouseDown

I've been working days on a program that draws a grid of dots, and I had to start all over again several times because of a bad approach / to complicated. I've come to a point now where I have to draw a line from a clicked dot (point) to a second clicked dot (point) on the form.
Seriously I've been spending hours even days of my time searching for the right approach.
As for now I only managed to get a line drawn from a point on the form to another point on the form on random clicks...
Could someone please help get the code done, its just frustrating me how I don't have any progress after all attempts of drawing a grid of dots..
So what I want to do is "draw a line from a clicked dot (point) to a second clicked dot (point) on the form".
See below of my code:
Form1.cs:
public partial class Form1 : Form
{
private GridDrawing drawing;
private Point point1;
private Point point2;
List<Point> p1List = new List<Point>(); //Temp
List<Point> p2List = new List<Point>(); //Temp
//True if point1 must be updated
//False if point2 must be updated
private bool firstPoint = true;
private int sizeOfDot;
private int rows;
private int columns;
public Form1()
{
InitializeComponent();
sizeOfDot = 10; //The size of the dot
rows = 6; //The amount of rows for the matrix
columns = 8; //The amount of columns for the matrix
}
private void Form_Paint(object sender, PaintEventArgs e)
{
e.Graphics.FillRectangle(Brushes.White, ClientRectangle); //Fill the form in white
drawing = new GridDrawing(this, rows, columns); //Control, Rows, Columns
foreach (var piece in drawing.Pieces) //Draws all the dots
{
e.Graphics.FillEllipse(Brushes.Black, (piece.Dot.X - sizeOfDot / 2),
(piece.Dot.Y - sizeOfDot / 2), sizeOfDot, sizeOfDot); //Draws the dot
}
using (var pen = new Pen(Color.Black, 2))
{
for (int i = 0; i < p1List.Count; i++)
{
e.Graphics.DrawLine(pen, p1List[i], p2List[i]);
}
}
}
private void startToolStripMenuItem_Click(object sender, EventArgs e)
{}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (firstPoint) //Update point1 or point2
{
//Point 1
point1.X = e.X;
point1.Y = e.Y;
}
else
{
//Point 2
point2.X = e.X;
point2.Y = e.Y;
p1List.Add(point1);
p2List.Add(point2);
}
firstPoint = !firstPoint; //Change the bool value
Invalidate(); //Redraw
}
private void Form1_SizeChanged(object sender, EventArgs e)
{
Invalidate();
}
}
GridDrawing.cs:
public class GridDrawing
{
private int columns;
private int rows;
private List<GridPiece> pieces;
private Point dot;
//private Point point1; //point1 to start drawing line from
//private Point point2; //point2 to end drawing line from
/// <summary>
/// Constructs a grid
/// </summary>
/// <param name="ctrl"></param>
/// <param name="rows"></param>
/// <param name="columns"></param>
/// <param name="sizeOfDot"></param>
public GridDrawing(Control ctrl, int rows, int columns)
{
this.rows = rows; // The amount of rows in the matrix.
this.columns = columns; // The amount of columns in the matrix.
this.pieces = new List<GridPiece>(); // Initializes the List GridPieces
int xOffset = (int)ctrl.ClientRectangle.Width / (columns + 1); // FP offset for X
int yOffset = (int)ctrl.ClientRectangle.Height / (rows + 1); // FP offset for Y
//Generate the dots
for (int i = 0; i < rows; i++) //Matrix with 6 rows
{
for (int j = 0; j < columns; j++) //Matrix with 8 columns
{
dot = new Point((j + 1) * xOffset, (i + 1) * yOffset); // Center of the dot
GridPiece p = new GridPiece(dot); // Creates a piece
pieces.Add(p); // Puts the piece that has to be drawn in the List<GridPiece>pieces
}
}
}
public List<GridPiece> Pieces //Property List<GridPiece>pieces
{
get { return this.pieces; }
}
public Point Dot //Property Point dot
{
get { return this.dot; }
}
}
GridPiece.cs:
public class GridPiece
{
private Point dot;
/// <summary>
/// Constructor of GriedPiece
/// </summary>
/// <param name="bmpPic"></param>
/// <param name="position"></param>
public GridPiece(Point dot)
{
this.dot = dot;
}
public Point Dot
{
get { return dot; }
}
}
Here's an example how I'm trying to make it look like
Could someone please help me?
Here is how to do this. add following code
public class Line
{
public float X1 { get; set; }
public float X2 { get; set; }
public float Y1 { get; set; }
public float Y2 { get; set; }
}
public sealed class Grid : Panel
{
readonly DotDrawing drawing = new DotDrawing();
private List<Line> Markers { get; set; }
public Grid()
{
this.DoubleBuffered = true;
Markers = new List<Line>();
}
protected override void OnPaint(PaintEventArgs e)
{
foreach (Line line in Markers)
{
using (Pen pen = new Pen(Brushes.Black))
{
pen.Width = 2;
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
e.Graphics.DrawLine(pen, line.X1, line.Y1, line.X2, line.Y2);
}
}drawing.Render(e.Graphics);
base.OnPaint(e);
}
private Dot lastDot;
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
var x = this.drawing.GetDotFromPoint(e.Location);
if (x != null)
{
lastDot = x;
}
else
{
lastDot = null;
}
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
var x = this.drawing.GetDotFromPoint(e.Location);
if (x != null)
{
Line line = new Line();
line.X1 = lastDot.Center.X;
line.Y1 = lastDot.Center.Y;
line.X2 = x.Center.X;
line.Y2 = x.Center.Y;
this.Markers.Add(line);
Invalidate();
}
}
}
public class Dot
{
public PointF Location { get; set; }
public int Radius { get; set; }
public PointF Center
{
get
{
return new PointF(this.Bounds.Left + (float)this.Radius,
this.Bounds.Top + (float)this.Radius);
}
}
public RectangleF Bounds
{
get
{
return new RectangleF(Location, new SizeF(2 * Radius, 2 * Radius));
}
}
public Dot()
{
Radius = 5;
}
}
public class DotDrawing
{
private List<Dot> Dots { get; set; }
public int RowCount { get; set; }
public int ColumnCount { get; set; }
public int ColumnSpacing { get; set; }
public int RowSpacing { get; set; }
public int DotRadius { get; set; }
public DotDrawing()
{
Dots = new List<Dot>();
DotRadius = 10;
ColumnCount = 15;
RowCount = 25;
this.RowSpacing = 30;
this.ColumnSpacing = 30;
}
public void Render(Graphics g)
{
this.Dots.Clear();
float x = 0;
float y = 0;
for (int i = 0; i < RowCount; i++)
{
for (int j = 0; j < ColumnCount; j++)
{
{
Dot dot = new Dot();
dot.Location = new PointF(x, y);
using (SolidBrush brush = new SolidBrush(ColorTranslator.FromHtml("#009aff")))
{
g.FillEllipse(brush, dot.Location.X, dot.Location.Y, DotRadius, DotRadius);
}
x += (DotRadius + ColumnSpacing);
Dots.Add(dot);
}
}
x = 0;
y += (DotRadius + this.RowSpacing);
}
}
public Dot GetDotFromPoint(PointF point)
{
for (int i = 0; i < this.Dots.Count; i++)
{
RectangleF rect = this.Dots[i].Bounds;
rect.Inflate(new SizeF(3, 3));
Region region = new Region(rect);
if (region.IsVisible(point))
{
return this.Dots[i];
}
}
return null;
}
}
Drag the Grid from the tool box.
Mouse Click on any of the dots without releasing it point to another grid you'll see the effect.

Categories

Resources