Serialize Media and Shapes objects - c#

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;
}
}

Related

How to custom draw a GridItem in PropertyGrid?

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);
}
}

How to calculate area using Open closed principle C#

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.

How to save custom class in C# WPF?

I'm developing a WPF application and I'm trying to do it without any reference to Windows Forms. I'm actually using the Wpf Font Picker by Alessio Saltarin which is a font picker with color picker completely developed in WPF.
What I'm trying to do is to let the user choose a font+color and save their choice in order to restore it for a new start of the application. The font is stored in the FontInfo class:
public class FontInfo
{
public SolidColorBrush BrushColor { get; set; }
public FontColor Color { get { return AvailableColors.GetFontColor(this.BrushColor); } }
public FontFamily Family { get; set; }
public double Size { get; set; }
public FontStretch Stretch { get; set; }
public FontStyle Style { get; set; }
public FontWeight Weight { get; set; }
public FamilyTypeface Typeface
{
get
{
FamilyTypeface ftf = new FamilyTypeface()
{
Stretch = this.Stretch,
Weight = this.Weight,
Style = this.Style
};
return ftf;
}
}
public FontInfo() { }
public FontInfo(FontFamily fam, double sz, FontStyle style, FontStretch strc, FontWeight weight, SolidColorBrush c)
{
this.Family = fam;
this.Size = sz;
this.Style = style;
this.Stretch = strc;
this.Weight = weight;
this.BrushColor = c;
}
public static void ApplyFont(Control control, FontInfo font)
{
control.FontFamily = font.Family;
control.FontSize = font.Size;
control.FontStyle = font.Style;
control.FontStretch = font.Stretch;
control.FontWeight = font.Weight;
control.Foreground = font.BrushColor;
}
public static FontInfo GetControlFont(Control control)
{
FontInfo font = new FontInfo()
{
Family = control.FontFamily,
Size = control.FontSize,
Style = control.FontStyle,
Stretch = control.FontStretch,
Weight = control.FontWeight,
BrushColor = (SolidColorBrush)control.Foreground
};
return font;
}
public static string TypefaceToString(FamilyTypeface ttf)
{
StringBuilder sb = new StringBuilder(ttf.Stretch.ToString());
sb.Append("-");
sb.Append(ttf.Weight.ToString());
sb.Append("-");
sb.Append(ttf.Style.ToString());
return sb.ToString();
}
}
I didn't get the point about what is the best option. I saw that it can be achieved by XML Serialization but I failed and I saw that every example is using simple classes with strings and int variables.
Cold you please point me to some documentation or give me an example on how to do this?
As types like SolidColorBrush are not decorated with the SerializableAttribute they don't serialize by default. Therefore you have do do it manually by implementing the ISerializable interface and converting those types into a serializable format e.g., string. This can be accomplished by using the build-in library converters that exist for almost all those types.
[Serializable]
public class FontInfo : ISerializable
{
public FontInfo()
{
// Empty constructor required to compile.
}
public SolidColorBrush BrushColor { get; set; }
//public FontColor Color { get { return AvailableColors.GetFontColor(this.BrushColor); } }
public FontFamily Family { get; set; }
public double Size { get; set; }
public FontStretch Stretch { get; set; }
public FontStyle Style { get; set; }
public FontWeight Weight { get; set; }
public FamilyTypeface Typeface =>
new FamilyTypeface()
{
Stretch = this.Stretch,
Weight = this.Weight,
Style = this.Style
};
// Implement this method to serialize data. The method is called
// on serialization e.g., by the BinaryFormatter.
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
// Use the AddValue method to specify serialized values.
info.AddValue(nameof(this.BrushColor), new ColorConverter().ConvertToString(this.BrushColor.Color), typeof(string));
info.AddValue(nameof(this.Family), new FontFamilyConverter().ConvertToString(this.Family), typeof(string));
info.AddValue(nameof(this.Stretch), new FontStretchConverter().ConvertToString(this.Stretch), typeof(string));
info.AddValue(nameof(this.Style), new FontStyleConverter().ConvertToString(this.Style), typeof(string));
info.AddValue(nameof(this.Weight), new FontWeightConverter().ConvertToString(this.Weight), typeof(string));
info.AddValue(nameof(this.Size), this.Size, typeof(double));
}
// The special constructor is used
// e.g. by the BinaryFormatter to deserialize values.
public FontInfo(SerializationInfo info, StreamingContext context)
{
// Reset the property value using the GetValue method.
this.BrushColor = new SolidColorBrush((Color) ColorConverter.ConvertFromString((string)info.GetValue(nameof(this.BrushColor), typeof(string))));
this.Family = (FontFamily) new FontFamilyConverter().ConvertFromString((string)info.GetValue(nameof(this.Family), typeof(string)));
this.Stretch = (FontStretch) new FontStretchConverter().ConvertFromString((string)info.GetValue(nameof(this.Stretch), typeof(string)));
this.Style = (FontStyle) new FontStyleConverter().ConvertFromString((string)info.GetValue(nameof(this.Style), typeof(string)));
this.Weight = (FontWeight) new FontWeightConverter().ConvertFromString((string)info.GetValue(nameof(this.Weight), typeof(string)));
this.Size = (double) info.GetValue(nameof(this.Size), typeof(double));
}
}
Usage
public static void SerializeItem(string fileName)
{
var fontInfo = new FontInfo();
using (FileStream fileStream = File.Create(fileName))
{
var formatter = new BinaryFormatter();
formatter.Serialize(fileStream, fontInfo);
}
}
public static void DeserializeItem(string fileName)
{
using (FileStream fileStream = File.OpenRead(fileName))
{
var formatter = new BinaryFormatter();
FontInfo fontInfo = (FontInfo) formatter.Deserialize(fileStream);
}
}
Note
I don't know what FontColor is - must be a custom type of yours. In this case you need to decorate it with the SerializableAttribute too in order to serialize it (or provide a converter).
I didn't tested the code. Use this as a guide on how to serialize by implementing ISerializable.
You were on the right track with serialization, but it can be tricky at times. Here is a quick example you can try with your class that should work. This takes advantage of binary serialization.
First thing you must always do is make your class Serializable with an attribute like so.
[Serializable] //Add this attribute above your class
public class FontInfo
{
//...
}
Next try this simple example to see if your class serializes, saves to a file then deserializes.
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
public void Example()
{
FontInfo fi = new FontInfo(){Size = 12};
BinaryFormatter bf = new BinaryFormatter();
// Serialize the Binary Object and save to file
using (FileStream fsout = new FileStream("FontInfo.txt", FileMode.Create, FileAccess.Write, FileShare.None))
{
bf.Serialize(fsout, fi);
}
//Open saved file and deserialize
using (FileStream fsin = new FileStream("FontInfo.txt", FileMode.Open, FileAccess.Read, FileShare.None))
{
FontInfo fi2 = (FontInfo)bf.Deserialize(fsin);
Console.WriteLine(fi2.Size); //Should output 12
}
}
This is just a quick example, but should get your started on the right track.

Linking instances of two classes together

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..)

Draw a shape on a canvas in a new window C#

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);

Categories

Resources