Use statement lambdas in C#

[statement lambdas]

The example Use lambda expressions in C# showed how to use lambda expressions to concisely create an anonymous method that takes parameters and returns a value. The following code shows one of the lambda expressions that example used.

private void radF3_CheckedChanged(object sender, EventArgs e)
{
    DrawGraph((float x, float y) => (float)(x * x +
        (y - Math.Pow(x * x, 1.0 / 3.0)) *
        (y - Math.Pow(x * x, 1.0 / 3.0)) - 1)
    );
}

This expression works, but it’s all one statement so it’s length makes it fairly confusing.

Technically, this is called an “expression lambda” because the part of it on the right is an expression that returns some value. Instead of using expression lambdas, the code could use statement lambdas. Statement lambdas contain any number of statements inside braces.

Statement lambdas that return a value must use a return statement just as a method would. Like expression lambdas, statement lambdas can let Visual Studio use inference to figure out the lambda’s parameter types, or you can include the parameter types explicitly.

The following code shows the previous event handler rewritten with a statement lambda.

private void radF3_CheckedChanged(object sender, EventArgs e)
{
    DrawGraph((float x, float y) => 
        {
            float temp = (float)(y - Math.Pow(x * x, 1.0 / 3.0));
            return (x * x + (temp * temp) - 1);
        }
    );
}

This makes the calculation somewhat simpler in this example. In a more complicated example, statement lambdas can do a lot more than an expression lambda, which can execute only a single line of code.

Here’s a brief summary of lambda statement formats.

  • Expression lambda with one parameter:

    x => x * x
  • Expression lambda without parameter types that has multiple parameters:

    (x, y) => x * y
  • Expression lambda with parameter types:

    (float x, float y) => x * y
  • Statement lambda without parameter types that does not return a value:

    (x, y) =>
    {
        float result = x + y;
        MessageBox.Show("Result: " + result.ToString());
    }
  • Statement lambda without parameter types that returns a value:

    (x, y) =>
    {
        float temp = x + y;
        return temp * temp;
    }
  • Statement lambda with parameter types that returns a value:

    (float x, float y) =>
    {
        float temp = x + y;
        return temp * temp;
    }


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in algorithms, graphics, variables | Tagged , , , , , , , , , , , , , , , , | Leave a comment

Use lambda expressions in C#

[lambda expressions]

Lambda expressions are basically just a shorthand notation for making an anonymous method. There are a couple of formats, the simplest of which has the following syntax.

x => expression

Here expression is an expression involving the variable x. For example, the following code defines an anonymous function that takes a parameter x and returns x squared.

x => x * x

These are called lambda expressions because the thing to the right of the => operator is an expression that returns a value.

The following code shows how a program could pass this anonymous method into the method CalculateValue.

CalculateValue(x => x * x);

For this to work, the CalculateValue method must take as a parameter a method that takes a number as a parameter and that returns another number. Visual Studio infers the data types of the parameter x and the returned result. The following code shows how you might defined CalculateValue.

private void CalculateValue(Func<int, float> function)
{
    ...
}

In this case, CalculateValue expects as a parameter a method that takes an int as a parameter and that returns a float. The anonymous method shown earlier can meet those requirements.

If you want to include more than one parameter in lambda expressions, you must enclose the parameters in parentheses. For example, the following code shows the declaration of CalculateValue method that expects as a parameter a method that takes two int parameters and that returns a float.

private void CalculateValue(Func<int, int, float> act)
{
    ...
}

The following code shows how the program might use a lambda expression to call this method.

CalculateValue((x, y) => x * y);

In these examples, Visual Studio infers the data types of the lambda expression’s parameters. If you don’t want to use inference, for example if you want to make the code easier to read, you can include the parameters’ data types as in the following code.

CalculateValue((int x, int y) => x * y);

If you include the data types, then they must match those expected by the CalculateValue method. (As far as I know you can’t explicitly specify the return type, although you can make the expression on the right include a cast operator so you know what data type it returns.)

For a final example, consider the previous post Use anonymous methods in C#. That example uses the following code to pass anonymous methods to the DrawGraph method.

// Draw the appropriate graph.
private void radF1_CheckedChanged(object sender, EventArgs e)
{
    DrawGraph(delegate(float x, float y) {return x * x + x * y - y; });
}

private void radF2_CheckedChanged(object sender, EventArgs e)
{
    DrawGraph(delegate(float x, float y) { return (y - 1 / (x * x)); });
}

