C/C++ Interoperability Naming Conventions with C# - c#

Consider the following Win32 API struct:
typedef struct _SECURITY_ATTRIBUTES {
DWORD nLength;
LPVOID lpSecurityDescriptor;
BOOL bInheritHandle;
} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;
When porting this object to C#, should I follow the name naming conventions used here, like so:
public struct _SECURITY_ATTRIBUTES
{
public int nLength;
public unsafe byte* lpSecurityDescriptor;
public int bInheritHandle;
}
or can I go all out, and write my struct in a C# style, like so:
public struct SecurityAttributes
{
private int length;
private unsafe byte* securityDescriptor;
private int bInheritHandle;
public Int32 Length
{
get { return this.length; }
set { this.length = value; }
}
public Byte* SecurityDescriptor
{
get { return this.seurityDescriptor; }
set { this.securityDescriptor = value; }
}
public Int32 InheritHandle
{
get { return this.bInheritHandle; }
set { this.bInheritHandle = value; }
}
public SecurityAttributes(int length, byte* securityDescriptor, int inheritHandle)
{
this.length = length;
this.securityDescriptor = securityDescriptor;
this.inheritHandle = inheritHandle;
}
}
Whilst the second approach seems much more elegant, I would like to know if it is advisable to invoke native functionality using a struct written in that fashion, or if there are any other pitfalls when porting structs from C/C++.

This comes down to your personal preference. Your primary consideration in which approach to chose should be ease of code maintenance. Personally, I favor sticking with the exact same names as those used in the C declaration, because it makes it easier to understand what I'm looking at. For example, if I define a struct like so:
/// <summary>
/// Unmanaged sockaddr_in structure from Ws2def.h.
/// </summary>
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct sockaddr_in
{
/// <summary>
/// short sa_family;
/// </summary>
public short sa_family;
/// <summary>
/// unsigned short sin_port;
/// </summary>
public ushort sin_port;
/// <summary>
/// struct in_addr addr;
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I1, SizeConst = 4)]
public byte[] addr;
/// <summary>
/// char sin_zero[8];
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I1, SizeConst = 8)]
public byte[] sin_zero;
}
Then later I or a co-worker want to know just what the heck sa_family is, we can just search for documentation on sa_family. If I instead had a Family property, I would have the extra step of figuring out that it maps to sa_family.
Of course, I could put nicely named getters and setters on the struct, e.g., public short Family... However, I try to hide interop structs and methods behind an easier-to-use interface. Spiffing up the low-level interop definitions just doesn't seem necessary.

I think this should not be a personal preference. If you are porting a code to another language, you should apply the conventions of the language that you are porting to.
I would certainly use C# conventions since the code will be used by C# developers, not C/C++ developers, right? Otherwise we would be still using ugly _int32 DWORD like code in C#.
Here are some good guides for C# conventions:
C# Coding Standards - and Naming Conventions
C# Coding Conventions (C# Programming Guide)

