I am working with GDI+ and need to create a Brush or Pen. In most cases I should use a "color Struct". Searching around I see two different styles: One is like this:
Brush B1 = new SolidBrush(Color.FromArgb(255, 0, 0));
and the other is:
Color myColor;
myColor = Color.FromArgb(255,0,0);
Brush B2 = new SolidBrush(myColor);
Can anyone describe how can we use a Color without declaring an instance of the Struct with new operator that calls the default constructor.
All that is going on here is that the interesting constructor is non-public, and you must create the value via a static utility method. You can achieve the same thing trivially in your own code:
struct Indirect
{
private readonly int value;
private Indirect(int value)
{
this.value = value;
}
public static Indirect Create(int value)
{
return new Indirect(value);
}
}
struct Direct
{
private readonly int value;
public Direct(int value)
{
this.value = value;
}
}
class Program
{
static void Main()
{
var x = Indirect.Create(42);
var y = new Direct(42);
}
}
Sometimes the expected usage is that the caller uses new; sometimes the expected usage is that the caller gets handed values from a helper method. In the case of Color: the latter. In the case of SolidBrush: the former. Note that this can be the case for both struct and class types - that is not the distinguishing factor.
In the case of Color, there are actually many more fields than you see directly; for example, knownColor, name, state - separately to the ARGB values. Some colors are "known" (from pre-defined named lists); some colors are ad-hoc (from ARGB data). The way you get the color determines these additional values.
The constructors of the type System.Drawing.Color are private and internal, meaning you can't call them from your code.
You'll need to instantiate a color through the given static methods and properties it contains, like Color.FromArgb() or Color.White.
As for the comments, which now make the question clear: those methods and properties are static, which means you don't call them on an instance (new Color().White) but on the type (Color.White).
Judging from its behavior, the method
Color.FromArgb(int red, int green, int blue)
most probably calls
new Color()
in its implementation, i.e. it declares an instance of the struct Color with the new operator.
Both implementations are equal, however
Brush B1 = new SolidBrush(Color.FromArgb(255, 0, 0));
is shorter. I'd rather use even shorter in the case
Brush B1 = new SolidBrush(Color.Red); // R = 255, G = 0, B = 0 is just "Red"
Note, that Brush is IDisposable, that's why it seems that you have put it
using (Brush B1 = new SolidBrush(Color.Red)) {
... // Working with brush
}
Related
I'm trying to write some code that sets a property on a struct (important that it's a property on a struct) and it's failing:
System.Drawing.Rectangle rectangle = new System.Drawing.Rectangle();
PropertyInfo propertyInfo = typeof(System.Drawing.Rectangle).GetProperty("Height");
propertyInfo.SetValue(rectangle, 5, null);
The Height value (as reported by the debugger) never gets set to anything - it stays at the default value of 0.
I have done plenty of reflection on classes before and this has worked fine. Also, I know that when dealing with structs, you need to use FieldInfo.SetValueDirect if setting a field, but I don't know of an equivalent for PropertyInfo.
The value of rectangle is being boxed - but then you're losing the boxed value, which is what's being modified. Try this:
Rectangle rectangle = new Rectangle();
PropertyInfo propertyInfo = typeof(Rectangle).GetProperty("Height");
object boxed = rectangle;
propertyInfo.SetValue(boxed, 5, null);
rectangle = (Rectangle) boxed;
Ever heard of SetValueDirect? There's a reason they made it. :)
struct MyStruct { public int Field; }
static class Program
{
static void Main()
{
var s = new MyStruct();
s.GetType().GetField("Field").SetValueDirect(__makeref(s), 5);
System.Console.WriteLine(s.Field); //Prints 5
}
}
There's other methods than the undocumented __makeref which you could use (see System.TypedReference) but they're more painful.
I have a class called Surface, in this class i have an array of type struct Color.
public class Surface
{
private Color[,] pixels;
public Color this[int x, int y]
{
get { return pixels[y, x]; }
}
}
[StructLayout(LayoutKind.Explicit)]
public struct Color
{
[FieldOffset(0)]
public byte R;
public void Set(byte r)
{
R = r;
}
}
However when i try to access the color using the indexer it don't get updated.
mySurface[x, y].Set(255); // Will not work, i don't get an error but the color don't get updated.
How can i solve this problem?
How can i solve this problem?
Well you could avoid creating mutable structs and exposing public fields, to start with. That's where the problem is coming from. Your code is effectively:
Color tmp = mySurface[x, y]; // Take a copy from the array...
tmp.Set(255); // This only affects the copy
To change the array, you'll need to call the setter on the indexer instead. For example:
Color tmp = mySurface[x, y];
tmp.Set(255);
mySurface[x, y] = tmp;
Assuming you actually have several values in your struct, it would be simpler if you'd make your struct immutable but provide methods that returned new values, just like DateTime.AddDays etc. Then you could write code like:
mySurface[x, y] = mySurface[x, y].WithRed(255);
Options if you really want to avoid using a setter:
Use ref return from C# 7: redefine your indexer to return a ref Color; although then you can't have a setter.
Make Color a class instead of a struct
Use a reference type inside Color, so you don't need to change the bits in the Color value itself. (This is really nasty - I'm not suggesting that.)
Structs are value types, so if you get it from the array by calling pixels[y,x], you will actually create a copy of the struct to change the field on.
See also Unable to Modify struct Members
I'm trying to write some code that sets a property on a struct (important that it's a property on a struct) and it's failing:
System.Drawing.Rectangle rectangle = new System.Drawing.Rectangle();
PropertyInfo propertyInfo = typeof(System.Drawing.Rectangle).GetProperty("Height");
propertyInfo.SetValue(rectangle, 5, null);
The Height value (as reported by the debugger) never gets set to anything - it stays at the default value of 0.
I have done plenty of reflection on classes before and this has worked fine. Also, I know that when dealing with structs, you need to use FieldInfo.SetValueDirect if setting a field, but I don't know of an equivalent for PropertyInfo.
The value of rectangle is being boxed - but then you're losing the boxed value, which is what's being modified. Try this:
Rectangle rectangle = new Rectangle();
PropertyInfo propertyInfo = typeof(Rectangle).GetProperty("Height");
object boxed = rectangle;
propertyInfo.SetValue(boxed, 5, null);
rectangle = (Rectangle) boxed;
Ever heard of SetValueDirect? There's a reason they made it. :)
struct MyStruct { public int Field; }
static class Program
{
static void Main()
{
var s = new MyStruct();
s.GetType().GetField("Field").SetValueDirect(__makeref(s), 5);
System.Console.WriteLine(s.Field); //Prints 5
}
}
There's other methods than the undocumented __makeref which you could use (see System.TypedReference) but they're more painful.
How do you easily clone (copy) a RectangleF in C#?
There are obviously inelegant ways to do it, such as new RectangleF(r.Location, r.size), but surely there's a .Copy or .Clone method hiding somewhere? But neither of those compiles for me, nor does there appear to be a copy constructor. I suspect there's some simple, C#-standard way of copying any struct, that I just haven't found yet.
In case it matters, my real objective is to make a method that returns an offset version of a rectangle (because, amazingly, RectangleF doesn't have such built in - it has only a mutator method). My best stab at this is:
public static RectangleF Offset(RectangleF r, PointF offset) {
PointF oldLoc = r.Location;
return new RectangleF(new PointF(oldLoc.X+offset.X, oldLoc.Y+offset.Y), r.Size);
}
(Made uglier than it should by be the astounding lack of an addition operator for PointF, but that's another issue.) Is there a simpler way to do this?
RectangleF is a struct i.e. a value type. Consider the following:
public class Program
{
struct S
{
public int i;
}
static void Main(string[] args)
{
S s1 = new S();
S s2 = s1;
s1.i = 5;
Console.WriteLine(s1.i);
Console.WriteLine(s2.i);
}
}
The output is:
5
0
Because S is a struct i.e. s2 is a copy of s1.
A Rect is a struct, a value type.
To clone it just assign it to a new variable.
Here is an example function:
public void DrawSquare(int x, int y, Color boxColor = Color.Black)
{
//Code to draw the square goes here
}
The compiler keeps giving me the error: Default parameter value for 'boxColor'must be a compile-time constant
I have tried
Color.Black,
Color.FromKnownColor(KnownColor.Black), and
Color.FromArgb(0, 0, 0)
How do I make Color.Black be the default color? Also, I do not want to use a string Black to specify it (which I know would work). I want the Color.Black value.
Color.Black is a static, not a constant, so no, you cannot do this.
To use a default, you can make the parameter nullable (Color?), and if it is null, then set it to Black.
Do this:
void foo(... Color boxColor = default(Color))
{
if(object.Equals(boxColor, default(Color))) boxColor = Color.Black;
// ...
}
Quick aside: I like to use object.Equals static method because it's a consistent way to write an equality comparison. With reference types such as string, str.Equals("abc") can throw NRE, whereas string.Equals(str, "abc"[,StringComparison.___]) will not. Color is a value type and therefore will never be null, but it's better to be consistent in code style, especially at zero additional cost. Obviously this doesn't apply to primitives such as int and even DateTime, where == clearly states/communicates the mathematical equality comparison.
Or, with nullables (credit to Brian Ball's answer):
void foo(... Color? boxColor = null)
{
if(boxColor == null) boxColor = Color.Black;
// ...
}
What's wrong with keeping it simple?
public void DrawSquare(int x, int y)
{
DrawSquare(x,y,Color.Black);
}
public void DrawSquare(int x, int y, Color color)
{
// Do your thing.
}