private void radF3_CheckedChanged(object sender, EventArgs e)
{
    DrawGraph(delegate(float x, float y)
        {
            double temp = y - Math.Pow(x * x, 1.0 / 3.0);
            return (float)(x * x + temp * temp - 1);
        });
}

private void radF4_CheckedChanged(object sender, EventArgs e)
{
    DrawGraph(delegate(float x, float y)
        { return (float)(y - 3 * Math.Cos(x) / x); });
}

This post’s example uses the following version of the code, which uses lambda expressions to define its anonymous methods.

// Draw the appropriate graph.
private void radF1_CheckedChanged(object sender, EventArgs e)
{
    DrawGraph((float x, float y) => x * x + x * y - y);
}

private void radF2_CheckedChanged(object sender, EventArgs e)
{
    DrawGraph((x, y) => (y - 1 / (x * x)));
}

private void radF3_CheckedChanged(object sender, EventArgs e)
{
    DrawGraph((float x, float y) => (float)(x * x +
        (y - Math.Pow(x * x, 1.0 / 3.0)) *
        (y - Math.Pow(x * x, 1.0 / 3.0)) - 1)
    );
}

private void radF4_CheckedChanged(object sender, EventArgs e)
{
    DrawGraph((float x, float y) => (float)(y - 3 * Math.Cos(x) / x));
}

This is somewhat shorter, although its unusual syntax can be more confusing. The lambda expression used by radF3_CheckedChanged is particularly complicated because it is so long. The previous version used an intermediate variable to simplify the calculation a bit.

You don’t need to use lambda expressions. You can always use the longer syntax to define anonymous methods. In fact, you don’t really need to use anonymous methods either. Both anonymous methods and lambda expressions are provided so you can make your code more concise if you prefer.

My next post will explain how to use statement lambdas, which will let the program simplify the complicated expression used by radF3_CheckedChanged.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in algorithms, graphics, variables | Tagged , , , , , , , , , , , , , , | 1 Comment

Use anonymous methods in C#

[example]

My previous post Use the predefined Action, Func, and EventHandler delegate types in C# explains how to use the predefined generic Func, Action, and EventHandler delegate types to graph four functions F(x, y). It uses the following code to define the functions and call them.

// x^2 + x*y - y = 0
private float F1(float x, float y)
{
    return (x * x + x * y - y);
}

// y - 1 / x^2 = 0
private float F2(float x, float y)
{
    return (y - 1 / (x * x));
}

// x^2 + (y - (x^2)^1/3))^2 - 1 = 0
private float F3(float x, float y)
{
    double temp = y - Math.Pow(x * x, 1.0 / 3.0);
    return (float)(x * x + temp * temp - 1);
}

// y - 3 * Cos(x) / x
private float F4(float x, float y)
{
    return (float)(y - 3 * Math.Cos(x) / x);
}

// Draw the appropriate graph.
private void radF1_CheckedChanged(object sender, EventArgs e)
{
    DrawGraph(F1);
}

private void radF2_CheckedChanged(object sender, EventArgs e)
{
    DrawGraph(F2);
}

private void radF3_CheckedChanged(object sender, EventArgs e)
{
    DrawGraph(F3);
}

private void radF4_CheckedChanged(object sender, EventArgs e)
{
    DrawGraph(F4);
}

The code first defines the four functions F1, F2, F3, and F4. The four CheckBox controls’ CheckedChanged event handlers call the DrawGraph method, passing that method the function to graph. The DrawGraph method (which isn’t really important to this example, so it’s not shown here) takes as a parameter the function to draw and draws it, at one point passing the function to another method.

The fact that their names are F1, F2, F3, and F4 is a hint that the functions themselves aren’t really meaningful in themselves. They are basically defined, passed into DrawGraph, and then forgotten.

Because the functions aren’t used in other parts of the program, you can replace these functions with anonymous methods. An anonymous method is basically a delegate that refers to some code that doesn’t have a name. You can store the delegate in a delegate variable or pass it to a method as a parameter.

The syntax for an anonymous method is:

delegate(parameters) { ...code... });

Here parameters defines any parameters the delegate should take. If the code inside the braces returns a value, it should use a return statement just like any other method.

The following code shows how this post’s example uses anonymous methods to handle its CheckedChanged events.

// Draw the appropriate graph.
private void radF1_CheckedChanged(object sender, EventArgs e)
{
    DrawGraph(delegate(float x, float y) {return x * x + x * y - y; });
}

private void radF2_CheckedChanged(object sender, EventArgs e)
{
    DrawGraph(delegate(float x, float y) { return (y - 1 / (x * x)); });
}