I am adding this answer for the sake of completeness. It combines points from Mert's and dgvid's answers. Here is an example using the Win32 RECT structure.
C/C++ definition:
typedef struct _RECT {
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT, *PRECT;
C# definition:
namespace NetBlast.Runtime.PlatformInvoke.Windows
{
#region USING
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
#endregion
/// <summary>
/// The Rect (RECT) structure defines the coordinates of the upper-left and lower-right corners of a rectangle.
/// </summary>
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct Rect : IEquatable<Rect>, IEquatable<Rectangle>, ICloneable
{
#region CONSTANTS
#endregion
#region VARIABLES
/// <summary>
/// Win32 RECT.left value.
/// </summary>
private int left;
/// <summary>
/// Win32 RECT.top value.
/// </summary>
private int top;
/// <summary>
/// Win32 RECT.right value.
/// </summary>
private int right;
/// <summary>
/// Win32 RECT.bottom value.
/// </summary>
private int bottom;
#endregion
#region PROPERTIES
/// <summary>
/// Gets or sets the x-coordinate of the upper-left corner of the rectangle.
/// </summary>
public Int32 Left
{
get { return this.left; }
set { this.left = value; }
}
/// <summary>
/// Gets or sets the y-coordinate of the upper-left corner of the rectangle.
/// </summary>
public Int32 Top
{
get { return this.top; }
set { this.top = value; }
}
/// <summary>
/// Gets or sets the x-coordinate of the lower-right corner of the rectangle.
/// </summary>
public Int32 Right
{
get { return this.right; }
set { this.right = value; }
}
/// <summary>
/// Gets or sets the y-coordinate of the lower-right corner of the rectangle.
/// </summary>
public Int32 Bottom
{
get { return this.bottom; }
set { this.bottom = value; }
}
/// <summary>
/// Gets or sets the height of the rectangle.
/// </summary>
public Int32 Height
{
get { return this.bottom - this.top; }
set { this.bottom = value + this.top; }
}
/// <summary>
/// Gets or sets the width of the rectangle.
/// </summary>
public Int32 Width
{
get { return this.right - this.left; }
set { this.right = value + this.left; }
}
/// <summary>
/// Gets or sets the top, left location of the rectangle.
/// </summary>
public Point Location
{
get
{
return new Point(this.left, this.top);
}
set
{
this.right = this.left - value.X;
this.bottom = this.top - value.Y;
this.left = value.X;
this.top = value.Y;
}
}
/// <summary>
/// Gets or sets the size of the rectangle.
/// </summary>
public Size Size
{
get
{
return new Size(this.Width, this.Height);
}
set
{
this.right = value.Width + this.left;
this.bottom = value.Height + this.top;
}
}
#endregion
#region CONSTRUCTORS / FINALIZERS
/// <summary>
/// Initializes a new instance of the <see cref="Rect" /> struct.
/// </summary>
/// <param name="location">The top, left location of the rectangle.</param>
/// <param name="size">The size of the rectangle.</param>
public Rect(Point location, Size size)
{
this.left = default(int);
this.top = default(int);
this.right = default(int);
this.bottom = default(int);
this.Location = location;
this.Size = size;
}
/// <summary>
/// Initializes a new instance of the <see cref="Rect" /> struct.
/// </summary>
/// <param name="left">The x-coordinate of the upper-left corner of the rectangle.</param>
/// <param name="top">The y-coordinate of the upper-left corner of the rectangle.</param>
/// <param name="right">The x-coordinate of the lower-right corner of the rectangle.</param>
/// <param name="bottom">The y-coordinate of the lower-right corner of the rectangle.</param>
public Rect(int left, int top, int right, int bottom)
{
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
}
#endregion
#region OPERATORS
/// <summary>
/// Provides implicit casting from Rect to Rectangle.
/// </summary>
/// <param name="rectangle">The Rect instance to cast.</param>
/// <returns>A Rectangle representation of the Rect instance.</returns>
public static implicit operator Rectangle(Rect rectangle)
{
return new Rectangle(rectangle.Location, rectangle.Size);
}
/// <summary>
/// Provides implicit casting from Rectangle to Rect.
/// </summary>
/// <param name="rectangle">The Rectangle instance to cast.</param>
/// <returns>A Rect representation of the Rectangle instance.</returns>
public static implicit operator Rect(Rectangle rectangle)
{
return new Rect(rectangle.Location, rectangle.Size);
}
/// <summary>
/// Performs an equality check between two instances of Rect.
/// </summary>
/// <param name="a">Instance a of Rect.</param>
/// <param name="b">Instance b of Rect.</param>
/// <returns>True if the instances are equal, otherwise false.</returns>
public static bool operator ==(Rect a, Rect b)
{
return a.Equals(b);
}
/// <summary>
/// Performs an inequality check between two instances of Rect.
/// </summary>
/// <param name="a">Instance a of Rect.</param>
/// <param name="b">Instance b of Rect.</param>
/// <returns>True if the instances are not equal, otherwise false.</returns>
public static bool operator !=(Rect a, Rect b)
{
return !a.Equals(b);
}
#endregion
#region STATIC METHODS
#endregion
#region INSTANCE METHODS
/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
/// <param name="obj">An object to compare with this object.</param>
/// <returns>True if the instances are not equal, otherwise false.</returns>
public override bool Equals(object obj)
{
return this.Equals((Rect)obj);
}
/// <summary>
/// Serves as a hash function for this instance of Rect.
/// </summary>
/// <returns>A hash code for the current Rect.</returns>
public override int GetHashCode()
{
return ObjectUtilities.CreateHashCode(this.left, this.top, this.right, this.bottom);
}
/// <summary>
/// Returns a string representation of this instance.
/// </summary>
/// <returns>A string representation of this instance.</returns>
public override string ToString()
{
return string.Format("Left: {0}; Top: {1}; Right: {2}; Bottom: {3};", this.left, this.top, this.right, this.bottom);
}
/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
/// <param name="other">A Rect instance to compare with this object.</param>
/// <returns>True if the instances are not equal, otherwise false.</returns>
public bool Equals(Rect other)
{
return this.left == other.left
&& this.top == other.top
&& this.right == other.right
&& this.bottom == other.bottom;
}
/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
/// <param name="other">A Rectangle instance to compare with this object.</param>
/// <returns>True if the instances are not equal, otherwise false.</returns>
public bool Equals(Rectangle other)
{
return this.left == other.Left
&& this.top == other.Top
&& this.right == other.Right
&& this.bottom == other.Bottom;
}
/// <summary>
/// Returns a clone of this Rect instance.
/// </summary>
/// <returns>A clone of this Rect instance.</returns>
public object Clone()
{
return new Rect(this.left, this.top, this.right, this.bottom);
}
#endregion
#region DELEGATES & EVENTS
#endregion
#region CLASSES & STRUCTURES
#endregion
}
}
I feel that this will provide a somewhat complete solution, and should map appropriately when used with native code calls.
Additional work:
This struct currently allows Size, Point to be used from the System.Drawing namespace. Since Win32 also has Size and Point structures, it will be appropriate to allow use of these too.

Related

Making smaller Bitmaps from a Bitmap object [duplicate]

This question already has answers here:
How do I crop an image using C#?
(15 answers)
Closed 2 years ago.
I have a Bitmap object of a hand-written survey (see survey image below) which contains various checkboxes. I am using an algorithm to compare a Bitmap of a blank, unmarked checkbox against a Bitmap of the same checkbox (which may or may not be marked), in order to determine if the checkbox has been marked or not.
Would it be possible to break the main survey Bitmap into smaller Bitmap objects? For example, with question 14 below I would like to make smaller Bitmap objects out of the red squares given the startX, endX, startY and endY locations of each checkbox.
I have an open source program called Transparency Maker that I am working on as we speak that could help you do this, or at least give you some guides on how to get started.
My project reads in a Bitmap (.png or .jpg) and creates a Pixel Database. Actually it is a List of PixelInformation objects.
LoadPixelDatabase Method
My Windows Forms app has a PictureBox called Canvas for the background image.
You could easily pass in an image as a parameter instead.
using System.Drawing;
using System.Drawing.Imaging;
public void LoadPixelDatabase()
{
// if we do not have a BackgroundImage yet
if (this.Canvas.BackgroundImage == null)
{
// to do: Show message
// bail
return;
}
// Create a Bitmap from the Source image
Bitmap source = new Bitmap(this.Canvas.BackgroundImage);
// Code To Lockbits
BitmapData bitmapData = source.LockBits(new Rectangle(0, 0, source.Width,
source.Height), ImageLockMode.ReadWrite, source.PixelFormat);
IntPtr pointer = bitmapData.Scan0;
int size = Math.Abs(bitmapData.Stride) * source.Height;
byte[] pixels = new byte[size];
Marshal.Copy(pointer, pixels, 0, size);
// End Code To Lockbits
// Marshal.Copy(pixels,0,pointer, size);
source.UnlockBits(bitmapData);
// test only
int length = pixels.Length;
// Create a new instance of a 'PixelDatabase' object.
this.PixelDatabase = new PixelDatabase();
// locals
Color color = Color.FromArgb(0, 0, 0);
int red = 0;
int green = 0;
int blue = 0;
int alpha = 0;
// variables to hold height and width
int width = source.Width;
int height = source.Height;
int x = -1;
int y = 0;
// Iterating the pixel array, every 4th byte is a new pixel,faster than GetPixel
for (int a = 0; a < pixels.Length; a = a + 4)
{
// increment the value for x
x++;
// every new column
if (x >= width)
{
// reset x
x = 0;
// Increment the value for y
y++;
}
// get the values for r, g, and blue
blue = pixels[a];
green = pixels[a + 1];
red = pixels[a + 2];
alpha = pixels[a + 3];
// create a color
color = Color.FromArgb(alpha, red, green, blue);
// Add this point
PixelInformation pixelInformation = this.PixelDatabase.AddPixel(color, x, y);
}
// Create a DirectBitmap
this.DirectBitmap = new DirectBitmap(source.Width, source.Height);
// Now we must copy over the Pixels from the PixelDatabase to the DirectBitmap
if ((this.HasPixelDatabase) && (ListHelper.HasOneOrMoreItems(this.PixelDatabase.Pixels)))
{
// iterate the pixels
foreach (PixelInformation pixel in this.PixelDatabase.Pixels)
{
// Set the pixel at this spot
DirectBitmap.SetPixel(pixel.X, pixel.Y, pixel.Color);
}
}
}
The way my app could help you is, once the PixelDatabase is loaded, you can perform LinqQueries such as:
// Get the pixels in the X range
pixels = pixels.Where(x => x.X >= MinValue && x.X <= MaxValue).ToList();
// Get the Y range
pixels = pixels.Where(x => x.Y >= MinValue && x.Y <= MaxValue).ToList();
(I know the above could be written in 1 line, it is hard to post here).
Once you have your pixels, you can create a new image:
Image image = new Bitmap(width, height);
Create another DirectBitmap for the new image, and then copy the pixels from the query above into your new image and save.
// Save the bitmap
bitmap.Save(fileName);
PixelDatabase.cs
#region using statements
using DataJuggler.Core.UltimateHelper;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
#endregion
namespace TransparencyMaker.Objects
{
#region class PixelDatabase
/// <summary>
/// This class represents a collection of PixelInformation objects
/// </summary>
public class PixelDatabase
{
#region Private Variables
private List<PixelInformation> pixels;
#endregion
#region Constructor
/// <summary>
/// Create a new instance of a PixelDatabase object
/// </summary>
public PixelDatabase()
{
// Create a new collection of 'PixelInformation' objects.
this.Pixels = new List<PixelInformation>();
}
#endregion
#region Methods
#region AddPixel(Color color, int x, int y)
/// <summary>
/// method returns the Pixel
/// </summary>
public PixelInformation AddPixel(Color color, int x, int y)
{
// Create a pixe
PixelInformation pixel = new PixelInformation();
// Set the color
pixel.Color = color;
// Set the values for x and y
pixel.X = x;
pixel.Y = y;
/// The Index is set before the count increments when this item is added
pixel.Index = this.Pixels.Count;
// Add this pixel
this.Pixels.Add(pixel);
// return value
return pixel;
}
#endregion
#endregion
#region Properties
#region HasOneOrMorePixels
/// <summary>
/// This property returns true if this object has one or more 'Pixels'.
/// </summary>
public bool HasOneOrMorePixels
{
get
{
// initial value
bool hasOneOrMorePixels = ((this.HasPixels) && (this.Pixels.Count > 0));
// return value
return hasOneOrMorePixels;
}
}
#endregion
#region HasPixels
/// <summary>
/// This property returns true if this object has a 'Pixels'.
/// </summary>
public bool HasPixels
{
get
{
// initial value
bool hasPixels = (this.Pixels != null);
// return value
return hasPixels;
}
}
#endregion
#region Pixels
/// <summary>
/// This property gets or sets the value for 'Pixels'.
/// </summary>
public List<PixelInformation> Pixels
{
get { return pixels; }
set { pixels = value; }
}
#endregion
#endregion
}
#endregion
}
PixelInformation.cs
#region using statements
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
#endregion
namespace TransparencyMaker.Objects
{
#region class PixelInformation
/// <summary>
/// This class is used to contain information about a pixel, and
/// </summary>
public class PixelInformation
{
#region Private Variables
private int index;
private Color color;
private int x;
private int y;
#endregion
#region Constructor
/// <summary>
/// Create a new instance of a PixelInformationObject
/// </summary>
public PixelInformation()
{
// Perform initializations for this object
Init();
}
#endregion
#region Methods
#region Init()
/// <summary>
/// This method performs initializations for this object.
/// </summary>
public void Init()
{
}
#endregion
#region ToString()
/// <summary>
/// method returns the String
/// </summary>
public override string ToString()
{
// Create a new instance of a 'StringBuilder' object.
StringBuilder sb = new StringBuilder();
// Append the string
sb.Append("R:");
sb.Append(Red);
sb.Append("G:");
sb.Append(Green);
sb.Append("B:");
sb.Append(Blue);
sb.Append("T:");
sb.Append(Total);
// set the return value
string toString = sb.ToString();
// return value
return toString;
}
#endregion
#endregion
#region Properties
#region Alpha
/// <summary>
/// This property gets or sets the value for 'Alpha'.
/// </summary>
public int Alpha
{
get
{
// initial value
int alpha = Color.A;
// return value
return alpha;
}
}
#endregion
#region Blue
/// <summary>
/// This property gets or sets the value for 'Blue'.
/// </summary>
public int Blue
{
get
{
// initial value
int blue = Color.B;
// return value
return blue;
}
}
#endregion
#region BlueGreen
/// <summary>
/// This read only property returns the value for 'BlueGreen'.
/// </summary>
public int BlueGreen
{
get
{
// initial value
int blueGreen = Blue + Green;
// return value
return blueGreen;
}
}
#endregion
#region BlueRed
/// <summary>
/// This read only property returns the value for 'BlueRed'.
/// </summary>
public int BlueRed
{
get
{
// initial value
int blueRed = Blue + Red;
// return value
return blueRed;
}
}
#endregion
#region Color
/// <summary>
/// This property gets or sets the value for 'Color'.
/// </summary>
public Color Color
{
get { return color; }
set { color = value; }
}
#endregion
#region Green
/// <summary>
/// This property gets or sets the value for 'Green'.
/// </summary>
public int Green
{
get
{
// initial value
int green = Color.G;
// return value
return green;
}
}
#endregion
#region GreenRed
/// <summary>
/// This read only property returns the value for 'GreenRed'.
/// </summary>
public int GreenRed
{
get
{
// initial value
int greenRed = Green + Red;
// return value
return greenRed;
}
}
#endregion
#region Index
/// <summary>
/// This property gets or sets the value for 'Index'.
/// </summary>
public int Index
{
get { return index; }
set { index = value; }
}
#endregion
#region Red
/// <summary>
/// This property gets or sets the value for 'Red'.
/// </summary>
public int Red
{
get
{
// initial value
int red = this.Color.R;
// return value
return red;
}
}
#endregion
#region Total
/// <summary>
/// This read only property returns the value for 'Total'.
/// </summary>
public int Total
{
get
{
// initial value
int total = Red + Green + Blue;
// return value
return total;
}
}
#endregion
#region X
/// <summary>
/// This property gets or sets the value for 'X'.
/// </summary>
public int X
{
get { return x; }
set { x = value; }
}
#endregion
#region Y
/// <summary>
/// This property gets or sets the value for 'Y'.
/// </summary>
public int Y
{
get { return y; }
set { y = value; }
}
#endregion
#endregion
}
#endregion
}
DirectBitmap.cs
This class here is called DirectBitmap, I didn't write it but I wish I knew who the author was to give them credit as it sped up my app by quite a bit.
#region using statements
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using TransparencyMaker.Objects;
#endregion
namespace TransparencyMaker.Util
{
#region class DirectBitmap
/// <summary>
/// This class is used as a faster alternative to GetPixel and SetPixel
/// </summary>
public class DirectBitmap : IDisposable
{
#region Private Variables
private History history;
#endregion
#region Constructor
/// <summary>
/// Create a new instance of a 'DirectBitmap' object.
/// </summary>
public DirectBitmap(int width, int height)
{
Width = width;
Height = height;
Bits = new Int32[width * height];
BitsHandle = GCHandle.Alloc(Bits, GCHandleType.Pinned);
Bitmap = new Bitmap(width, height, width * 4, PixelFormat.Format32bppPArgb, BitsHandle.AddrOfPinnedObject());
}
#endregion
#region Methods
#region Dispose()
/// <summary>
/// method Dispose
/// </summary>
public void Dispose()
{
if (Disposed) return;
Disposed = true;
Bitmap.Dispose();
BitsHandle.Free();
}
#endregion
#region GetPixel(int x, int y)
/// <summary>
/// method Get Pixel
/// </summary>
public Color GetPixel(int x, int y)
{
int index = x + (y * Width);
int col = Bits[index];
Color result = Color.FromArgb(col);
return result;
}
#endregion
#region HandleHistory(int x, int y, Guid historyId, Color previousColor)
/// <summary>
/// This method Handle History
/// </summary>
public void HandleHistory(int x, int y, Guid historyId, Color previousColor)
{
// If the History object exists
if ((!this.HasHistory) || (History.Id != historyId) && (historyId != Guid.Empty))
{
// here a new History object is created and the pixels are added to it instead
this.History = new History(historyId);
}
// If the History object exists
if (this.HasHistory)
{
// Create a new instance of a 'PixelInformation' object.
PixelInformation pixel = new PixelInformation();
pixel.X = x;
pixel.Y = y;
pixel.Color = previousColor;
// Add this pixel to history
this.History.ChangedPixels.Add(pixel);
}
}
#endregion
#region SetPixel(int x, int y, Color color)
/// <summary>
/// method Set Pixel
/// </summary>
public void SetPixel(int x, int y, Color color)
{
int index = x + (y * Width);
int col = color.ToArgb();
Bits[index] = col;
}
#endregion
#region SetPixel(int x, int y, Color color, Guid historyId, Color prevoiusColor)
/// <summary>
/// This method Sets a Pixel and it includes a historyId so any changes are stored in history
/// </summary>
public void SetPixel(int x, int y, Color color, Guid historyId, Color prevoiusColor)
{
// history has to be set before the pixel is set
// Handle the history
HandleHistory(x, y, historyId, prevoiusColor);
int index = x + (y * Width);
int col = color.ToArgb();
Bits[index] = col;
}
#endregion
#region UndoChanges()
/// <summary>
/// This method Undo Changes
/// </summary>
public void UndoChanges()
{
// If the History object exists
if ((this.HasHistory) && (this.History.HasChangedPixels))
{
// get the changed pixels
List<PixelInformation> pixels = this.History.ChangedPixels;
// Iterate the collection of PixelInformation objects
foreach (PixelInformation pixel in pixels)
{
// for debugging only
int alpha = pixel.Color.A;
// Restore this pixel
SetPixel(pixel.X, pixel.Y, pixel.Color);
}
// Remove the history
this.History = null;
}
}
#endregion
#endregion
#region Properties
#region Bitmap
/// <summary>
/// method [Enter Method Description]
/// </summary>
public Bitmap Bitmap { get; private set; }
#endregion
#region Bits
/// <summary>
/// method [Enter Method Description]
/// </summary>
public Int32[] Bits { get; private set; }
#endregion
#region BitsHandle
/// <summary>
/// This is a ptr to the garbage collector
/// </summary>
protected GCHandle BitsHandle { get; private set; }
#endregion
#region Disposed
/// <summary>
/// method [Enter Method Description]
/// </summary>
public bool Disposed { get; private set; }
#endregion
#region HasHistory
/// <summary>
/// This property returns true if this object has a 'History'.
/// </summary>
public bool HasHistory
{
get
{
// initial value
bool hasHistory = (this.History != null);
// return value
return hasHistory;
}
}
#endregion
#region Height
/// <summary>
/// method [Enter Method Description]
/// </summary>
public int Height { get; private set; }
#endregion
#region History
/// <summary>
/// This property gets or sets the value for 'History'.
/// </summary>
public History History
{
get { return history; }
set { history = value; }
}
#endregion
#region Width
/// <summary>
/// method [Enter Method Description]
/// </summary>
public int Width { get; private set; }
#endregion
#endregion
}
#endregion
}
Here is the full Project, as it is hard to post a complete application, I tried to show the most relevant parts:
https://github.com/DataJuggler/TransparencyMaker
I have a section on my YouTube channel for TransparencyMaker videos if anyone would care to watch: https://youtu.be/7kfNKyr_oqg
Version 2 is released, but still being polished.

c# transparent spinning wheel (or gif) is just half transparent

Well, first try was with a readily made spinning wheel (a gif). After that, I found a code that dynamically generates a wheel, but no way in both cases to have full transparency.
Depending on what I set as parent (form or panel) and the position on my wheel on form, the spin is just half transparent.
I use C# express (VS 2008).
All I want is a nice wheel in center of form, activated when BG is doing something, but full transparent so I can resize form.
Thanks,
Update:
I worked on some code that is draw a spinning wheel just fine. Almost working except OnPantBackground() which needs to be empty to paint behind, but in this case, a black rectangle is drawn because of ControlStyles.OptimizedDoubleBuffer enabled.
Any suggestions? Thank you.
using System;
using System.Drawing;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing.Drawing2D;
namespace WinFormsControls
{
/// <summary>
/// A label that can be transparent.
/// </summary>
public class TransparentLabel : Control
{
// Constants =========================================================
private const double NumberOfDegreesInCircle = 360;
private const double NumberOfDegreesInHalfCircle = NumberOfDegreesInCircle / 2;
private const int DefaultInnerCircleRadius = 8;
private const int DefaultOuterCircleRadius = 10;
private const int DefaultNumberOfSpoke = 10;
private const int DefaultSpokeThickness = 4;
private readonly Color DefaultColor = Color.DarkGray;
private const int MacOSXInnerCircleRadius = 5;
private const int MacOSXOuterCircleRadius = 11;
private const int MacOSXNumberOfSpoke = 12;
private const int MacOSXSpokeThickness = 2;
private const int FireFoxInnerCircleRadius = 6;
private const int FireFoxOuterCircleRadius = 7;
private const int FireFoxNumberOfSpoke = 9;
private const int FireFoxSpokeThickness = 4;
private const int IE7InnerCircleRadius = 8;
private const int IE7OuterCircleRadius = 9;
private const int IE7NumberOfSpoke = 24;
private const int IE7SpokeThickness = 4;
// Enumeration =======================================================
public enum StylePresets
{
MacOSX,
Firefox,
IE7,
Custom
}
// Attributes ========================================================
private Timer m_Timer;
private bool m_IsTimerActive;
private int m_NumberOfSpoke;
private int m_SpokeThickness;
private int m_ProgressValue;
private int m_OuterCircleRadius;
private int m_InnerCircleRadius;
private PointF m_CenterPoint;
private Color m_Color;
private Color[] m_Colors;
private double[] m_Angles;
private StylePresets m_StylePreset;
// Properties ========================================================
/// <summary>
/// Gets or sets the lightest color of the circle.
/// </summary>
/// <value>The lightest color of the circle.</value>
[TypeConverter("System.Drawing.ColorConverter"),
Category("LoadingCircle"),
Description("Sets the color of spoke.")]
public Color Color
{
get
{
return m_Color;
}
set
{
m_Color = value;
GenerateColorsPallet();
Invalidate();
}
}
/// <summary>
/// Gets or sets the outer circle radius.
/// </summary>
/// <value>The outer circle radius.</value>
[System.ComponentModel.Description("Gets or sets the radius of outer circle."),
System.ComponentModel.Category("LoadingCircle")]
public int OuterCircleRadius
{
get
{
if (m_OuterCircleRadius == 0)
m_OuterCircleRadius = DefaultOuterCircleRadius;
return m_OuterCircleRadius;
}
set
{
m_OuterCircleRadius = value;
Invalidate();
}
}
/// <summary>
/// Gets or sets the inner circle radius.
/// </summary>
/// <value>The inner circle radius.</value>
[System.ComponentModel.Description("Gets or sets the radius of inner circle."),
System.ComponentModel.Category("LoadingCircle")]
public int InnerCircleRadius
{
get
{
if (m_InnerCircleRadius == 0)
m_InnerCircleRadius = DefaultInnerCircleRadius;
return m_InnerCircleRadius;
}
set
{
m_InnerCircleRadius = value;
Invalidate();
}
}
/// <summary>
/// Gets or sets the number of spoke.
/// </summary>
/// <value>The number of spoke.</value>
[System.ComponentModel.Description("Gets or sets the number of spoke."),
System.ComponentModel.Category("LoadingCircle")]
public int NumberSpoke
{
get
{
if (m_NumberOfSpoke == 0)
m_NumberOfSpoke = DefaultNumberOfSpoke;
return m_NumberOfSpoke;
}
set
{
if (m_NumberOfSpoke != value && m_NumberOfSpoke > 0)
{
m_NumberOfSpoke = value;
GenerateColorsPallet();
GetSpokesAngles();
Invalidate();
}
}
}
/// <summary>
/// Gets or sets a value indicating whether this <see cref="T:LoadingCircle"/> is active.
/// </summary>
/// <value><c>true</c> if active; otherwise, <c>false</c>.</value>
[System.ComponentModel.Description("Gets or sets the number of spoke."),
System.ComponentModel.Category("LoadingCircle")]
public bool Active
{
get
{
return m_IsTimerActive;
}
set
{
m_IsTimerActive = value;
ActiveTimer();
}
}
/// <summary>
/// Gets or sets the spoke thickness.
/// </summary>
/// <value>The spoke thickness.</value>
[System.ComponentModel.Description("Gets or sets the thickness of a spoke."),
System.ComponentModel.Category("LoadingCircle")]
public int SpokeThickness
{
get
{
if (m_SpokeThickness <= 0)
m_SpokeThickness = DefaultSpokeThickness;
return m_SpokeThickness;
}
set
{
m_SpokeThickness = value;
Invalidate();
}
}
/// <summary>
/// Gets or sets the rotation speed.
/// </summary>
/// <value>The rotation speed.</value>
[System.ComponentModel.Description("Gets or sets the rotation speed. Higher the slower."),
System.ComponentModel.Category("LoadingCircle")]
public int RotationSpeed
{
get
{
return m_Timer.Interval;
}
set
{
if (value > 0)
m_Timer.Interval = value;
}
}
/// <summary>
/// Quickly sets the style to one of these presets, or a custom style if desired
/// </summary>
/// <value>The style preset.</value>
[Category("LoadingCircle"),
Description("Quickly sets the style to one of these presets, or a custom style if desired"),
DefaultValue(typeof(StylePresets), "Custom")]
public StylePresets StylePreset
{
get { return m_StylePreset; }
set
{
m_StylePreset = value;
switch (m_StylePreset)
{
case StylePresets.MacOSX:
SetCircleAppearance(MacOSXNumberOfSpoke,
MacOSXSpokeThickness, MacOSXInnerCircleRadius,
MacOSXOuterCircleRadius);
break;
case StylePresets.Firefox:
SetCircleAppearance(FireFoxNumberOfSpoke,
FireFoxSpokeThickness, FireFoxInnerCircleRadius,
FireFoxOuterCircleRadius);
break;
case StylePresets.IE7:
SetCircleAppearance(IE7NumberOfSpoke,
IE7SpokeThickness, IE7InnerCircleRadius,
IE7OuterCircleRadius);
break;
case StylePresets.Custom:
SetCircleAppearance(DefaultNumberOfSpoke,
DefaultSpokeThickness,
DefaultInnerCircleRadius,
DefaultOuterCircleRadius);
break;
}
}
}
/// <summary>
/// Creates a new <see cref="TransparentLabel"/> instance.
/// </summary>
public TransparentLabel()
{
TabStop = false;
InitializeComponent();
SetStyle(ControlStyles.UserPaint, true);
//SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
m_Color = DefaultColor;
GenerateColorsPallet();
GetSpokesAngles();
GetControlCenterPoint();
m_Timer = new Timer();
m_Timer.Tick += new EventHandler(aTimer_Tick);
ActiveTimer();
this.Resize += new EventHandler(LoadingCircle_Resize);
this.DoubleBuffered = true;
this.SetStyle(ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.ResizeRedraw |
ControlStyles.ContainerControl |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.SupportsTransparentBackColor
, true);
}
// Events ============================================================
/// <summary>
/// Handles the Resize event of the LoadingCircle control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="T:System.EventArgs"/> instance containing the event data.</param>
void LoadingCircle_Resize(object sender, EventArgs e)
{
GetControlCenterPoint();
}
/// <summary>
/// Handles the Tick event of the aTimer control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="T:System.EventArgs"/> instance containing the event data.</param>
void aTimer_Tick(object sender, EventArgs e)
{
m_ProgressValue = ++m_ProgressValue % m_NumberOfSpoke;
Invalidate();
}
/// <summary>
/// Gets the creation parameters.
/// </summary>
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x20;
return cp;
}
}
// Overridden Methods ================================================
/// <summary>
/// Retrieves the size of a rectangular area into which a control can be fitted.
/// </summary>
/// <param name="proposedSize">The custom-sized area for a control.</param>
/// <returns>
/// An ordered pair of type <see cref="T:System.Drawing.Size"></see> representing the width and height of a rectangle.
/// </returns>
public override Size GetPreferredSize(Size proposedSize)
{
proposedSize.Width =
(m_OuterCircleRadius + m_SpokeThickness) * 2;
return proposedSize;
}
/// <summary>
/// Paints the background.
/// </summary>
/// <param name="e">E.</param>
///
protected override void OnPaintBackground(PaintEventArgs e)
{
// do nothing
}
/// <summary>
/// Paints the control.
/// </summary>
/// <param name="e">E.</param>
protected override void OnPaint(PaintEventArgs e)
{
//DrawText();
if (m_NumberOfSpoke > 0)
{
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
int intPosition = m_ProgressValue;
for (int intCounter = 0; intCounter < m_NumberOfSpoke; intCounter++)
{
intPosition = intPosition % m_NumberOfSpoke;
DrawLine(e.Graphics,
GetCoordinate(m_CenterPoint, m_InnerCircleRadius, m_Angles[intPosition]),
GetCoordinate(m_CenterPoint, m_OuterCircleRadius, m_Angles[intPosition]),
m_Colors[intCounter], m_SpokeThickness);
intPosition++;
}
}
base.OnPaint(e);
}
/*
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == 0x000F)
{
DrawText();
}
}
private void DrawText()
{
using (Graphics graphics = CreateGraphics())
using (SolidBrush brush = new SolidBrush(ForeColor))
{
SizeF size = graphics.MeasureString(Text, Font);
// first figure out the top
float top = 0;
switch (textAlign)
{
case ContentAlignment.MiddleLeft:
case ContentAlignment.MiddleCenter:
case ContentAlignment.MiddleRight:
top = (Height - size.Height) / 2;
break;
case ContentAlignment.BottomLeft:
case ContentAlignment.BottomCenter:
case ContentAlignment.BottomRight:
top = Height - size.Height;
break;
}
float left = -1;
switch (textAlign)
{
case ContentAlignment.TopLeft:
case ContentAlignment.MiddleLeft:
case ContentAlignment.BottomLeft:
if (RightToLeft == RightToLeft.Yes)
left = Width - size.Width;
else
left = -1;
break;
case ContentAlignment.TopCenter:
case ContentAlignment.MiddleCenter:
case ContentAlignment.BottomCenter:
left = (Width - size.Width) / 2;
break;
case ContentAlignment.TopRight:
case ContentAlignment.MiddleRight:
case ContentAlignment.BottomRight:
if (RightToLeft == RightToLeft.Yes)
left = -1;
else
left = Width - size.Width;
break;
}
graphics.DrawString(Text, Font, brush, left, top);
}
}
*/
/*
/// <summary>
/// Gets or sets the text associated with this control.
/// </summary>
/// <returns>
/// The text associated with this control.
/// </returns>
public override string Text
{
get
{
return base.Text;
}
set
{
base.Text = value;
RecreateHandle();
}
}
/// <summary>
/// Gets or sets a value indicating whether control's elements are aligned to support locales using right-to-left fonts.
/// </summary>
/// <value></value>
/// <returns>
/// One of the <see cref="T:System.Windows.Forms.RightToLeft"/> values. The default is <see cref="F:System.Windows.Forms.RightToLeft.Inherit"/>.
/// </returns>
/// <exception cref="T:System.ComponentModel.InvalidEnumArgumentException">
/// The assigned value is not one of the <see cref="T:System.Windows.Forms.RightToLeft"/> values.
/// </exception>
public override RightToLeft RightToLeft
{
get
{
return base.RightToLeft;
}
set
{
base.RightToLeft = value;
RecreateHandle();
}
}
/// <summary>
/// Gets or sets the font of the text displayed by the control.
/// </summary>
/// <value></value>
/// <returns>
/// The <see cref="T:System.Drawing.Font"/> to apply to the text displayed by the control. The default is the value of the <see cref="P:System.Windows.Forms.Control.DefaultFont"/> property.
/// </returns>
public override Font Font
{
get
{
return base.Font;
}
set
{
base.Font = value;
RecreateHandle();
}
}
private ContentAlignment textAlign = ContentAlignment.TopLeft;
/// <summary>
/// Gets or sets the text alignment.
/// </summary>
public ContentAlignment TextAlign
{
get { return textAlign; }
set
{
textAlign = value;
RecreateHandle();
}
}
*/
private void InitializeComponent()
{
this.SuspendLayout();
this.ResumeLayout(false);
}
// Methods ===========================================================
/// <summary>
/// Darkens a specified color.
/// </summary>
/// <param name="_objColor">Color to darken.</param>
/// <param name="_intPercent">The percent of darken.</param>
/// <returns>The new color generated.</returns>
private Color Darken(Color _objColor, int _intPercent)
{
int intRed = _objColor.R;
int intGreen = _objColor.G;
int intBlue = _objColor.B;
return Color.FromArgb(_intPercent, Math.Min(intRed, byte.MaxValue), Math.Min(intGreen, byte.MaxValue), Math.Min(intBlue, byte.MaxValue));
}
/// <summary>
/// Generates the colors pallet.
/// </summary>
private void GenerateColorsPallet()
{
m_Colors = GenerateColorsPallet(m_Color, Active, m_NumberOfSpoke);
}
/// <summary>
/// Generates the colors pallet.
/// </summary>
/// <param name="_objColor">Color of the lightest spoke.</param>
/// <param name="_blnShadeColor">if set to <c>true</c> the color will be shaded on X spoke.</param>
/// <returns>An array of color used to draw the circle.</returns>
private Color[] GenerateColorsPallet(Color _objColor, bool _blnShadeColor, int _intNbSpoke)
{
Color[] objColors = new Color[NumberSpoke];
// Value is used to simulate a gradient feel... For each spoke, the
// color will be darken by value in intIncrement.
byte bytIncrement = (byte)(byte.MaxValue / NumberSpoke);
//Reset variable in case of multiple passes
byte PERCENTAGE_OF_DARKEN = 0;
for (int intCursor = 0; intCursor < NumberSpoke; intCursor++)
{
if (_blnShadeColor)
{
if (intCursor == 0 || intCursor < NumberSpoke - _intNbSpoke)
objColors[intCursor] = _objColor;
else
{
// Increment alpha channel color
PERCENTAGE_OF_DARKEN += bytIncrement;
// Ensure that we don't exceed the maximum alpha
// channel value (255)
if (PERCENTAGE_OF_DARKEN > byte.MaxValue)
PERCENTAGE_OF_DARKEN = byte.MaxValue;
// Determine the spoke forecolor
objColors[intCursor] = Darken(_objColor, PERCENTAGE_OF_DARKEN);
}
}
else
objColors[intCursor] = _objColor;
}
return objColors;
}
/// <summary>
/// Gets the control center point.
/// </summary>
private void GetControlCenterPoint()
{
m_CenterPoint = GetControlCenterPoint(this);
}
/// <summary>
/// Gets the control center point.
/// </summary>
/// <returns>PointF object</returns>
private PointF GetControlCenterPoint(Control _objControl)
{
return new PointF(_objControl.Width / 2, _objControl.Height / 2 - 1);
}
/// <summary>
/// Draws the line with GDI+.
/// </summary>
/// <param name="_objGraphics">The Graphics object.</param>
/// <param name="_objPointOne">The point one.</param>
/// <param name="_objPointTwo">The point two.</param>
/// <param name="_objColor">Color of the spoke.</param>
/// <param name="_intLineThickness">The thickness of spoke.</param>
private void DrawLine(Graphics _objGraphics, PointF _objPointOne, PointF _objPointTwo,
Color _objColor, int _intLineThickness)
{
using (Pen objPen = new Pen(new SolidBrush(_objColor), _intLineThickness))
{
objPen.StartCap = LineCap.Round;
objPen.EndCap = LineCap.Round;
_objGraphics.DrawLine(objPen, _objPointOne, _objPointTwo);
}
}
/// <summary>
/// Gets the coordinate.
/// </summary>
/// <param name="_objCircleCenter">The Circle center.</param>
/// <param name="_intRadius">The radius.</param>
/// <param name="_dblAngle">The angle.</param>
/// <returns></returns>
private PointF GetCoordinate(PointF _objCircleCenter, int _intRadius, double _dblAngle)
{
double dblAngle = Math.PI * _dblAngle / NumberOfDegreesInHalfCircle;
return new PointF(_objCircleCenter.X + _intRadius * (float)Math.Cos(dblAngle),
_objCircleCenter.Y + _intRadius * (float)Math.Sin(dblAngle));
}
/// <summary>
/// Gets the spokes angles.
/// </summary>
private void GetSpokesAngles()
{
m_Angles = GetSpokesAngles(NumberSpoke);
}
/// <summary>
/// Gets the spoke angles.
/// </summary>
/// <param name="_shtNumberSpoke">The number spoke.</param>
/// <returns>An array of angle.</returns>
private double[] GetSpokesAngles(int _intNumberSpoke)
{
double[] Angles = new double[_intNumberSpoke];
double dblAngle = (double)NumberOfDegreesInCircle / _intNumberSpoke;
for (int shtCounter = 0; shtCounter < _intNumberSpoke; shtCounter++)
Angles[shtCounter] = (shtCounter == 0 ? dblAngle : Angles[shtCounter - 1] + dblAngle);
return Angles;
}
/// <summary>
/// Actives the timer.
/// </summary>
private void ActiveTimer()
{
if (m_IsTimerActive)
{
m_Timer.Start();
}
else
{
m_Timer.Stop();
m_ProgressValue = 0;
}
GenerateColorsPallet();
Invalidate();
}
/// <summary>
/// Sets the circle appearance.
/// </summary>
/// <param name="numberSpoke">The number spoke.</param>
/// <param name="spokeThickness">The spoke thickness.</param>
/// <param name="innerCircleRadius">The inner circle radius.</param>
/// <param name="outerCircleRadius">The outer circle radius.</param>
public void SetCircleAppearance(int numberSpoke, int spokeThickness,
int innerCircleRadius, int outerCircleRadius)
{
NumberSpoke = numberSpoke;
SpokeThickness = spokeThickness;
InnerCircleRadius = innerCircleRadius;
OuterCircleRadius = outerCircleRadius;
Invalidate();
}
}
}
Sorry for answering my own post, but after testing a lot of projects, modify without success, I finally found one that is almost full transparent
https://www.codeproject.com/Articles/27185/WYSIWYG-Progress-Circle-for-NET-Framework-C
That guy made a very well job almost 10 years ago, at least inner part of spin is copied and re-drawn in OnPaint so quite nice transparent over RichTextBox control where all other projects failed :)
The only small problem is that the circle trail, don't copy the bmp behind so there will always be a comet effect, but I can live with that! Much pleasant effect than other solutions, including few on stackoverflow.
In case anyone will need!
Wow that seems incredibly complicated. I don't know much about wpf, but on iOS what we usually do is load an image that has the exact properties we need (here, transparent background), and just rotate the image to make the spinning effect.
You only need very little logic to make it appear/disappear and rotate. For a very basic spinner you get to create and use that class in a matter of seconds.
At least that's the route I'd go for, instead of writing 300 lines of code to manually handle the spinner :p

