The [Flags]
attribute should be used whenever the enumerable represents a collection of possible values, rather than a single value. Such collections are often used with bitwise operators, for example:
var allowedColors = MyColor.Red | MyColor.Green | MyColor.Blue;
Note that the [Flags]
attribute doesn't enable this by itself - all it does is allow a nice representation by the .ToString()
method:
enum Suits { Spades = 1, Clubs = 2, Diamonds = 4, Hearts = 8 }
[Flags] enum SuitsFlags { Spades = 1, Clubs = 2, Diamonds = 4, Hearts = 8 }
...
var str1 = (Suits.Spades | Suits.Diamonds).ToString();
// "5"
var str2 = (SuitsFlags.Spades | SuitsFlags.Diamonds).ToString();
// "Spades, Diamonds"
It is also important to note that [Flags]
does not automatically make the enum values powers of two. If you omit the numeric values, the enum will not work as one might expect in bitwise operations, because by default the values start with 0 and increment.
Incorrect declaration:
[Flags]
public enum MyColors
{
Yellow, // 0
Green, // 1
Red, // 2
Blue // 3
}
The values, if declared this way, will be Yellow = 0, Green = 1, Red = 2, Blue = 3. This will render it useless as flags.
Here's an example of a correct declaration:
[Flags]
public enum MyColors
{
Yellow = 1,
Green = 2,
Red = 4,
Blue = 8
}
To retrieve the distinct values in your property, one can do this:
if (myProperties.AllowedColors.HasFlag(MyColor.Yellow))
{
// Yellow is allowed...
}
or prior to .NET 4:
if((myProperties.AllowedColors & MyColor.Yellow) == MyColor.Yellow)
{
// Yellow is allowed...
}
if((myProperties.AllowedColors & MyColor.Green) == MyColor.Green)
{
// Green is allowed...
}
Under the covers
This works because you used powers of two in your enumeration. Under the covers, your enumeration values look like this in binary ones and zeros:
Yellow: 00000001
Green: 00000010
Red: 00000100
Blue: 00001000
Similarly, after you've set your property AllowedColors to Red, Green and Blue using the binary bitwise OR |
operator, AllowedColors looks like this:
myProperties.AllowedColors: 00001110
So when you retrieve the value you are actually performing bitwise AND &
on the values:
myProperties.AllowedColors: 00001110
MyColor.Green: 00000010
-----------------------
00000010 // Hey, this is the same as MyColor.Green!
The None = 0 value
And regarding the use of 0
in your enumeration, quoting from MSDN:
[Flags]
public enum MyColors
{
None = 0,
....
}
Use None as the name of the flag enumerated constant whose value is zero. You cannot use the None enumerated constant in a bitwise AND operation to test for a flag because the result is always zero. However, you can perform a logical, not a bitwise, comparison between the numeric value and the None enumerated constant to determine whether any bits in the numeric value are set.
You can find more info about the flags attribute and its usage at msdn and designing flags at msdn
You can use the chart controls in two ways:
Generating the Image from a Controller
By generating the chart and returning it as an image from an action (as Chatuman is referring to I think):
Chart chart = new Chart();
chart.BackColor = Color.Transparent;
chart.Width = Unit.Pixel(250);
chart.Height = Unit.Pixel(100);
Series series1 = new Series("Series1");
series1.ChartArea = "ca1";
series1.ChartType = SeriesChartType.Pie;
series1.Font = new Font("Verdana", 8.25f, FontStyle.Regular);
series1.Points.Add(new DataPoint {
AxisLabel = "Value1", YValues = new double[] { value1 } });
series1.Points.Add(new DataPoint {
AxisLabel = "Value2", YValues = new double[] { value2 } });
chart.Series.Add(series1);
ChartArea ca1 = new ChartArea("ca1");
ca1.BackColor = Color.Transparent;
chart.ChartAreas.Add(ca1);
using (var ms = new MemoryStream())
{
chart.SaveImage(ms, ChartImageFormat.Png);
ms.Seek(0, SeekOrigin.Begin);
return File(ms.ToArray(), "image/png", "mychart.png");
}
WebForms Style
This way you just include the chart in your .aspx views (just like with traditional web forms). For this you'll have to hook up the relevant bits in your web.config
<controls>
...
<add tagPrefix="asp"
namespace="System.Web.UI.DataVisualization.Charting"
assembly="System.Web.DataVisualization, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</controls>
<httpHandlers>
...
<add path="ChartImg.axd"
verb="GET,HEAD"
validate="false"
type="System.Web.UI.DataVisualization.Charting.ChartHttpHandler, System.Web.DataVisualization, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</httpHandlers>
<handlers>
...
<add name="ChartImageHandler"
preCondition="integratedMode"
verb="GET,HEAD"
path="ChartImg.axd"
type="System.Web.UI.DataVisualization.Charting.ChartHttpHandler, System.Web.DataVisualization, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</handlers>
You can't run code inside the DataPoint elements when building the chart, so to hook up your data you'll need a method in the View class. This works ok for me. Working this way makes the control render a URL to an image generated by the chart control http handler. In your deployment you'll need to provide a writable folder for it to cache the images.
* VS 2010 / .NET 4 Support *
To get this working in .NET 4 you need to change the chart references to version 4.0.0.0 with the appropriate public key token.
Also it seems that the chart control now generates urls to the current request path rather than the request route. For me this meant that all the chart requests resulted in 404 errors because /{Controller}/ChartImg.axd
and equivalents were blocked by routes. To fix this I added extra IgnoreRoute calls that cover my usages - a more general solution would be better:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("ChartImg.axd/{*pathInfo}");
routes.IgnoreRoute("{controller}/ChartImg.axd/{*pathInfo}");
routes.IgnoreRoute("{controller}/{action}/ChartImg.axd/{*pathInfo}");
...
Best Answer
The ASPX files in both ASP.NET and ASP.NET MVC are not compiled from the Visual Studio IDE. This is often the cause for "false positives" as you have pointed out.
I often add the aspnet_compiler as a post build action to find those errors. You will add some time to your build process, but in exchange for the wait you should be able to spot these errors more easily.