private void radF3_CheckedChanged(object sender, EventArgs e)
{
    DrawGraph(delegate(float x, float y)
        {
            double temp = y - Math.Pow(x * x, 1.0 / 3.0);
            return (float)(x * x + temp * temp - 1);
        });
}

private void radF4_CheckedChanged(object sender, EventArgs e)
{
    DrawGraph(delegate(float x, float y)
        { return (float)(y - 3 * Math.Cos(x) / x); });
}

In this version, the event handlers pass the four functions to the DrawGraph method as anonymous methods so the program doesn’t need to define the functions separately. This makes the code a bit more concise and easier to read, although the third anonymous method is a bit long. If that function were much longer, it might be better to put its code in a named method to make the code more readable.

Usually you shouldn’t use an anonymous method if the method will be used in multiple places, if its code is too long, or if it would otherwise be less confusing to use a named method. Anonymous methods don’t give you any real performance advantage (unlike the inline macros used by some programming languages), so you should only use them if they make the code easier to understand.

In the next post, I’ll show how you can use lambda statements to make defining anonymous methods easier.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in algorithms, graphics, variables | Tagged , , , , , , , , , , , , | 1 Comment

Use the predefined Action, Func, and EventHandler delegate types in C#

[delegate types]

This and the next couple of posts discuss delegates and the somewhat related topics of anonymous methods and lambda expressions.

Briefly, delegate types are programmer-defined data types that represent methods. For example, the following code declares a delegate type.

// Define a delegate type named FofXY.
private delegate float FofXY(float x, float y);

The FofXY type represents methods that take two float values as parameters and that return a float value.

Later the program can use delegate types to declare variables, parameters, or return values. The following code uses the type to define the parameter to the DrawGraph method.

// Draw the indicated function.
private void DrawGraph(FofXY func)
{
    ...
}

The DrawGraph method can invoke whatever method is passed into it for the func parameter just as it would use func if it were a normal method. For example, it could use the following code to evaluate the function for the X and Y values 1.2 and 6.5.

float result = func(1.2f, 6.5f);

This can be a bit confusing because a delegate represents a kind of method instead of some more data-oriented piece of information such as an int, struct, or object.

Defining delegate types isn’t hard, but it does add one extra step when you want to declare a variable or parameter to have a method type. To make that kind of declaration easier, the .NET Framework defines two generic method types: Func and Action.

One of the simpler Func types is defined as:

public delegate TResult Func<in T1, out TResult>(T1 arg1);

In other words, it represents a method that takes a parameter of type T1 and returns a result of type TResult. For example, suppose the GraphFunction method takes as a parameter a function y = F(x) and graphs it. The following code shows how you could declare this method.

private void GraphFunction(Func<float, float> func)
{
    ...
}

This is equivalent to the following version that declares its own delegate type.

private delegate float MyFunction(float x);

private void GraphFunction(MyFunction func)
{
    ...
}

Other versions of the Func type take between 0 and 16 parameters of different types, plus a result type. You can use the version that takes two parameters (plus the return type) to rewrite the declaration of the DrawGraph method shown earlier like this:

// Draw the indicated function.
private void DrawGraph(Func<float, float, float> func)
{
    ...
}

This version of Func takes two float parameters and returns a float.

In addition to the Func delegate, the .NET Framework also defines a generic Action delegate to represent a method that takes between 0 and 16 parameters and that doesn’t return any value. (Or returns void if you prefer.)

For example, suppose the LogMessage method takes two parameters, a string and a method that takes a string as a parameter. The LogMessage method calls its delegate parameter to make it do something to the string. The following code shows how you could define the LogMessage method.

private void LogMessage(string message, Action<string> action)
{
    action(message);
}

The .NET Framework defines one other useful delegate type: EventHandler. This type takes two parameters, a non-specific object and an EventArgs object. It is equivalent to Action<object, EventArgs>.

You can use the EventHandler type to make it easier to define your own events. For example, consider the following BankAccount class.

public class BankAccount
{
    public delegate void OverdrawnEventHandler(
        object sender, OverdrawnArgs e);
    public event OverdrawnEventHandler Overdrawn;

    public void Debit()
    {
        OverdrawnArgs args = new OverdrawnArgs();
        if (Overdrawn != null) Overdrawn(this, args);
    }
}

This code declares the OverdrawnEventHandler delegate to be a method that returns void and that takes as parameters a non-specific object and an OverdrawnArgs object. It then uses the delegate to declare the event. Finally, the Debit method raises the event.