Flickering in ListView control (OwnerDraw, Virtual)

This question might be considered a follow-up to Flickering in listview with ownerdraw and virtualmode.
I've got a ListView control in Virtual mode and I attempt to perform custom drawing. Item rendering is done via the following method override:
protected override void OnDrawItem(DrawListViewItemEventArgs eventArgs)
As mentioned in the referenced question, custom drawing introduces flickering on mouse over events. Debugger tells me this happens due to an excessive amount of custom draw events which are fired.
Now - the accepted answer to the referenced question tells us:
This is a bug in .NET's ListView and you cannot get around it by
double buffering.
So, how reliable is that information? Is that really a bug? Or maybe we simply attempt to cut off a part of the messages and hope that it won't alter the visible behavior?
Is this true that if I have my owner drawing routine for the ListView in Virtual Mode, I can suppress these Custom Draw events and only perform my drawing in WM_PAINT or, maybe, this is incorrect for some cases?
What are the prerequisities for the System.Windows.Forms control to be able to do all the painting in WM_PAINT without altering it's initial behavior?
At least for double buffering for OnDrawItem, it is incorrect that there is a bug, but it is a little bit stupid: there is a protected attribute you can set, but you need to override the ListView. I created this kind of class:
public class MyListView : ListView
{
public MyListView()
: base()
{
DoubleBuffered = true;
}
}
And then in my MyForm.Designer.cs file I change the instantiation of the ListView with the following line:
private ListView myListView;
this.myListView = new MyListView();
And OnDrawItem will work like a charm!
I've seen this flickering issue with ListView control in any custom rendering event handlers (DrawItem, DrawSubItem). I tried BeginUpdate()/EndUpdate() and double buffering with no success. I think .NET triggers additional WM_PAINT to all columns to the right of the custom drawn column.
However I found this workaround to a single custom rendered column ListView. It works just fine!
In the columnheader editor, set the custom drawn column as the last column
Change the "DisplayIndex" of the position you want
This should solve the flickering in mouseover or run-time rendering.
Like This Answer in Here, though not sure but,
I think that ListView.BeginUpdate() and ListView.EndUpdate() will solve the problem.
MSDN Thread about This
Maybe In This Way :
protected override void OnDrawItem(DrawListViewItemEventArgs eventArgs)
{
ListView.BeginUpdate();
//Do Works Here
ListView.EndUpdate();
}
Update
Another Alternative may be using a new Thread in BackgroundWorker to Update the ListView...
I implemented this along with BeginUpdate()/EndUpDate() in my application and found it relatively faster than only the BeginUpdate()/EndUpDate()..
Update
I found another working Solution at SO, a Helper class provided by Brian Gillespie :
public enum ListViewExtendedStyles
{
/// <summary>
/// LVS_EX_GRIDLINES
/// </summary>
GridLines = 0x00000001,
/// <summary>
/// LVS_EX_SUBITEMIMAGES
/// </summary>
SubItemImages = 0x00000002,
/// <summary>
/// LVS_EX_CHECKBOXES
/// </summary>
CheckBoxes = 0x00000004,
/// <summary>
/// LVS_EX_TRACKSELECT
/// </summary>
TrackSelect = 0x00000008,
/// <summary>
/// LVS_EX_HEADERDRAGDROP
/// </summary>
HeaderDragDrop = 0x00000010,
/// <summary>
/// LVS_EX_FULLROWSELECT
/// </summary>
FullRowSelect = 0x00000020,
/// <summary>
/// LVS_EX_ONECLICKACTIVATE
/// </summary>
OneClickActivate = 0x00000040,
/// <summary>
/// LVS_EX_TWOCLICKACTIVATE
/// </summary>
TwoClickActivate = 0x00000080,
/// <summary>
/// LVS_EX_FLATSB
/// </summary>
FlatsB = 0x00000100,
/// <summary>
/// LVS_EX_REGIONAL
/// </summary>
Regional = 0x00000200,
/// <summary>
/// LVS_EX_INFOTIP
/// </summary>
InfoTip = 0x00000400,
/// <summary>
/// LVS_EX_UNDERLINEHOT
/// </summary>
UnderlineHot = 0x00000800,
/// <summary>
/// LVS_EX_UNDERLINECOLD
/// </summary>
UnderlineCold = 0x00001000,
/// <summary>
/// LVS_EX_MULTIWORKAREAS
/// </summary>
MultilWorkAreas = 0x00002000,
/// <summary>
/// LVS_EX_LABELTIP
/// </summary>
LabelTip = 0x00004000,
/// <summary>
/// LVS_EX_BORDERSELECT
/// </summary>
BorderSelect = 0x00008000,
/// <summary>
/// LVS_EX_DOUBLEBUFFER
/// </summary>
DoubleBuffer = 0x00010000,
/// <summary>
/// LVS_EX_HIDELABELS
/// </summary>
HideLabels = 0x00020000,
/// <summary>
/// LVS_EX_SINGLEROW
/// </summary>
SingleRow = 0x00040000,
/// <summary>
/// LVS_EX_SNAPTOGRID
/// </summary>
SnapToGrid = 0x00080000,
/// <summary>
/// LVS_EX_SIMPLESELECT
/// </summary>
SimpleSelect = 0x00100000
}
public enum ListViewMessages
{
First = 0x1000,
SetExtendedStyle = (First + 54),
GetExtendedStyle = (First + 55),
}
/// <summary>
/// Contains helper methods to change extended styles on ListView, including enabling double buffering.
/// Based on Giovanni Montrone's article on <see cref="http://www.codeproject.com/KB/list/listviewxp.aspx"/>
/// </summary>
public class ListViewHelper
{
private ListViewHelper()
{
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int SendMessage(IntPtr handle, int messg, int wparam, int lparam);
public static void SetExtendedStyle(Control control, ListViewExtendedStyles exStyle)
{
ListViewExtendedStyles styles;
styles = (ListViewExtendedStyles)SendMessage(control.Handle, (int)ListViewMessages.GetExtendedStyle, 0, 0);
styles |= exStyle;
SendMessage(control.Handle, (int)ListViewMessages.SetExtendedStyle, 0, (int)styles);
}
public static void EnableDoubleBuffer(Control control)
{
ListViewExtendedStyles styles;
// read current style
styles = (ListViewExtendedStyles)SendMessage(control.Handle, (int)ListViewMessages.GetExtendedStyle, 0, 0);
// enable double buffer and border select
styles |= ListViewExtendedStyles.DoubleBuffer | ListViewExtendedStyles.BorderSelect;
// write new style
SendMessage(control.Handle, (int)ListViewMessages.SetExtendedStyle, 0, (int)styles);
}
public static void DisableDoubleBuffer(Control control)
{
ListViewExtendedStyles styles;
// read current style
styles = (ListViewExtendedStyles)SendMessage(control.Handle, (int)ListViewMessages.GetExtendedStyle, 0, 0);
// disable double buffer and border select
styles -= styles & ListViewExtendedStyles.DoubleBuffer;
styles -= styles & ListViewExtendedStyles.BorderSelect;
// write new style
SendMessage(control.Handle, (int)ListViewMessages.SetExtendedStyle, 0, (int)styles);
}
}

Optimizing Bitmap Loading in .Net Compact Framework

I'm in need to load an bunch of bitmaps in my application. The problem is that the loading make the form very slow. My actual class is as follows:
public class ImagensDisponiveis
{
/// <summary>
/// List of ImagemSygic struct
/// </summary>
private List<ImagemSygic> _poolImagens;
/// <summary>
/// index of next avaiable image
/// </summary>
private int indiceProximoDisponivel;
/// <summary>
/// Path to image folder
/// </summary>
private string caminhoPasta;
/// <summary>
/// Number of found images that conforms to patterm
/// </summary>
private int MAXCOUNT;
public ImagensDisponiveis(string caminhoPastaRecursos)
{
indiceProximoDisponivel = 0;
caminhoPasta = caminhoPastaRecursos;
PreencherPool(out _poolImagens, caminhoPasta);
MAXCOUNT = _poolImagens.Count;
}
/// <summary>
/// Preenche a lista de imagens com uma estrutura que contém a imagem e o caminho dessa imagem para o Sygic
/// </summary>
/// <param name="_poolImagens">The _pool imagens.</param>
/// <param name="filepath">The filepath.</param>
private void PreencherPool(out List<ImagemSygic> _poolImagens, string filepath)
{
DateTime momentoInicio = DateTime.Now;
_poolImagens = new List<ImagemSygic>();
string[] imagens = Directory.GetFiles(filepath);
#if DEBUG
//int counter = 0;
//int numFiles = imagens.Length;
#endif
foreach (string caminhoImagem in imagens)
{
try
{
string filename = Path.GetFileName(caminhoImagem);
//original image to show on .net [POI]anything.bmp
//image that sygic tries to use on drive ?[POI]anything.bmp, where ? is an number between 1 to 6
bool valido = filename.StartsWith("[POI]", StringComparison.InvariantCulture);
//Log.writeToLog(caminhoImagem + " " + valido.ToString());
if (valido)
{
var streamImagem = File.Open(caminhoImagem, FileMode.Open, FileAccess.Read);
Bitmap temImagem = new Bitmap(streamImagem);
ImagemSygic tempImgSygic = new ImagemSygic();
tempImgSygic.CaminhoImagemSygic = caminhoImagem;
tempImgSygic.ImagemWindows = temImagem;
tempImgSygic.SygicImageID = -1;
_poolImagens.Add(tempImgSygic);
#if DEBUG
//counter++;
#endif
}
}
catch (ArgumentException aec)
{
Log.writeToLog("[EXCEPCAO ImagensDisp]: ArgumentException - " + aec.Message);
}
catch (UnauthorizedAccessException uae)
{
Log.writeToLog("[EXCEPCAO ImagensDisp]: UnauthorizedAccessException - " + uae.Message);
}
catch (Exception exc)
{
Log.writeToLog("[EXCEPCAO ImagensDisp]: Exception - " + exc.Message);
}
}
DateTime tempoFim = DateTime.Now;
TimeSpan duracao = tempoFim.Subtract(momentoInicio);
Log.writeToLog("[Criacao da pool] Demorou " + duracao.TotalSeconds.ToString());
}
/// <summary>
/// OObtains the next avaianle ImagemSygic if there is an avaiable
/// </summary>
/// <returns>ImagemSygic if possible, else null</returns>
public ImagemSygic ObterProximoDisponivel()
{
if (indiceProximoDisponivel > MAXCOUNT)
return null;
else
{
ImagemSygic imagemRetornar = _poolImagens[indiceProximoDisponivel];
indiceProximoDisponivel++;
return imagemRetornar;
}
}
public void ResetCounter()
{
indiceProximoDisponivel = 0;
}
}
/// <summary>
/// Class that contains the Bitmap preview and the original path to that image
/// </summary>
public class ImagemSygic
{
private volatile int _imageID;
/// <summary>
/// Gets or sets the imagem windows.
/// </summary>
/// <value>The imagem windows.</value>
public Bitmap ImagemWindows { get; set; }
/// <summary>
/// Gets or sets the caminho imagem sygic.
/// </summary>
/// <value>The caminho imagem sygic.</value>
public string CaminhoImagemSygic { get; set; }
/// <summary>
/// Gets or sets the sygic image ID.
/// </summary>
/// <value>The sygic image ID.</value>
public int SygicImageID
{
get
{
return this._imageID;
}
set
{
this._imageID = value;
}
}
}
/// <summary>
///
/// </summary>
public class POISygic
{
private volatile int _latitude;
private volatile int _longitude;
/// <summary>
/// Gets or sets the imagem.
/// </summary>
/// <value>The imagem.</value>
public ImagemSygic Imagem { get; set; }
/// <summary>
/// Gets or sets the latitude.
/// </summary>
/// <value>The latitude.</value>
public int Latitude { get { return this._latitude; } set { this._latitude = value; } }
/// <summary>
/// Gets or sets the longitude.
/// </summary>
/// <value>The longitude.</value>
public int Longitude { get { return this._longitude; } set { this._longitude = value; } }
/// <summary>
/// Gets or sets the descricao.
/// </summary>
/// <value>The descricao.</value>
public string Descricao { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is displayed now.
/// </summary>
/// <value>
/// <c>true</c> if this instance is displayed now; otherwise, <c>false</c>.
/// </value>
public bool isDisplayedNow { get; set; }
/// <summary>
/// Gets or sets the elem ID.
/// </summary>
/// <value>The elem ID.</value>
public int elemID { get; set; }
}
The objective of this class is to read an serie of bitmaps that have the [POI] prefix to allow .net to display an legend in an form control to the poi image appearing in an Sygic Drive window.
The question is how i can optimize this code to load the images faster. At the moment it loads 26 315k bitmaps images in 10s. But probably in the final solution we could have as many as +260 images, so that is the reason of the need of optimization.
The biggest potential improvement I see is that PreencherPool loads all images in a folder. Are you showing all images at once? If not, you could change that to lazy-load the images on demand, or at least load them in a background thread so the caller doesn't block while they all get loaded.
I'd also suggest that 300k seems a bit large for a "thumbnail" (which the code suggests they are). Are you sizing it to what you actually need for displ15?

Get aspect ratio of a monitor

I want to get aspect ratio of a monitor as two digits : width and height. For example 4 and 3, 5 and 4, 16 and 9.
I wrote some code for that task. Maybe it is any easier way to do that ? For example, some library function =\
/// <summary>
/// Aspect ratio.
/// </summary>
public struct AspectRatio
{
int _height;
/// <summary>
/// Height.
/// </summary>
public int Height
{
get
{
return _height;
}
}
int _width;
/// <summary>
/// Width.
/// </summary>
public int Width
{
get
{
return _width;
}
}
/// <summary>
/// Ctor.
/// </summary>
/// <param name="height">Height of aspect ratio.</param>
/// <param name="width">Width of aspect ratio.</param>
public AspectRatio(int height, int width)
{
_height = height;
_width = width;
}
}
public sealed class Aux
{
/// <summary>
/// Get aspect ratio.
/// </summary>
/// <returns>Aspect ratio.</returns>
public static AspectRatio GetAspectRatio()
{
int deskHeight = Screen.PrimaryScreen.Bounds.Height;
int deskWidth = Screen.PrimaryScreen.Bounds.Width;
int gcd = GCD(deskWidth, deskHeight);
return new AspectRatio(deskHeight / gcd, deskWidth / gcd);
}
/// <summary>
/// Greatest Common Denominator (GCD). Euclidean algorithm.
/// </summary>
/// <param name="a">Width.</param>
/// <param name="b">Height.</param>
/// <returns>GCD.</returns>
static int GCD(int a, int b)
{
return b == 0 ? a : GCD(b, a % b);
}
}
Use Screen class to get the height/width.
Divide to get the GCD
Calculate the ratio.
See following code:
private void button1_Click(object sender, EventArgs e)
{
int nGCD = GetGreatestCommonDivisor(Screen.PrimaryScreen.Bounds.Height, Screen.PrimaryScreen.Bounds.Width);
string str = string.Format("{0}:{1}", Screen.PrimaryScreen.Bounds.Height / nGCD, Screen.PrimaryScreen.Bounds.Width / nGCD);
MessageBox.Show(str);
}
static int GetGreatestCommonDivisor(int a, int b)
{
return b == 0 ? a : GetGreatestCommonDivisor(b, a % b);
}
I don't think there's a library function to do it, but that code looks good. Very similar to the answer in this related post of doing the same thing in Javascript: Javascript Aspect Ratio

Categories