I am working with Open Closed principle of SOLID in C#. I have abstract class Shape which i want to used to calculate the area of different shapes. How to call areaCalculator class and how to pass different shapes. Here is my code.
public abstract class Shape
{
public abstract double Area();
}
public class Rectangle : Shape
{
public double Height { get; set; }
public double Width { get; set; }
public override double Area()
{
return Height * Width;
}
}
public class AreaCalculator
{
public double TotalArea(Shape[] shapes)
{
double area = 0;
foreach (var objShapes in shapes)
{
area += objShapes.Area();
}
return area;
}
}
I want to call areaCalculator class to calculate the area.
AreaCalculator _obj = new AreaCalculator();
Shape[] _shapes = new Shape[2];
var _result = _obj.TotalArea(_shapes);
Console.WriteLine(_result);
Console.ReadLine();
You need to create the rectangle objects and set their height and width for the calculation. If not the _shapes list is empty. Find below a sample of working code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ShapesStacjOverflow {
public abstract class Shape {
public abstract double Area();
}
public class Rectangle : Shape {
public double Height { get; set; }
public double Width { get; set; }
public override double Area() {
return Height * Width;
}
}
public class AreaCalculator {
public double TotalArea(Shape[] shapes) {
double area = 0;
foreach (var objShapes in shapes) {
area += objShapes.Area();
}
return area;
}
}
class Program {
static void Main(string[] args) {
AreaCalculator _obj = new AreaCalculator();
Shape[] _shapes = new Shape[2];
Rectangle rectangle1 = new Rectangle {
Width = 2,
Height = 3
};
Rectangle rectangle2 = new Rectangle {
Width = 1,
Height = 1
};
_shapes[0] = rectangle1;
_shapes[1] = rectangle2;
var _result = _obj.TotalArea(_shapes);
Console.WriteLine(_result);
Console.ReadLine();
}
}
}
Returning 7 as a result.
If you want to create other child shapes, those should override the Area() method, so for each of the objects created in the list, the corresponding Area() method would be applied.
Hope that helps.
Related
I want to draw the Property value in my PropertyGrid in a similar fashion as owner-drawing items in a ListView (Details), and other controls.
If a Property is declared of type Color, its value is drawn with a swatch of the color next to a string description. If a Property is a type of Image, a thumbnail of the image is drawn next to a string description.
I have a property that is a class that contains three Properties of type Color. I want to draw all three colors in the PropertyGrid next to the Property name. The class has an ExpandableObjectConverter as the TypeConverter, where the colors are edited, but the only option I know of for changing how the Property's value is displayed is to use a TypeConverter to return a String.
You need to create a editor for your type (which has 3 color properties) by deriving from UITypeEditor and overriding its GetPaintValueSupported and PaintValue. Than register the editor for your class using an Editor attribute:
Exapmle
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
public class MyComponent : Component
{
public SampleClass SampleProperty { get; set; } = new SampleClass();
}
[TypeConverter(typeof(ExpandableObjectConverter))]
[Editor(typeof(SampleClassEditor), typeof(UITypeEditor))]
public class SampleClass
{
public Color Color1 { get; set; } = Color.Red;
public Color Color2 { get; set; } = Color.Green;
public Color Color3 { get; set; } = Color.Blue;
}
public class SampleClassEditor : UITypeEditor
{
public override bool GetPaintValueSupported(ITypeDescriptorContext context)
{
return true;
}
public override void PaintValue(PaintValueEventArgs e)
{
var sample = e.Value as SampleClass;
if (sample != null)
{
int x = e.Bounds.X, y = e.Bounds.Y;
int w = e.Bounds.Width, h = e.Bounds.Height;
using (var b = new SolidBrush(sample.Color1))
e.Graphics.FillRectangle(b, x, y, w / 3, h);
using (var b = new SolidBrush(sample.Color2))
e.Graphics.FillRectangle(b, x += w / 3, y, w / 3, h);
using (var b = new SolidBrush(sample.Color3))
e.Graphics.FillRectangle(b, x += w / 3, y, w / 3 + 1, h);
}
base.PaintValue(e);
}
}
Programming newbie here and I've been breaking my head over this for several hours now.
I can make a coordinate object but then I want to make a dot object that can access the coordinate fields from a Coordinate object. How do I "link" these two classes together? And do you have any recommendations for good YouTube videos that explain what I'm missing here? Thanks!
class Coordinate
{
public int X { get; private set; } = 0;
public int Y { get; private set; } = 0;
public Coordinate(int x, int y)
{
x = X;
y = Y;
}
}
class Dot
{
public string color { get; set; }
public Dot(string color, Dot dot)
{
this.Color = color;
}
}
class Program
{
static void Main(string[] args)
{
Coordinate coor1 = new Coordinate(2, 3);
Dot dot1 = new Dot("Blue", coor1);
}
Here is what you are searching for a "linking" your classes. In object-oriented programming this is called composition.
That way you can use functionality and data of Coordinate-instance inside your Dot class.
class Coordinate
{
public int X { get; private set; }
public int Y { get; private set; }
public Coordinate(int x, int y)
{
X = x;
Y = y;
}
}
class Dot
{
public Coordinate coord { get; private set; }
public string color { get; set; }
public Dot(string color, Coordinate coord)
{
this.color = color;
this.coord = coord;
}
}
class Program
{
static void Main(string[] args)
{
Coordinate coor1 = new Coordinate(2, 3);
Dot dot1 = new Dot("Blue", coor1);
Console.WriteLine(dot1.coord.X);
}
}
Note: I also fixed possible typo in Coordinate-constructor (setting X=x and Y=y..)
I am looking for a way to draw a simple shape on a canvas with the shape being made in another class ShapeManager. This ShapeManager decides what shape it is and assigns a color to it coming from ColorManager.
I apologize in advance for the long code, this is my first post and I am still just learning C# and OOP in general.
Canvas Window
A window with a canvas on it (cvs_Drawing). Should place a shape it gets from CanvasManager.ShapeManager.CreateNewShape(), but throws a NullReference.
public partial class CanvasWindow : Window
{
public string CanvasName { get; set; }
public CanvasManager CanvasManager { get; set; }
public CanvasWindow(string name)
{
InitializeComponent();
CanvasManager= new CanvasManager();
CanvasName = name;
this.Title = CanvasName;
}
//Click event to draw the chosen shape on canvas
private void cvs_Drawing_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
try
{
Shape shapeDrawing = CanvasManager.ShapeManager.CreateNewShape();
Point location = e.GetPosition(cvs_Drawing);
Canvas.SetTop(shapeDrawing, location.Y);
Canvas.SetLeft(shapeDrawing, location.X);
cvs_Drawing.Children.Add(shapeDrawing);
}
//catch block here
CanvasManager
Creates CanvasWindows and provides interaction between CanvasWindow and ShapeManager. Multiple CanvasWindows is normally a possibility.
public CanvasWindow CanvasWindow { get; set; }
public MainWindow MainWindow { get; set; }
public ShapeManager ShapeManager { get; set; }
//Constructors
public CanvasManager(MainWindow w)
{
MainWindow = w;
ShapeManager = new ShapeManager(w);
}
public CanvasManager() { }
//Add a brand new canvas
public CanvasWindow CreateNewCanvas(string name)
{
CanvasWindow = new CanvasWindow(name);
return CanvasWindow;
}
ShapeManager
Creates Shapes needed for CanvasWindow
public MainWindow Window { get; set; }
public Shape NewShape { get; set; }
public ColorManager ColorManager { get; set; }
public List<string> ListShapes { get; set; } = new List<string>();
public ShapeManager(MainWindow w)
{
Window = w;
ListShapes.Add("Ellipse");
ListShapes.Add("Rectangle");
ColorManager = new ColorManager();
}
public ShapeManager() { }
#region Shape Creation
public Shape CreateNewShape()
{
Color newShapeColor = ColorManager.CreateNewColor();
if (Window.cb_Shapes.SelectedItem.ToString() == "Ellipse")
{
NewShape = new Ellipse
{
Width = Int32.Parse(Window.tb_Width.Text),
Height = Int32.Parse(Window.tb_Height.Text),
Fill = new SolidColorBrush(newShapeColor)
};
return NewShape;
}
else
{
NewShape = new Rectangle
{
Width = Int32.Parse(Window.tb_Width.Text),
Height = Int32.Parse(Window.tb_Height.Text),
Fill = new SolidColorBrush(newShapeColor)
};
return NewShape;
}
}
ColorManager
Creates the color for the shape that was created in ShapeManager.
public MainWindow Window { get; set; }
public Color NewColor { get; set; }
//Constructors
public ColorManager(MainWindow w)
{
Window = w;
}
//public ColorManager(){}
//Add new color method
public Color CreateNewColor()
{
NewColor = new Color
{
A = 255,
R = Byte.Parse(Window.tb_RedValue.Text),
G = Byte.Parse(Window.tb_GreenValue.Text),
B = Byte.Parse(Window.tb_BlueValue.Text)
};
return NewColor;
}
TL;DR. I can't create a shape on the canvas, always get a NullReference every time I click on the canvas.
Your code has an error here
public CanvasManager(){ ShapeManager = new ShapeManager(MainWindow); }
// CanvasManager.cs , Line 33
you passed MainWindow, which is null
and it comes from here
public CanvasManager CanvasManager { get; set; } = new CanvasManager();
// CanvasWindow.xaml.cs, Line 28
You can correct your code like this:
// in CanvasWindow.xaml.cs, Line 28
public CanvasWindow(string name, MainWindow mainWindow)
{
InitializeComponent();
**CanvasManager = new CanvasManager(mainWindow);**
CanvasName = name;
//ShapeManager = new ShapeManager();
this.Title = CanvasName;
...
...
...
// NewDrawingWindow.xaml.cs, Line 47
CanvasWindow canvasWindow = new CanvasWindow(tb_Drawing_Name.Text, Window);
// CanvasManager.cs, Line 38
CanvasWindow = new CanvasWindow(name, MainWindow);
I want to serialize my object as binary or xml.
I used this method to serialize my object. but it gives error : System.Windows.Media.SolidColorBrush not serializable.
My object contains Grid, Ellipse, SolidColorBrush objects.
How can I serialize these objects?
You need to create a SerializableBrush class of your own which has constructors taking SolidBrush etc and also a ToBrush method to reconstruct the GDI+ brushes..
The same goes for most other GDI+ objects and structures like Color, Pen etc, some of which, like Color you will even need for the SerializableBrush class..
Adorn it with the [Serializable] attribute!
A simple serializable Color class:
[Serializable]
public class SerColor
{
public byte Red { get; set; }
public byte Green { get; set; }
public byte Blue { get; set; }
public byte Alpha { get; set; }
public SerColor() { }
public SerColor(Color c)
{ Red = c.R; Green = c.G; Blue = c.B; Alpha = c.A; }
static public Color Color(SerColor c)
{ return System.Drawing.Color.FromArgb(c.Alpha, c.Red, c.Green, c.Blue); }
}
'And a simple serializable SolidBrush class:
[Serializable]
public class SerSolidBrush
{
public SerColor sColor { get; set; }
public SerSolidBrush() { }
public SerSolidBrush(Color c)
{
sColor = new SerColor(c);
}
public SerSolidBrush(SolidBrush b)
{
sColor = new SerColor(b.Color);
}
public SolidBrush SolidBrush()
{
Color c = SerColor.Color(sColor);
return new System.Drawing.SolidBrush(c);
}
static public SolidBrush SolidBrush(SerSolidBrush b)
{
Color c = SerColor.Color(b.sColor);
return new System.Drawing.SolidBrush(c);
}
}
And a small test bed:
SolidBrush brush = new SolidBrush(Color.Red);
SerSolidBrush sBrush = new SerSolidBrush(brush);
XmlSerializer xs = new XmlSerializer(sBrush.GetType());
using (TextWriter tw = new StreamWriter(#"d:\xmlBrush.xml"))
{
xs.Serialize(tw, sBrush);
tw.Close();
}
SerSolidBrush sBrush2 = null;
using (TextReader tr = new StreamReader(#"d:\xmlBrush.xml"))
sBrush2 = (SerSolidBrush) xs.Deserialize(tr);
SolidBrush newBrush = sBrush2.SolidBrush();
This is the resulting xml file ((no idead how to insert xml text in an SO answer properly)):
I hope this shows how to do it; note that SolidBrush is a very simple class with only one property. Pen and most others will be more complicated if you want to support all properties..
Note that simple built-in enums, like LineJoin etc are serializable, so you can simply add the proerties and everything works just fine. To demostrate here is a rather incomplete serilizable Pen class. You will want to add several other properties..:
[Serializable]
public class SerPen
{
public SerColor sColor { get; set; }
public float width { get; set; }
public LineJoin lineJoin { get; set; }
// constructors
public SerPen() { width = 1f; }
public SerPen(Color c, float w)
{
sColor = new SerColor(c);
width = w;
}
public SerPen(Pen p)
{
sColor = new SerColor(p.Color);
width = p.Width;
lineJoin = p.LineJoin;
}
// re-constructors
public Pen Pen ()
{
Color c = SerColor.Color(sColor);
Pen pen = new System.Drawing.Pen (c, width);
pen.LineJoin = lineJoin;
return pen;
}
static public Pen Pen (SerPen p)
{
Color c = SerColor.Color(p.sColor);
Pen pen = new System.Drawing.Pen (c, p.width);
pen.LineJoin = p.lineJoin;
return pen;
}
}
I would like to understand and make my own classes in the way like the common rectangle:
Rectangle r1 = new Rectangle();
Size s = r1.Size;
int size = r1.Size.Width;
I don't want to use methods, just simple property values.
public partial class Rectangle
{
private Size _size;
public Size Size
{
get { return _size; }
set { _size = value; }
}
}
So how to create the Width, Height, etc. properties?
And if i would like to create longer chain? e.g.:
r1.Size.Width.InInches.Color.
etc.
Probably you'll find yourself saying: I knew it.
Class properties can be associations with other classes:
public class Size
{
public Size(double width, double height)
{
Width = width;
Height = height;
}
public double Width { get; }
public double Height { get; }
}
Now you'll be able to get rectangle's size as follows: rect1.Size.Width.
About providing the size unit, I wouldn't create an InInches property, but I would create an enumeration:
public enum Unit
{
Inch = 1,
Pixel
}
...and I would add a property to Size as follows:
public class Size
{
public Size(double width, double height, Unit unit)
{
Width = width;
Height = height;
Unit = unit;
}
public double Width { get; }
public double Height { get; }
public Unit Unit { get; }
}
...and if you need to perform conversions, you could easily implement them in Size too:
public class Size
{
public Size(double width, double height, Unit unit)
{
Width = width;
Height = height;
Unit = unit;
}
public double Width { get; }
public double Height { get; }
public Unit Unit { get; }
public Size ConvertTo(Unit unit)
{
Size convertedSize;
switch(unit)
{
case Unit.Inch:
// Calc here the conversion from current Size
// unit to inches, and return
// a new size
convertedSize = new Size(...);
break;
case Unit.Pixel:
// Calc here the conversion from current Size
// unit to pixels, and return
// a new size
convertedSize = new Size(...);
break;
default:
throw new NotSupportedException("Unit not supported yet");
break;
}
return convertedSize;
}
}
What you call chain is what in object-oriented programming is called composition.
Thus, you can associate Size with other class, and associate another class to the other one, and so on...