Compare this to the following version that uses the predefined generic EventHandler delegate.

public class BankAccount
{
    public event EventHandler<OverdrawnArgs> Overdrawn;

    public void Debit()
    {
        OverdrawnArgs args = new OverdrawnArgs();
        if (Overdrawn != null) Overdrawn(this, args);
    }
}

Here the class uses the predefined EventHandler delegate instead of defining its own. The code is simpler and easier to read.

In my next few posts, I’ll describe anonymous methods and lambda statements that you can use to initialize delegate variables or to pass into methods as if they were delegates.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in algorithms, graphics, variables | Tagged , , , , , , , , , , , , | 1 Comment

A quick note on error messages


[error messages]

I went to a local museum the other day and when the attendant scanned by membership card his computer said:

Object not set to a reference of an object.

Because we’re programmers, you and I know what that means (more or less), but the poor attendant hasn’t got a clue. The message may as well have said:

There’s an error and I’m not going to tell you what went wrong or what to do about it! Bwah, hah, hah!

Of course the attendant had seen this message before, probably hundreds of times, so he knew what to do and scanned my membership card again at a different speed holding it slightly differently. It worked the second time.

The point of the story is that you should never display an error message like this one to a user. They don’t know what it means and don’t know how to try to fix the problem. You may as well just insult the user and get it over with.

Whenever I see a message like this in an application I’m using, I think, “What a piece of garbage. A beginning programmer could have anticipated this error and displayed a better message than this.” Do you really want the user to think of your program as a piece of garbage (or worse) every time they use it?

In my trip, it was obvious that this error occurs frequently so displaying such a bad message is even less forgivable.

The moral is, you should always catch errors (with a try-catch block in C#) and display something meaningful to the user. Even if you can’t really tell specifically what went wrong, give the user a general idea of what went wrong. If possible, include a suggestion of something to try that might fix it. In this case a much better message would be:

Error scanning membership card. Please try again or enter the membership number manually.

See? Even not knowing exactly what was going wrong in the software, I can come up with a meaningful and constructive error message.


Follow me on Twitter   RSS feed   Donate




Posted in MessageBox, miscellany, user interface | Tagged , , , , , , , , , , , , , | 1 Comment

Make a button display the picture beneath slightly grayed it in C#

[button]

The example Make a button display the picture beneath it in C# shows how to make a button display the picture that lies below it. Unfortunately, the button only adds a border as decoration and the border doesn’t have a very three-dimensional appearance, so it can be hard to see. It may also be difficult to see the button’s text on top of the picture.

This example modifies the SetButtonBackground method to allow you to add some gray to the button’s image. That makes it much easier to see.


The following code shows the modified version of the SetButtonBackground method. The new code is highlighted in blue.

// Make the Button display the part of the
// PictureBox's picture that is under it.
private void SetButtonBackground(PictureBox pic, Button btn, byte alpha)
{
    // Get the offset between the PictureBox's
    // and button's upper left corners.
    Point pic_pt = new Point(0, 0);
    pic_pt = pic.PointToScreen(pic_pt);
    Point btn_pt = new Point(0, 0);
    btn_pt = btn.PointToScreen(btn_pt);
    int x_offset = btn_pt.X - pic_pt.X;
    int y_offset = btn_pt.Y - pic_pt.Y;

    // Get the button's size.
    int wid = btn.ClientSize.Width;
    int hgt = btn.ClientSize.Height;

    // Make a bitmap to hold the button image.
    Bitmap bm = new Bitmap(wid, hgt);
    using (Graphics gr = Graphics.FromImage(bm))
    {
        // Destination rectangle.
        Rectangle dest_rect = new Rectangle(0, 0, wid, hgt);

        // Source rectangle.
        Rectangle src_rect = new Rectangle(x_offset, y_offset, wid, hgt);

        // Copy the image under the button into the bitmap.
        gr.DrawImage(pic.Image, dest_rect, src_rect, GraphicsUnit.Pixel);

        // Draw some gray over the image.
        Color color = Color.FromArgb(alpha, Color.White);
        using (Brush brush = new SolidBrush(color))
        {
            gr.FillRectangle(brush, dest_rect);
        }
    }

    // Make the button display the image.
    btn.Image = bm;
}

The method works mostly as it did before. After it copies the part of the image below the button into a new image, the method draw a translucent white rectangle over the image. It uses its alpha parameter to determine how opaque the rectangle is. Use a large alpha value (closer to 255) to make the button more gray. Use a small values (close to 0) to make the button less gray.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in controls, graphics, image processing | Tagged , , , , , , , , , , , , | Leave a comment

Make a button display the picture beneath it in C#

[button]

This example makes a button display copies of the picture on which it sits, making it appear that the button is part of the underlying image.


The key to this example is the following SetButtonBackground method.

// Make the Button display the part of the
// PictureBox's picture that is under it.
private void SetButtonBackground(PictureBox pic, Button btn)
{
    // Get the offset between the PictureBox's
    // and button's upper left corners.
    Point pic_pt = new Point(0, 0);
    pic_pt = pic.PointToScreen(pic_pt);
    Point btn_pt = new Point(0, 0);
    btn_pt = btn.PointToScreen(btn_pt);
    int x_offset = btn_pt.X - pic_pt.X;
    int y_offset = btn_pt.Y - pic_pt.Y;

    // Get the button's size.
    int wid = btn.ClientSize.Width;
    int hgt = btn.ClientSize.Height;

    // Make a bitmap to hold the button image.
    Bitmap bm = new Bitmap(wid, hgt);
    using (Graphics gr = Graphics.FromImage(bm))
    {
        // Destination rectangle.
        Rectangle dest_rect = new Rectangle(0, 0, wid, hgt);

        // Source rectangle.
        Rectangle src_rect = new Rectangle(x_offset, y_offset, wid, hgt);

        // Copy the image under the button into the bitmap.
        gr.DrawImage(pic.Image, dest_rect, src_rect, GraphicsUnit.Pixel);
    }

    // Make the button display the image.
    btn.Image = bm;
}

The method starts by using the PointToScreen method to determine where the upper left corner of the PictureBox and Button are in screen coordinates. This gives the relative offset between the two controls in pixels.

The code then gets the button’s size, makes a Bitmap to fit it, and creates an associated Graphics object.

Next, the method makes Rectangle structures to define the source and destination areas in the PictureBox control’s image that should be copied to the button. It then uses the Graphics object’s DrawImage method to copy that part of the PictureBox image into the new Bitmap. It finishes by making the Button display the new Bitmap.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in controls, graphics, image processing | Tagged , , , , , , , , , , , , | 1 Comment

Validate optional parameters in C#

[optional parameters]

The example Use named and optional parameters in C# explains how to use named and optional parameters to let the calling code omit any combination of parameters. In many applications, you may not want to allow the user to omit every possible combination, just most of them. In that case, you can add some code to the method to verify that the combination provided by the calling code is allowed.

In this example, the Parson class requires a name and at least one contact method. The following code shows the constructor, which ensures that there is at least one contact method.

public Person(string name, string address = "", string email = "",
    string sms_phone = "", string voice_phone = "", string fax = "")
{
    // Make sure at least one contact method is present.
    if (address == "" && email == "" && sms_phone == "" &&
        voice_phone == "" && fax == "")
            throw new ArgumentException(
                "You must provide at least one contact method.");

    Name = name;
    Address = address;
    Email = email;
    SmsPhone = sms_phone;
    VoicePhone = voice_phone;
    Fax = fax;
}

When the program creates a Person object, the constructor checks the contact method parameters and throws an exception if they are all blank. If any contact method is non-blank, then the constructor uses the parameters to initialize the object.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in methods, syntax, variables | Tagged , , , , , , , , , , , , , | 1 Comment

Use named and optional parameters in C#

[optional parameters]

Optional parameters is one of the few additions in recent versions of Visual Studio that are really useful. I usually try to post examples in an older version of C# because it’s easier for someone to move an older example to a more recent version than it is to move a recent example to an older version. Most of the C# language has remained unchanged for a long time, so this isn’t a problem. However, C# includes are a few useful features that were added relatively recently.

Named and optional parameters were added with C# 2010.

Named arguments let you use the names of parameters when you invoke a method. For example, suppose the Person class has a constructor that takes the parameters: name, address, email, sms_phone, voice_phone, and fax. Then your code could invoke the constructor like this:

Person person = new Person(name: "Rod Stephens",
    email: "RodStephens@CSharpHelper.com",
    address: "", sms_phone: "", voice_phone: "", fax: "");

This makes your code a bit more self-documenting, particularly if the parameter list is long. It also allows you to specify arguments in any order you wish.

While named arguments provide some benefit, they’re really not all that exciting until you combine them with optional parameters. To make a parameter optional, follow it with a default value in the method’s declaration. For example, the following code shows Person class’s constructor with the address, email, sms_phone, voice_phone, and fax parameters optional.

public Person(string name, string address = "", string email = "",
    string sms_phone = "", string voice_phone = "", string fax = "")
{
    Name = name;
    Address = address;
    Email = email;
    SmsPhone = sms_phone;
    VoicePhone = voice_phone;
    Fax = fax;
}

Now the program can use the following code to create a new Person object while specifying only the name argument (which is required because it doesn’t have a default value in the constructor’s declaration) and the email argument.

Person person = new Person(name: "Rod Stephens",
    email: "RodStephens@CSharpHelper.com");

This is not only handy, but it also gives you a new capability that you didn’t have before. Suppose you want the constructor to require name but not the other parameters. Without optional parameters, you could make several overloaded versions of the constructor, one that takes (name), one that takes (name, address), one that takes (name, address, email), and so forth.

That would let you create Person objects while omitting some of the arguments, but it would not let you omit them in any combination. For example, you could not specify name and email without address. Even if you were willing to make overloaded constructors for all of the 32 possible combinations (if I’ve counted correctly), the compiler couldn’t tell all of the versions apart because all of the arguments are strings.

Named and optional parameters let you provide and omit arguments in any combination you want with only a single constructor.

Optional parameters are also useful for setting default values easily. For example, without optional parameters you could provide a version of the constructor that takes values for all parameters and then use a second version similar to the following code to pass it default values for arguments that are omitted.

public Person(string name)
    : this(name, "????", "????", "????", "????", "????")
{
}

This works, but again only lets you handle certain combinations of omitted arguments and requires many different versions of the constructor.

Another approach would be to let the calling code pass null or some other value to “omit” arguments and then make the code check each one to see if it is null as in the following code.

public Person(string name, string address, string email,
    string sms_phone, string voice_phone, string fax)
{
    Name = name;

    if (address == null) Address = "????";
    else Address = address;

    if (email == null) Email = "????";
    else Email = email;

    if (sms_phone == null) SmsPhone = "????";
    else SmsPhone = sms_phone;

    if (voice_phone == null) VoicePhone = "????";
    else VoicePhone = voice_phone;

    if (fax == null) Fax = "????";
    else Fax = fax;
}

This is a lot more cumbersome and inelegant than using named and optional parameters.

To summarize, named and optional parameters are particularly useful when:

  • A method has lots of parameters and you want to use names to help document the calling code
  • You want to provide default values for parameters
  • You want to let the calling code omit arguments in any combination


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in methods, syntax, variables | Tagged , , , , , , , , , , , , , | 1 Comment

Display system metric values with descriptions in C#

[system metrics]

The example Get system metrics in C# shows how to get system metrics, but the the metrics’ terse names make the results hard to understand. This example displays descriptions of the metrics in addition to their values.

Some of the descriptions are too long to fit nicely in a ListView column so the program sets the ListView items’ ToolTipText values to also show the descriptions. Even if you set those values, however, the ListView doesn’t display the items’ tooltips unless you set its ShowItemToolTips property to true. The program uses the following code to set that property and to initialize the ListView control’s values.

// Display some useful metrics.
private void Form1_Load(object sender, EventArgs e)
{
    lvwMetrics.ShowItemToolTips = true;

    AddValue(SystemMetric.SM_CXSCREEN, "Primary screen width.");
    AddValue(SystemMetric.SM_CYSCREEN, "Primary screen height.");
    AddValue(SystemMetric.SM_CXVSCROLL, "Width of vertical scroll bar.");
    AddValue(SystemMetric.SM_CYHSCROLL, "Height of horizontal scroll bar.");
    AddValue(SystemMetric.SM_CYCAPTION, "Height of caption area.");
    ...
    AddValue(SystemMetric.SM_REMOTECONTROL,
        "Nonzero if the session is remotely controlled; zero otherwise.");
}

The following code shows the new AddValue method used by this example.

private void AddValue(SystemMetric metric, string descr)
{
    ListViewItem item = lvwMetrics.Items.Add(metric.ToString());
    item.SubItems.Add(GetSystemMetrics(metric).ToString());
    item.SubItems.Add(descr);
    item.ToolTipText = descr;
}

This code creates a ListView item, setting its text equal to the metric’s name. It adds the metric’s value and description as sub-items. It also sets the item’s ToolTipText property equal to the description.

Download the example and look at the code to see all 89 of the metrics and their descriptions.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in API, system | Tagged , , , , , , , , , , , , , , | Leave a comment