Category Archives: Code

A WPF Numeric Entry Control with Pop-up Calculator

Part 1 – WPF Numeric Entry Control

Part 2 – This article

Download Source Code

When WPF first shipped, there was a noticeable lack of certain controls we’ve become used to in Win32 and WinForms: Calendar, DateTimePicker, and NumericUpDown. WPF 4 adds Calendar and DatePicker, but not anything for numeric entry.

I described how to create a numeric entry control in a previous article. In this article, I will follow that up by adding a popup calculator to allow you to quickly manipulate the number.

If you find this article useful, you will love my book, C# 4.0 How-To, which is filled with tips such as this.

Adding a Popup Calculator

Now that we have a basic numeric entry control, let’s extend it by adding the power of a keyboard-driven calculator popup window.

If you’ve used Quicken or the now-sadly-defunct Microsoft Money, you’ve seen a feature that pops up a calculator window whenever you hit +, –, *, or / in a number field.

Here are some further requirements for such a control:

  • It should be activated when the user types +, –, *, or /
  • It should be dismissed if the user hits Escape, Enter, or clicks anywhere outside the calculator (which is considered equivalent to Enter, not escape)
  • Both mouse and keyboard input should be handled
  • This version only handles integers
  • It should handle Backspace key to erase previously-input character
  • It should be visually compact
  • It should allow the user to string computations together. A + B – C / D * E

Extend the Numeric Entry Control

We first need to come up with a way to trigger the calculator in our numeric entry control. This is going to simply be if the user hits any math-operation character, such as +, –, *, or /.

First, we’ll need to define the allowed operations and a way to associate keyboard keys with math operations:
 

public enum MathOperation
{
    None = 0,
    Add,
    Subtract,
    Multiply,
    Divide
};

Now, let’s subclass NumericEntryControl with a new class that adds some additional keyboard handling.

class NumericEntryWithCalcControl : NumericEntryControl
{
    static Dictionary<Key, MathOperation> _keyToOp =
        new Dictionary<Key, MathOperation>();
 
    static NumericEntryWithCalcControl()
    {
        //associate keyboard keys with a math operation
        _keyToOp[Key.Add] = MathOperation.Add;
        _keyToOp[Key.Subtract] = MathOperation.Subtract;
        _keyToOp[Key.Multiply] = MathOperation.Multiply;
        _keyToOp[Key.Divide] = MathOperation.Divide;
 
#if DEBUG
        //easier keys on a laptop
        _keyToOp[Key.A] = MathOperation.Add;
        _keyToOp[Key.S] = MathOperation.Subtract;
        _keyToOp[Key.M] = MathOperation.Multiply;
        _keyToOp[Key.D] = MathOperation.Divide;
#endif
    }
}

With this bookkeeping down, we can intercept the keystrokes and show our calculator window (which we’ll define later) in the right spot. We also should handle when the window closes.

private CalcWindow _calc = null;
 
protected override void OnKeyDown(KeyEventArgs e)
{
    MathOperation op = MathOperation.None;
    if (_keyToOp.TryGetValue(e.Key, out op))
    {
        e.Handled = true;
        HandleOperation(op);
    }
    else
    {
        e.Handled = false;
        base.OnKeyDown(e);
    }
}
 
private void HandleOperation(MathOperation mathOperation)
{
    //show the calc dialog and initialize with Value and Op
    if (mathOperation != MathOperation.None)
    {
        _calc = new CalcWindow(Value, mathOperation);
        _calc.Closed += new EventHandler(calc_Closed);
        Point point = this.PointToScreen(new Point(0, 0));
 
        //adjust location to correct for DPI settings
        PresentationSource source = PresentationSource.FromVisual(this);
 
        double dpiX = 96.0 * source.CompositionTarget.TransformToDevice.M11;
        double dpiY = 96.0 * source.CompositionTarget.TransformToDevice.M22;
        
        _calc.Left = point.X * 96.0 / dpiX;
        _calc.Top = point.Y * 96.0 / dpiY;
 
        _calc.Show();
    }
}
 
private void calc_Closed(object sender, EventArgs e)
{
    if (_calc != null)
    {
        this.Value = _calc.CurrentValue;
        _calc.Closed -= new EventHandler(calc_Closed);
        _calc = null;
    }
}

Notice in ProcessOperation that the location of the calculator window is set to the upper left corner of the NumericEntryControl and it takes into account the current DPI. This is important if you’re using anything other than the standard 96 DPI.

Create the Calculator

calc_demo2

The actual calculator is a WPF window with no border (or a thin one), a textbox, and buttons representing a standard calculator layout.

The screenshot to the right shows the design layout of this window. The C button clears the input and sets the current value to 0. The left arrow erases the last character you input.

Since this window is designed to popup over other controls, I wanted to keep it as compact as possible.

The XAML code looks like this:

<Window x:Class="NumericEntryDemo.CalcWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:my="clr-namespace:NumericEntryDemo"
        Title="CalcWindow" WindowStyle="None"
        SizeToContent="WidthAndHeight"
        WindowStartupLocation="Manual"
        ResizeMode="NoResize"
        BorderThickness="1"
        >
    <DockPanel>
        <TextBox Name="_textbox"
                 DockPanel.Dock="Top"
                 Margin="2"
                 IsReadOnly="True"
                 Text="{Binding RelativeSource={RelativeSource FindAncestor,
                    AncestorType=my:CalcWindow, AncestorLevel=1}, Path=CurrentValue}"
                 TextAlignment="Right" />
        <UniformGrid Columns="4" Rows="5" Width="100" Height="100" Margin="2">
            <Button Name="_button7" Content="7" Click="digitButton_Click"/>
            <Button Name="_button8" Content="8" Click="digitButton_Click"/>
            <Button Name="_button9" Content="9" Click="digitButton_Click"/>
            <Button Name="_buttonDivide" Content="÷"  Click="opButton_Click"/>
            <Button Name="_button4" Content="4" Click="digitButton_Click"/>
            <Button Name="_button5" Content="5" Click="digitButton_Click"/>
            <Button Name="_button6" Content="6" Click="digitButton_Click"/>
            <Button Name="_buttonMultiply" Content="×"  Click="opButton_Click"/>
            <Button Name="_button1" Content="1" Click="digitButton_Click"/>
            <Button Name="_button2" Content="2" Click="digitButton_Click"/>
            <Button Name="_button3" Content="3" Click="digitButton_Click"/>
            <Button Name="_buttonSubtract" Content="-" Click="opButton_Click"/>
            <Button Name="_button0" Content="0" Click="digitButton_Click"/>
            <!-- empty space -->
            <Rectangle/>
            <Rectangle/>
            <Button Name="_buttonAdd" Content="+" Click="opButton_Click"/>
            <Button Name="_buttonClear" Content="C" Click="clearButton_click"/>
            <Button Name="_buttonErase" Content="?" Click="backButton_Click"/>
            <Button Name="_buttonEquals" Content="=" Click="equalsButton_Click"/>
        </UniformGrid>
    </DockPanel>
    <Window.Background>
        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
            <GradientStop Color="White" Offset="0" />
            <GradientStop Color="#FFDBDBDB" Offset="1" />
        </LinearGradientBrush>
    </Window.Background>
</Window>

All of the click handlers and binding targets will be filled out in the code-behind.

To start with, we need a few housekeeping variables:

  • The original value upon starting the calculator, just in case after all the calculations the user just hits Escape
  • A way to track whether we’ve canceled the whole thing
  • The current operation
  • The current input, in both string and number form
  • The previously calculated value, allowing you to string together calculations like “123 + 456 / 2 * 29”
  • Map buttons and keystrokes to numbers, math operations, and the other commands.

With that, we can see the beginning of our class:

public partial class CalcWindow : Window
{
    private int _initialValue = 0;
    private bool _canceled = false;
    private MathOperation _currentOp = MathOperation.None;
 
    //value of current input
    public static readonly DependencyProperty CurrentValueProperty =
        DependencyProperty.Register("CurrentValue", typeof(int),
        typeof(CalcWindow), new PropertyMetadata(0));
 
    //current input in string form
    public static readonly DependencyProperty CurrentInputProperty =
        DependencyProperty.Register("CurrentInput", typeof(string),
        typeof(CalcWindow), new PropertyMetadata(""));
 
    //previously calculated value
    public static readonly DependencyProperty PreviousValueProperty =
        DependencyProperty.Register("PreviousValue", typeof(int),
        typeof(CalcWindow), new PropertyMetadata(0));
 
    private static readonly Dictionary<Key, int> _keyDigits =
        new Dictionary<Key, int>();
    private static readonly Dictionary<Key, MathOperation> _keyOps =
        new Dictionary<Key, MathOperation>();
 
    private readonly Dictionary<Button, int> _buttonDigits =
        new Dictionary<Button, int>();
    private readonly Dictionary<Button, MathOperation> _buttonOps =
        new Dictionary<Button, MathOperation>();
 
    static CalcWindow()
    {
        _keyDigits[Key.D0] = 0;
        _keyDigits[Key.D1] = 1;
        _keyDigits[Key.D2] = 2;
        _keyDigits[Key.D3] = 3;
        _keyDigits[Key.D4] = 4;
        _keyDigits[Key.D5] = 5;
        _keyDigits[Key.D6] = 6;
        _keyDigits[Key.D7] = 7;
        _keyDigits[Key.D8] = 8;
        _keyDigits[Key.D9] = 9;
 
        _keyDigits[Key.NumPad0] = 0;
        _keyDigits[Key.NumPad1] = 1;
        _keyDigits[Key.NumPad2] = 2;
        _keyDigits[Key.NumPad3] = 3;
        _keyDigits[Key.NumPad4] = 4;
        _keyDigits[Key.NumPad5] = 5;
        _keyDigits[Key.NumPad6] = 6;
        _keyDigits[Key.NumPad7] = 7;
        _keyDigits[Key.NumPad8] = 8;
        _keyDigits[Key.NumPad9] = 9;
 
        _keyOps[Key.Add] = MathOperation.Add;
        _keyOps[Key.Subtract] = MathOperation.Subtract;
        _keyOps[Key.Multiply] = MathOperation.Multiply;
        _keyOps[Key.Divide] = MathOperation.Divide;
 
#if DEBUG
        _keyOps[Key.A] = MathOperation.Add;
        _keyOps[Key.S] = MathOperation.Subtract;
        _keyOps[Key.M] = MathOperation.Multiply;
        _keyOps[Key.D] = MathOperation.Divide;
#endif
 
    }
 
    public int CurrentValue
    {
        get
        {
            return (Int32)GetValue(CurrentValueProperty);
        }
        set
        {
            SetValue(CurrentValueProperty, value);
        }
    }
 
    public string CurrentInput
    {
        get
        {
            return GetValue(CurrentInputProperty) as string;
        }
        set
        {
            SetValue(CurrentInputProperty, value);
        }
    }
 
    public int PreviousValue
    {
        get
        {
            return (Int32)GetValue(PreviousValueProperty);
        }
        set
        {
            SetValue(PreviousValueProperty, value);
        }
    }
 
    public CalcWindow(int initialValue, MathOperation operation)
    {
        _initialValue = initialValue;
        _currentOp = operation;
 
        CurrentValue = _initialValue;
        PreviousValue = CurrentValue;
 
        InitializeComponent();
 
        InitializeButtons();
    }
 
    private void InitializeButtons()
    {
        _buttonDigits[_button0] = 0;
        _buttonDigits[_button1] = 1;
        _buttonDigits[_button2] = 2;
        _buttonDigits[_button3] = 3;
        _buttonDigits[_button4] = 4;
        _buttonDigits[_button5] = 5;
        _buttonDigits[_button6] = 6;
        _buttonDigits[_button7] = 7;
        _buttonDigits[_button8] = 8;
        _buttonDigits[_button9] = 9;
 
        _buttonOps[_buttonAdd] = MathOperation.Add;
        _buttonOps[_buttonSubtract] = MathOperation.Subtract;
        _buttonOps[_buttonMultiply] = MathOperation.Multiply;
        _buttonOps[_buttonDivide] = MathOperation.Divide;
    }
}

All that’s left is to the actual work of handling input. Since input can be from both keyboard and button clicks, let’s first define methods to handle the general operations, and we can hook up the input later.

Generic Input Handling

First, we’ll look at the generic input handlers. These are called by the mouse and keyboard handlers and they return true so they can notify the caller of whether they actually handled the operation.

The “C” button on the calculator will not only clear the current input, but set the current value to 0 (I’m not going to bother implementing a “CE” button that clears just the current input, but it would be easy to add).

private bool HandleClear()
{
   CurrentInput = "";
   CurrentValue = 0;
 
   return true;
}

When the user hits escape, you want to close the window, after setting the value back to the initial one.

private bool HandleEscape()
{
    _canceled = true;
    CurrentValue = _initialValue;
 
    Close();
 
    return true;
}

We need the _canceled flag because, as we’ll see below, when the window is deactivated, under normal circumstances we want to complete the current operation, but in the canceled case we want to do nothing.

When a user hits Enter or presses the Equals button, the current operation should be completed and the window closed. In this control, since we also want the current operation to be completed when the window is deactivated, hitting Equals will just cause the window to close and we’ll handle the calculation in the deactivation code.

private bool HandleEquals()
{
    //The final operation will be 
    //handled when the window closes
    Close();
    return true;
}

This calculator provides a back button to erase the previously-entered digit. If the input becomes empty, then the current value is set to 0.

private bool HandleBack()
{
    if (!string.IsNullOrEmpty(CurrentInput))
    {
        CurrentInput = CurrentInput.Substring(0, CurrentInput.Length - 1);
        //this is guaranteed to succeed because we validate when we add digits
        if (!string.IsNullOrEmpty(CurrentInput))
        {
            CurrentValue = Int32.Parse(CurrentInput);
        }
        else
        {
            CurrentValue = 0;
        }
    }
    return true;
}

When accepting new input, our button and keyboard handlers will ensure that the user can only enter digits, but we also need to make sure we handle integer overflow. An easy way to do this is to treat the new digit as a character and append it to the current input and then reparse it.

private bool HandleDigit(int digit)
{
    string newInput = CurrentInput + digit.ToString();
    int temp = 0;
    //make sure the full input is a number
    if (Int32.TryParse(newInput, out temp))
    {
        CurrentInput = newInput;
        CurrentValue = temp;
        return true;
    }
    return false;
}

Finally, when the user selects an operation we need to do one of two things. If there is no current input, then we can just change the current operation to the new one. This lets you change your mind, say if you hit ‘+’, but really wanted ‘-’.

On the other hand, if the user has already entered a number, then you know you’re finishing up the current expression and the user wants to calculate the results and start a new expression. As an example,  consider the expression A + B. A is the initial value of the NumericEntryControl, the + is what triggered the calculator to show up, and B is the number the user entered after the calculator was visible. When the next operation is input, A + B should be resolved, placed into A, the current operation set, and the user can now enter the next B, and so on.

private bool HandleOperation(MathOperation op)
{
    if (CurrentInput.Length > 0)
    {
        ProcessCurrentOperation();
    }
    _currentOp = op;
    return true;
}

With that, we’ve seen all of the generic input handling. Now let’s move on to the actual math.

Doing the Math

The ProcessCurrentOperation method is the heart of this control as it updates all the values according to the user’s input. Here too we need to consider what happens if the user’s calculations cause an integer overflow. To detect this we need to use a combination of the checked keyword and some exception handling. To simplify things, if this happens, the whole calculation is canceled and the window closed. We also handle divide by zero errors by just setting the new value to 0.

(The checked keyword tells .NET to issue exceptions when integer math overflows. The default behavior depends on compilation and environment settings, but the unchecked behavior is usually what happens).

private void ProcessCurrentOperation()
{
    if (string.IsNullOrEmpty(CurrentInput))
    {
        return;
    }
    
    int newValue = 0;
    checked
    {
        try
        {
            switch (_currentOp)
            {
                case MathOperation.Add:
                    newValue = PreviousValue + CurrentValue;
                    break;
                case MathOperation.Subtract:
                    newValue = PreviousValue - CurrentValue;
                    break;
                case MathOperation.Multiply:
                    newValue = PreviousValue * CurrentValue;
                    break;
                case MathOperation.Divide:
                    if (CurrentValue != 0)
                    {
                        newValue = PreviousValue / CurrentValue;
                    }
                    else
                    {
                        newValue = CurrentValue;
                    }
                    break;
                default:
                    Debug.Assert(false, "Invalid operation. Should never happen!");
                    break;
            }
 
            CurrentInput = "";
            CurrentValue = newValue;
            PreviousValue = newValue;
        }
        catch (OverflowException)
        {
            //will cause the window to close, so we better cancel everything first
            _canceled = true;
            CurrentValue = _initialValue;
 
            MessageBox.Show("The result overflowed, calculation canceled.");
        }
    }
}

Deactivation

As we said before, deaction should cause the current operation to complete, unless the user has canceled.

protected override void OnDeactivated(EventArgs e)
{
    if (!_canceled)
    {
        ProcessCurrentOperation();
        if (IsVisible)
        {
            //window is still visible if we've 
            //clicked away from the window
            //before finishing calculation
            Close();
        }
    }
    base.OnDeactivated(e);
}

The only thing that remains is hooking up mouse and keyboard input to our existing methods.

Mouse Handling

These are already referenced in the XAML, and all they do is forward to the  generic handlers.

void opButton_Click(object sender, RoutedEventArgs e)
{
    MathOperation op = _buttonOps[sender as Button];
    e.Handled = HandleOperation(op);
}
 
void digitButton_Click(object sender, RoutedEventArgs e)
{
    int digit = _buttonDigits[sender as Button];
    e.Handled = HandleDigit(digit);
}
 
private void clearButton_click(object sender, RoutedEventArgs e)
{
    e.Handled = HandleClear();
}
 
private void backButton_Click(object sender, RoutedEventArgs e)
{
    e.Handled = HandleBack();
}
 
private void equalsButton_Click(object sender, RoutedEventArgs e)
{
    e.Handled = HandleEquals();
}

Keyboard Handling

To handle the keyboard, we need to preempt the normal message flow by looking at the preview messages (which flow from the top of the UI hierarchy down, rather than the normal messages which bubble from the bottom to the top). If we don’t do this, then when we hit keys like Enter, they go to the button with the current focus, when instead we want it to always cause the Equals functionality.

protected override void OnPreviewKeyDown(KeyEventArgs e)
{
    /*take over all keyboard input
     * this is important because if a button has focus 
     * and we hit enter then the button will be clicked
     * */
 
    int digit = 0;
    MathOperation op = MathOperation.None;
    if (_keyDigits.TryGetValue(e.Key, out digit))
    {
        e.Handled = HandleDigit(digit);
    }
    else if (_keyOps.TryGetValue(e.Key, out op))
    {
        e.Handled = HandleOperation(op);
    }
    else
    {
        switch (e.Key)
        {
            case Key.Enter:
                e.Handled = HandleEquals();
                break;
            case Key.Escape:
                e.Handled = HandleEscape();
                break;
            case Key.Back:
                e.Handled = HandleBack();
                break;
            case Key.C:
                e.Handled = HandleClear();
                break;
            default:
                e.Handled = false;
                break;
        }
    }
    base.OnPreviewKeyDown(e);
}

There you have it, a working pop-up calculator, usable from any other control you can subclass. As is often the case, there are a lot more features you could add to this basic implementation:calc_demo3

  • Undo
  • Floating-point support
  • Button highlights with corresponding key presses
  • More advanced display, showing current operator, previous values, etc.
  • More robust handling of overflow

Download Source Code

If you find this article useful, you will love my book, C# 4.0 How-To, which is filled with tips such as this.

Popularity: 2% [?]

Another C# 4.0 How-To Book Give-away

In celebration of the beginning of the school year here in the USA, I’m going to give away a few more copies of my book C# 4.0 How-To .

If you’ve ever wanted a step-by-step guide with practicable code examples for hundreds of tasks in C#, .Net, and Windows, then this is the book for you. So far, I’m very pleased with the reviews its gotten (if you already have the book and haven’t left a review, why not? Smile)

Just leave a comment on this post, and I’ll choose two people at random. You must be in the US or Canada.

Also, for twitter users, if you retweet a link to this post using the hashtag #cs4howto, I’ll include you in the drawing as well.

The more comments and #cs4howto re-tweets there are, the more books I’ll give away!

Popularity: 1% [?]

Measure Amount of Data to Serialize with a Null Stream

If you’ve got to serialize some data, especially in a binary format, it’s common to output the length of the data. This is useful for versioning, random access, knowing when you’re done reading the records, among other reasons.

Therefore, you need to know the size of the data you’re going to serialize. There are a few ways to do this:

  1. Measure the position you’re at, write the data, measure the new position, subtract, and that’s your length.
  2. If you want to write the length first (which is usually better), you can write a dummy value, such as 0, then writing the data, then backing up in the stream, and writing the real value.
  3. If you can’t back up the stream (very possible in some situations, or undesirable in others), you can measure the amount of data before you write. However, now you have to maintain that code in addition to the actual serialization.
  4. My solution presented here, avoids having to maintain separate code by writing the data to a null stream which does not write any data, but keeps track of how much data was “written.”
class NullStream : System.IO.Stream
{
    public override bool CanRead { get { return false; } }

    public override bool CanSeek { get { return false; } }

    public override bool CanWrite {get { return true; } }

    public override void Flush() { /*do nothing*/ }

    public override long Length { get { return Position; } }

    private long _position = 0;
    public override long Position
    {
        get
        {
            return _position;
        }
        set
        {
            _position = value;
        }
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        throw new InvalidOperationException();
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        Position += count;
    }

    public override long Seek(long offset, System.IO.SeekOrigin origin)
    {
        throw new InvalidOperationException();
    }

    public override void SetLength(long value)
    {
        throw new InvalidOperationException();
    }
}

You can use it like this:

long GetDataSize()
{
    using (NullStream stream = new NullStream())
    {
        if (SaveData(stream))
        {
            return stream.Position;
        }
    }
    return 0;
}

There is a downside to something like this: you’re still essentially doing a lot of the work of serialization. Sure, you’re not writing out the bytes anywhere, but if, say, you need to encode a string as bytes before writing to the stream, that’s still going to happen.

Still, this technique made sense in my case, maybe it will work for you.

Popularity: 1% [?]

C# 4.0 How-To Available Now!

Well, it’s finally out! Amazon no longer lists the book as available for pre-sale, and it should be shipping to purchasers today or tomorrow. If you’re a B&N shopper, you can also order it there, or grab it in stores within a few days.

From the product description:

Real Solutions for C# 4.0 Programmers

Need fast, robust, efficient code solutions for Microsoft C# 4.0? This book delivers exactly what you’re looking for. You’ll find more than 200 solutions, best-practice techniques, and tested code samples for everything from classes to exceptions, networking to XML, LINQ to Silverlight. Completely up-to-date, this book fully reflects major language enhancements introduced with the new C# 4.0 and .NET 4.0. When time is of the essence, turn here first: Get answers you can trust and code you can use, right now!

Beginning with the language essentials and moving on to solving common problems using the .NET Framework, C# 4.0 How-To addresses a wide range of general programming problems and algorithms. Along the way is clear, concise coverage of a broad spectrum of C# techniques that will help developers of all levels become more proficient with C# and the most popular .NET tools.

Fast, Reliable, and Easy to Use!

  • Write more elegant, efficient, and reusable code
  • Take advantage of real-world tips and best-practices advice
  • Create more effective classes, interfaces, and types
  • Master powerful data handling techniques using collections, serialization, databases, and XML
  • Implement more effective user interfaces with both WPF and WinForms
  • Construct Web-based and media-rich applications with ASP.NET and Silverlight
  • Make the most of delegates, events, and anonymous methods
  • Leverage advanced C# features ranging from reflection to asynchronous programming
  • Harness the power of regular expressions
  • Interact effectively with Windows and underlying hardware
  • Master the best reusable patterns for designing complex programs

I’ll be doing a book giveaway at some point as well, once I get my own shipment. Stay tuned!

Get it from Amazon

Get it from Barnes and Noble

Popularity: 3% [?]

How to position windows correctly at 120 DPI in WPF

If you want to place a window at a specific place in WPF, it will work pretty much as you expect—unless your DPI is 120 (the default is 96). Here’s a sample that shows how to put it where you want.

In this case, I want to put a window just under another control, aligned to its left side.

 

CalcWindow calc = new CalcWindow();
Point point = this.PointToScreen(
    new Point(0, this.ActualHeight));
 
PresentationSource source = 
    PresentationSource.FromVisual(control);
 
double dpiX = 
    96.0 * source.CompositionTarget.TransformToDevice.M11;
double dpiY = 
    96.0 * source.CompositionTarget.TransformToDevice.M22;
 
calc.Left = point.X * 96.0 / dpiX;
calc.Top = point.Y * 96.0 / dpiY;
 
calc.Show();

The crux of this is getting the current DPI. You could use P/Invoke to call native methods to get this, but the transformation matrix contains the same information as well.

Popularity: 8% [?]

A WPF Numeric Entry Control

image When WPF first shipped, there was a noticeable lack of certain controls we’ve become used to in Win32 and WinForms: Calendar, DateTimePicker, and NumericUpDown. WPF 4 adds Calendar and DatePicker, but not anything for numeric entry.

For my solution I wanted something that behaved very similarly to the WinForms NumericUpdown control.

Some of the specifications:

  1. Allows user to set Value, MaxValue, MinValue, Increment, and LargeIncrement.
  2. Text directly entered is limited to numbers
  3. Pasted text is not intercepted, but when the control has lost focus it will be validated and reset to the previous value if necessary
  4. Two buttons, for increment and decrement
  5. Holding down the buttons with the mouse causes the number to increment continuously
  6. Up and down increment and decrement by Interval
  7. Page Up and Page Down increment and decrement by LargeInterval
  8. This version only supports integers

Creating the control

To begin, create a new WPF project and add a new User Control called NumericEntryControl. This will create a pair of .cs and .xaml files.

In the XAML file, change the <Grid> root element to be a <DockPanel>.

 

<UserControl 
    x:Class="NumericEntryDemo.NumericEntryControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    mc:Ignorable="d"
    xmlns:my="clr-namespace:NumericEntryDemo" Width="200" Height="26">
 
    <DockPanel>
    </DockPanel>
</UserControl>

Before we add the controls, let’s add some properties to our user control to hold the values the controls will use. These are dependency properties in order to take advantage of all the WPF goodness like data binding and animation. Let’s also add standard .Net property wrappers.

 

public partial class NumericEntryControl : UserControl
{
    public static readonly DependencyProperty ValueProperty = 
        DependencyProperty.Register("Value",
            typeof(Int32), typeof(NumericEntryControl),
            new PropertyMetadata(0));
 
    public static readonly DependencyProperty MaxValueProperty = 
        DependencyProperty.Register("MaxValue",
            typeof(Int32), typeof(NumericEntryControl),
            new PropertyMetadata(100));
 
    public static readonly DependencyProperty MinValueProperty = 
        DependencyProperty.Register("MinValue",
            typeof(Int32), typeof(NumericEntryControl),
            new PropertyMetadata(0));
 
    public static readonly DependencyProperty IncrementProperty = 
        DependencyProperty.Register("Increment", 
            typeof(Int32), typeof(NumericEntryControl),
            new PropertyMetadata(1));
 
    public static readonly DependencyProperty LargeIncrementProperty = 
        DependencyProperty.Register("LargeIncrement",
            typeof(Int32), typeof(NumericEntryControl),
            new PropertyMetadata(5));    
 
    public Int32 Value
    {
        get
        {
            return (Int32)GetValue(ValueProperty);
        }
        set
        {
            SetValue(ValueProperty, value);
        }
    }
    
    public Int32 MaxValue
    {
        get
        {
            return (Int32)GetValue(MaxValueProperty);
        }
        set
        {
            SetValue(MaxValueProperty, value);
        }
    }
    
    public Int32 MinValue
    {
        get
        {
            return (Int32)GetValue(MinValueProperty);
        }
        set
        {
            SetValue(MinValueProperty, value);
        }
    }
    
    public Int32 Increment
    {
        get
        {
            return (Int32)GetValue(IncrementProperty);
        }
        set
        {
            SetValue(IncrementProperty, value);
        }
    }
    
    public Int32 LargeIncrement
    {
        get
        {
            return (Int32)GetValue(LargeIncrementProperty);
        }
        set
        {
            SetValue(LargeIncrementProperty, value);
        }
    }
}

 

Creating an incrementing TextBox

Add a TextBox inside the <DockPanel> and bind its text to the value we created in our control:

<DockPanel d:LayoutOverrides="Width">
    <TextBox 
        x:Name="_textbox" 
        Margin="2,0" 
        Text="{Binding Value, 
            Mode=TwoWay, 
            RelativeSource={RelativeSource FindAncestor,
                AncestorLevel=1, 
                AncestorType={x:Type my:NumericEntryControl}}, 
            UpdateSourceTrigger=PropertyChanged}" 
        HorizontalAlignment="Stretch" 
        HorizontalContentAlignment="Right" 
        VerticalContentAlignment="Center" />
</DockPanel>

This will create a TextBox that sizes itself with its parent (a feature I wanted, but is not strictly necessary) and  its text will be bound to the Value in our UserControl.

Handling text input

It used to be that you pointed with a mouse and entered text with a keyboard. However, it is common now to enter text with a stylus, gestures, or some future method not invented yet. Thankfully, WPF supports generic text input handling so you don’t have to concern yourself with the specific hardware.

 

public NumericEntryControl()
{
   InitializeComponent();
 
   _textbox.PreviewTextInput += 
        new TextCompositionEventHandler(_textbox_PreviewTextInput);
}
 
void _textbox_PreviewTextInput(object sender, 
                   TextCompositionEventArgs e)
{
    if (!IsNumericInput(e.Text))
    {
        e.Handled = true;
        return;
    }
}
 
private bool IsNumericInput(string text)
{
    foreach (char c in text)
    {
        if (!char.IsDigit(c))
        {
            return false;
        }
    }
    return true;
}

This prevents anything except numbers from being entered, whether via character recognition or keyboard. It does not, however, prevent the user from pasting non-numeric text into the box. We’ll handle that later.

Validating Text input

It’s problematic to validate and correct user input as they are entering it. For example, if you set the MaxValue to 100, then every time you enter 1000, it jumps to 100, it can be jarring. It’s a similar situation with text pasted into the control. What the NumericUpDown control does is handle these sort of situations when the control loses focus.

To prepare for this, when the control gains focus, we need to save the last valid value so we have something to restore to.

When the control loses focus, we need to first verify that it is a number and if so, clip it to the bounds of our MinValue and MaxValue. If anything fails, set it back to the previous value.

 

public partial class NumericEntryControl : UserControl
{
    private int _previousValue = 0;
 
    public NumericEntryControl()
    {
        InitializeComponent();
 
        _textbox.PreviewTextInput += 
            new TextCompositionEventHandler(
                _textbox_PreviewTextInput);
        _textbox.GotFocus += 
            new RoutedEventHandler(_textbox_GotFocus);
        _textbox.LostFocus += 
            new RoutedEventHandler(_textbox_LostFocus);
    }
 
    void _textbox_GotFocus(object sender, RoutedEventArgs e)
    {
        _previousValue = Value;
    }
 
    void _textbox_LostFocus(object sender, RoutedEventArgs e)
    {
        int newValue = 0;
        if (Int32.TryParse(_textbox.Text, out newValue))
        {
            if (newValue > MaxValue)
            {
                newValue = MaxValue;
            }
            else if (newValue < MinValue)
            {
                newValue = MinValue;
            }                
        }
        else
        {
            newValue = _previousValue;
        }
        _textbox.Text = newValue.ToString();
    }
}

Handle arrow keys

Just because WPF can handle text input from a variety of sources in a hardware-agnostic way doesn’t mean we should ignore the particular strengths of the keyboard. Specifically, we should handle the up and down arrows.

 

public NumericEntryControl()
{
    ...
    _textbox.PreviewKeyDown += 
        new KeyEventHandler(_textbox_PreviewKeyDown);
}
 
void _textbox_PreviewKeyDown(object sender, KeyEventArgs e)
{
    switch (e.Key)
    {
        case Key.Up:
            IncrementValue();
            break;
        case Key.Down:
            DecrementValue();
            break;
        case Key.PageUp:
            Value = Math.Min(Value + LargeIncrement, MaxValue);
            break;
        case Key.PageDown:
            Value = Math.Max(Value - LargeIncrement, MinValue);
            break;
        default:
            //do nothing
            break;
    }
}
 
private void IncrementValue()
{
    Value = Math.Min(Value + Increment, MaxValue);
}
 
private void DecrementValue()
{
    Value = Math.Max(Value - Increment, MinValue);
}

IncrementValue() and DecrementValue() are pulled out as their own method because they’re used in the button-handling code as well (see below).

The code so far is a perfectly usable textbox that accepts only numbers and can be incremented using the keyboard. Typically, however, we also need to support the mouse, and for that we need buttons (unless you want to do something exotic like programs like Photoshop and Lightroom do, where text boxes have support for incrementing gestures—that’s another article).

A button you can hold down

Adding buttons to increment once per click is pretty easy, but we really want to be able to hold down the buttons and have the TextBox increment. Let’s start by adding the XAML for the buttons:

 

<UserControl 
    x:Class="NumericEntryDemo.NumericEntryControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    mc:Ignorable="d"
    xmlns:my="clr-namespace:NumericEntryDemo" 
    Width="200" Height="26"
    >
    <DockPanel d:LayoutOverrides="Width">
        <Button x:Name="buttonDecrement" 
                DockPanel.Dock="Left"
                Content="-" 
                Width="{Binding ActualHeight, 
                    ElementName=buttonDecrement, Mode=Default}" 
                Height="{Binding ActualHeight, 
                    ElementName=_textbox, Mode=Default}"/>
        <Button x:Name="buttonIncrement" 
                DockPanel.Dock="Right" 
                Content="+" 
                Width="{Binding ActualHeight, 
                    ElementName=buttonDecrement, Mode=Default}" 
                Height="{Binding ActualHeight, 
                    ElementName=_textbox, Mode=Default}"/>
        <TextBox 
            x:Name="_textbox" 
            Margin="2,0" 
            Text="{Binding Value, 
                Mode=TwoWay, 
                RelativeSource={RelativeSource FindAncestor,
                    AncestorLevel=1, 
                    AncestorType={x:Type my:NumericEntryControl}}, 
                UpdateSourceTrigger=PropertyChanged}" 
            HorizontalAlignment="Stretch" 
            HorizontalContentAlignment="Right" 
            VerticalContentAlignment="Center" />
    </DockPanel>
</UserControl>

Note that the button Width property is  bound to its own ActualHeight property, and the Height property is bound to the TextBox’s ActualHeight. This has the effect of keeping the buttons square, the same height as the TextBox. It’s an effect I wanted, but you can easily dispose of it. With these buttons, our control finally takes shape:

image

How fast should we increment?

Before writing the code to do the incrementing as we hold the button down, it’s worth considering how fast the incrementing should occur. Ideally, we would want it to increment at about the same rate as if we were holding down the up key on the keyboard. The keyboard repeat rate is an operating system value that we can retrieve.

There are actually two values:

private static int _delayRate = 
    System.Windows.SystemParameters.KeyboardDelay;
private static int _repeatSpeed = 
    Math.Max(1, System.Windows.SystemParameters.KeyboardSpeed);

The delay rate is how long we should wait before starting the repetition, and is given in multiples of 250ms. Roughly speaking, humans can determine and control actions with lengths of time of about 200ms, so 250ms is a good value to start with. Any shorter and the repetition might start when it was not intended (say, if they just click the button instead of holding it down).

The keyboard speed is the number of times per second we should repeat—sort of. The value can be 0, so because of the way I use it below I want to sure it’s at least 1.

To allow us to hold the button down, we need to override the default mouse handling of a button which is to disable the standard LeftMouseButtonDown/Up messages. Instead, we need to handle the PreviewMouseLeftButtonDown message and its corresponding Up message.

When we handle the down message, we need to set a timer for the keyboard delay value. When we handle the timer’s tick, we need to increment (or decrement) and change the timer’s interval to the repeat speed. This repeat speed is calculated merely by dividing 1000ms (1s) by the rate per second. There may be better ways, but this gets pretty close to the rate experienced by the keyboard on my computer. Finally, when the mouse button is released we need to stop the timer. We also do a final increment, which will cover the case where the user clicks instead of holds.

We also need to capture the mouse in case the user moves it off the button—otherwise the timer will just keep incrementing forever.

Here’s the code:

 

private DispatcherTimer _timer = 
    new DispatcherTimer();
private static int _delayRate = 
    System.Windows.SystemParameters.KeyboardDelay;
private static int _repeatSpeed = 
    Math.Max(1, System.Windows.SystemParameters.KeyboardSpeed);
 
private bool _isIncrementing = false;
 
public NumericEntryControl()
{
    ...
 
    buttonIncrement.PreviewMouseLeftButtonDown += 
        new MouseButtonEventHandler(
            buttonIncrement_PreviewMouseLeftButtonDown);
    buttonIncrement.PreviewMouseLeftButtonUp += 
        new MouseButtonEventHandler(
            buttonIncrement_PreviewMouseLeftButtonUp);
 
    buttonDecrement.PreviewMouseLeftButtonDown += 
        new MouseButtonEventHandler(
            buttonDecrement_PreviewMouseLeftButtonDown);
    buttonDecrement.PreviewMouseLeftButtonUp += 
        new MouseButtonEventHandler(
            buttonDecrement_PreviewMouseLeftButtonUp);
 
    _timer.Tick += new EventHandler(_timer_Tick);
}
 
void buttonIncrement_PreviewMouseLeftButtonDown(
    object sender, MouseButtonEventArgs e)
{
    buttonIncrement.CaptureMouse();
    _timer.Interval = 
        TimeSpan.FromMilliseconds(_delayRate * 250);
    _timer.Start();
 
    _isIncrementing = true;
}
 
void buttonIncrement_PreviewMouseLeftButtonUp(
    object sender, MouseButtonEventArgs e)
{
    _timer.Stop();
    buttonIncrement.ReleaseMouseCapture();
    IncrementValue();
}
 
void buttonDecrement_PreviewMouseLeftButtonDown(
    object sender, MouseButtonEventArgs e)
{
    buttonDecrement.CaptureMouse();
    _timer.Interval = 
        TimeSpan.FromMilliseconds(_delayRate * 250);
    _timer.Start();
 
    _isIncrementing = false;
}
 
void buttonDecrement_PreviewMouseLeftButtonUp(
    object sender, MouseButtonEventArgs e)
{
    _timer.Stop();
    buttonDecrement.ReleaseMouseCapture();
    DecrementValue();
}
 
void _timer_Tick(object sender, EventArgs e)
{
    if (_isIncrementing)
    {
        IncrementValue();
    }
    else
    {
        DecrementValue();
    }
    _timer.Interval = 
        TimeSpan.FromMilliseconds(1000.0 / _repeatSpeed);
}

And voila! A NumericEntryControl that’s basic and easy-to-use for both keyboard and mouse.

Further improvements

This isn’t the last word in numeric entry controls, by any means. There are many ways to accomplish it, and this is one that worked well for me. There are a number of further enhancements you could do (and perhaps should do):

  • More validation
  • Ensure that MaxValue >= MinValue
  • Set focus to the TextBox when the control gains focus (maybe)
  • Define strokes to increment and decrement with a stylus
  • The user can change the keyboard repeat rate through Control Panel. This program could be modified to listen for updates to this value.

There’s also another, really cool feature that I will add to this in a future post.

Download full source.

Found this article helpful? Want a resource of hundreds of similar, how-to tips? I’ve written a book that covers topics like this and more in C# 4. Check out C# 4.0 How-To!

Popularity: 10% [?]

Updated CPU usage article

I made a important changes to the CPU usage code and have updated the article to reflect it. Instead of a critical section, the code uses just the interlocked increment/decrement functions. I also updated the sample demo to use multiple threads to read the CPU usage to demonstrate the thread safety clearly.

Popularity: 11% [?]

Determine CPU usage of current process (C++ and C#)

My first book, C# 4.0 How-To is now shipping! If you like tips you can use, check it out!

Updated 2/4/2009: I changed the implementation of these classes from the original:

  • Instead of a critical section, InterlockedIncrement/Decrement is used.
  • The sample driver program now demos using multiple threads using the CpuUsage class to show thread safety.

Download the C++ and C# projects that accompany this article.

Just to make it clear, there is no API called GetProcessCpuPercentage(). To find out the percentage, we can use some other, real APIs and do some calculations. Before getting to the equation and code, let’s discuss the different types of time available.

There are four types of time:

  1. Wall time – The actual, real-world progression of time as measured by you on your watch.
  2. Kernel time – The amount of time spent in kernel mode (protected, high-order mode of operation)
  3. User time – the amount of time spent in user-mode (often by the process itself)
  4. Idle time – nothing going on at all

Kernel, User, and Idle sum to total time, which is approximately wall-time.

Each process spends some time in kernel mode and some time in user mode. We just need to compare the time spent by a process to the time spent by all processes on the computer, since the last time we made such a measurement. It is important to note that we do NOT take into account the idle time.

Thus, the equation is

CpuPercentageEquation

There are two APIs that are useful:

The times reported are absolute, so what we are actually interested is in the difference between the current times and those from a previous run.

Armed with this information, we can calculate the CPU usage for the current process (or any arbitrary process, for that matter).

Let’s do it first in C++ to demonstrate usage of the APIs.

CPU Usage Percentage in C++

Here’s the header file:

   1: #pragma once
   2: #include <windows.h>
   3: 
   4: class CpuUsage
   5: {
   6: public:
   7:     CpuUsage(void);
   8:
   9:     short  GetUsage();
  10: private:
  11:     ULONGLONG SubtractTimes(const FILETIME& ftA, const FILETIME& ftB);
  12:     bool EnoughTimePassed();
  13:     inline bool IsFirstRun() const { return (m_dwLastRun == 0); }
  14:
  15:     //system total times
  16:     FILETIME m_ftPrevSysKernel;
  17:     FILETIME m_ftPrevSysUser;
  18: 
  19:     //process times
  20:     FILETIME m_ftPrevProcKernel;
  21:     FILETIME m_ftPrevProcUser;
  22: 
  23:     short m_nCpuUsage;
  24:     ULONGLONG m_dwLastRun;
  25:
  26:     volatile LONG m_lRunCount;
  27: };

The GetUsage() method is where the work occurs. The other methods are to help in the calculations. The critical section run count enables the code to be called in a multi-threaded environment without problems. I also prevent the code from being called more often than every 250ms. Here is the complete implementation:

   1: #include "StdAfx.h"
   2: #include <windows.h>
   3: #include "CpuUsage.h"
   4: 
   5: CpuUsage::CpuUsage(void)
   6: :m_nCpuUsage(-1)
   7: ,m_dwLastRun(0)
   8: ,m_lRunCount(0)
   9: {
  10:     ZeroMemory(&m_ftPrevSysKernel, sizeof(FILETIME));
  11:     ZeroMemory(&m_ftPrevSysUser, sizeof(FILETIME));
  12: 
  13:     ZeroMemory(&m_ftPrevProcKernel, sizeof(FILETIME));
  14:     ZeroMemory(&m_ftPrevProcUser, sizeof(FILETIME));
  15: 
  16: }
  17: 
  18: 
  19: /**********************************************
  20: * CpuUsage::GetUsage
  21: * returns the percent of the CPU that this process
  22: * has used since the last time the method was called.
  23: * If there is not enough information, -1 is returned.
  24: * If the method is recalled to quickly, the previous value
  25: * is returned.
  26: ***********************************************/
  27: short CpuUsage::GetUsage()
  28: {
  29:     //create a local copy to protect against race conditions in setting the 
  30:     //member variable
  31:     short nCpuCopy = m_nCpuUsage;
  32:     if (::InterlockedIncrement(&m_lRunCount) == 1)
  33:     {
  34:         /*
  35:         If this is called too often, the measurement itself will greatly 
  36:         affect the results.
  37:         */
  38: 
  39:         if (!EnoughTimePassed())
  40:         {
  41:             ::InterlockedDecrement(&m_lRunCount);
  42:             return nCpuCopy;
  43:         }
  44: 
  45:         FILETIME ftSysIdle, ftSysKernel, ftSysUser;
  46:         FILETIME ftProcCreation, ftProcExit, ftProcKernel, ftProcUser;
  47: 
  48:         if (!GetSystemTimes(&ftSysIdle, &ftSysKernel, &ftSysUser) ||
  49:             !GetProcessTimes(GetCurrentProcess(), &ftProcCreation,
  50:                 &ftProcExit, &ftProcKernel, &ftProcUser))
  51:         {
  52:             ::InterlockedDecrement(&m_lRunCount);
  53:             return nCpuCopy;
  54:         }
  55: 
  56:         if (!IsFirstRun())
  57:         {
  58:             /*
  59:             CPU usage is calculated by getting the total amount of time 
  60:             the system has operated since the last measurement 
  61:             (made up of kernel + user) and the total
  62:             amount of time the process has run (kernel + user).
  63:             */
  64:             ULONGLONG ftSysKernelDiff =
  65:                 SubtractTimes(ftSysKernel, m_ftPrevSysKernel);
  66:             ULONGLONG ftSysUserDiff =
  67:                 SubtractTimes(ftSysUser, m_ftPrevSysUser);
  68: 
  69:             ULONGLONG ftProcKernelDiff =
  70:                 SubtractTimes(ftProcKernel, m_ftPrevProcKernel);
  71:             ULONGLONG ftProcUserDiff =
  72:             SubtractTimes(ftProcUser, m_ftPrevProcUser);
  73: 
  74:             ULONGLONG nTotalSys =  ftSysKernelDiff + ftSysUserDiff;
  75:             ULONGLONG nTotalProc = ftProcKernelDiff + ftProcUserDiff;
  76: 
  77:             if (nTotalSys > 0)
  78:             {
  79:                 m_nCpuUsage = (short)((100.0 * nTotalProc) / nTotalSys);
  80:             }
  81:         }
  82:
  83:         m_ftPrevSysKernel = ftSysKernel;
  84:         m_ftPrevSysUser = ftSysUser;
  85:         m_ftPrevProcKernel = ftProcKernel;
  86:         m_ftPrevProcUser = ftProcUser;
  87:
  88:         m_dwLastRun = GetTickCount64();
  89: 
  90:         nCpuCopy = m_nCpuUsage;
  91:     }
  92:
  93:     ::InterlockedDecrement(&m_lRunCount);
  94: 
  95:     return nCpuCopy;
  96: }
  97: 
  98: ULONGLONG CpuUsage::SubtractTimes(const FILETIME& ftA, const FILETIME& ftB)
  99: {
 100:     LARGE_INTEGER a, b;
 101:     a.LowPart = ftA.dwLowDateTime;
 102:     a.HighPart = ftA.dwHighDateTime;
 103: 
 104:     b.LowPart = ftB.dwLowDateTime;
 105:     b.HighPart = ftB.dwHighDateTime;
 106: 
 107:     return a.QuadPart - b.QuadPart;
 108: }
 109: 
 110: bool CpuUsage::EnoughTimePassed()
 111: {
 112:     const int minElapsedMS = 250;//milliseconds
 113: 
 114:     ULONGLONG dwCurrentTickCount = GetTickCount64();
 115:     return (dwCurrentTickCount - m_dwLastRun) > minElapsedMS;
 116: }

In order to test this, here is a simple program that starts two threads that run an infinite loop, eating the processor. On a dual-core system, this process will take roughly 85-95% of the CPU. I also start two threads to access the usage object and poll the CPU usage in order to demonstrate the thread safety of the object.

   1: // CpuUsageCpp.cpp : Defines the entry point for the console application.
   2: //
   3: 
   4: #include "stdafx.h"
   5: #include <windows.h>
   6: #include "CpuUsage.h"
   7: 
   8: DWORD WINAPI EatItThreadProc(LPVOID lpParam);
   9: DWORD WINAPI WatchItThreadProc(LPVOID lpParam);
  10: 
  11: CpuUsage usage;
  12: 
  13: int _tmain(int argc, _TCHAR* argv[])
  14: {
  15:     //start threads to eat the processor
  16:     CreateThread(NULL, 0, EatItThreadProc, NULL, 0, NULL);
  17:     CreateThread(NULL, 0, EatItThreadProc, NULL, 0, NULL);
  18: 
  19:     //start threads to watch the processor (to test thread-safety)
  20:     CreateThread(NULL, 0, WatchItThreadProc, NULL, 0, NULL);
  21:     CreateThread(NULL, 0, WatchItThreadProc, NULL, 0, NULL);
  22:
  23:     while (true)
  24:     {
  25:         Sleep(1000);
  26:     }
  27: 
  28:     return 0;
  29: }
  30: 
  31: 
  32: DWORD WINAPI WatchItThreadProc(LPVOID lpParam)
  33: {
  34:     while (true)
  35:     {
  36:         short cpuUsage = usage.GetUsage();
  37: 
  38:         printf("Thread id %d: %d%% cpu usage\n", ::GetCurrentThreadId(), cpuUsage);
  39:         Sleep(1000);
  40:     }
  41: }
  42: 
  43: DWORD WINAPI EatItThreadProc(LPVOID lpParam)
  44: {
  45:     ULONGLONG accum = 0;
  46:     while (true)
  47:     {
  48:         accum++;
  49:     }
  50: 
  51:     printf("%64d\n", accum);
  52: }

C# Version

In C#, The System.Diagnostics.Process can give us the time information for a specific process. However, we still need the Win32 API call for getting the total system times (GetSystemTimes). The Process class reports times in TimeSpans, not FILETIME, so our class is modified accordingly.

   1: using System;using System.Collections.Generic;
   2: using System.Linq;
   3: using System.Text;
   4: using System.Runtime.InteropServices;
   5: using ComTypes = System.Runtime.InteropServices.ComTypes;
   6: using System.Threading;
   7: using System.Diagnostics;
   8: 
   9: namespace CpuUsageCs
  10: {
  11:     class CpuUsage
  12:     {
  13:         [DllImport("kernel32.dll", SetLastError = true)]
  14:         static extern bool GetSystemTimes(
  15:                     out ComTypes.FILETIME lpIdleTime,
  16:                     out ComTypes.FILETIME lpKernelTime,
  17:                     out ComTypes.FILETIME lpUserTime
  18:                     );
  19: 
  20:         ComTypes.FILETIME _prevSysKernel;
  21:         ComTypes.FILETIME _prevSysUser;
  22: 
  23:         TimeSpan _prevProcTotal;
  24:
  25:         Int16 _cpuUsage;
  26:         DateTime _lastRun;
  27:         long _runCount;
  28: 
  29:         public CpuUsage()
  30:         {
  31:             _cpuUsage = -1;
  32:             _lastRun = DateTime.MinValue;
  33:             _prevSysUser.dwHighDateTime = _prevSysUser.dwLowDateTime = 0;
  34:             _prevSysKernel.dwHighDateTime = _prevSysKernel.dwLowDateTime = 0;
  35:             _prevProcTotal = TimeSpan.MinValue;
  36:             _runCount = 0;
  37:         }
  38: 
  39:         public short GetUsage()
  40:         {
  41:             short cpuCopy = _cpuUsage;
  42:             if (Interlocked.Increment(ref _runCount) == 1)
  43:             {
  44:                 if (!EnoughTimePassed)
  45:                 {
  46:                     Interlocked.Decrement(ref _runCount);
  47:                     return cpuCopy;
  48:                 }
  49: 
  50:                 ComTypes.FILETIME sysIdle, sysKernel, sysUser;
  51:                 TimeSpan procTime;
  52: 
  53:                 Process process = Process.GetCurrentProcess();
  54:                 procTime = process.TotalProcessorTime;
  55: 
  56:                 if (!GetSystemTimes(out sysIdle, out sysKernel, out sysUser))
  57:                 {
  58:                     Interlocked.Decrement(ref _runCount);
  59:                     return cpuCopy;
  60:                 }
  61: 
  62:                 if (!IsFirstRun)
  63:                 {
  64:                     UInt64 sysKernelDiff =
  65:                         SubtractTimes(sysKernel, _prevSysKernel);
  66:                     UInt64 sysUserDiff =
  67:                         SubtractTimes(sysUser, _prevSysUser);
  68: 
  69:                     UInt64 sysTotal = sysKernelDiff + sysUserDiff;
  70: 
  71:                     Int64 procTotal = procTime.Ticks - _prevProcTotal.Ticks;
  72: 
  73:                     if (sysTotal > 0)
  74:                     {
  75:                         _cpuUsage = (short)((100.0 * procTotal) / sysTotal);
  76:                     }
  77:                 }
  78: 
  79:                 _prevProcTotal = procTime;
  80:                 _prevSysKernel = sysKernel;
  81:                 _prevSysUser = sysUser;
  82: 
  83:                 _lastRun = DateTime.Now;
  84: 
  85:                 cpuCopy = _cpuUsage;
  86:             }
  87:             Interlocked.Decrement(ref _runCount);
  88: 
  89:             return cpuCopy;
  90:
  91:         }
  92: 
  93:         private UInt64 SubtractTimes(ComTypes.FILETIME a, ComTypes.FILETIME b)
  94:         {
  95:             UInt64 aInt =
  96:             ((UInt64)(a.dwHighDateTime << 32)) | (UInt64)a.dwLowDateTime;
  97:             UInt64 bInt =
  98:             ((UInt64)(b.dwHighDateTime << 32)) | (UInt64)b.dwLowDateTime;
  99: 
 100:             return aInt - bInt;
 101:         }
 102: 
 103:         private bool EnoughTimePassed
 104:         {
 105:             get
 106:             {
 107:                 const int minimumElapsedMS = 250;
 108:                 TimeSpan sinceLast = DateTime.Now - _lastRun;
 109:                 return sinceLast.TotalMilliseconds > minimumElapsedMS;
 110:             }
 111:         }
 112: 
 113:         private bool IsFirstRun
 114:         {
 115:             get
 116:             {
 117:                 return (_lastRun == DateTime.MinValue);
 118:             }
 119:         }
 120:     }
 121: }

These classes can now be used wherever you need to monitor the CPU usage of a process.

Notice any improvements to be made? Leave a comment.

Download C++ and C# projects

My first book, C# 4.0 How-To is now shipping! If you like tips you can use, check it out!

Popularity: 43% [?]

An easy stack layout panel for WinForms

This is a simple, but useful tip. Users of WPF are spoiled. They have all sorts of layout options. Those of us still working in WinForms have FlowLayoutPanel and TableLayoutPanel. That’s it. WPF has those and more.

For my current project, I needed a panel to layout controls vertically. The TableLayoutPanel can be awkward to work with, at least for what I need it to. At first glance, the FlowLayoutPanel looks it won’t work, since it produces something like this:

FlowLayoutTable_1

That’s with changing the FlowDirection to TopDown and putting AutoScroll to true.

But what I want is this:

image

To achieve this layout, merely set all the following properties on a FlowLayoutPanel:

  • AutoScroll = True
  • FlowDirection = TopDown
  • WrapContents = False

et voilà, Instant stack panel.

Popularity: 18% [?]

Converting OLE_COLOR to System.Drawing.Color

I’ve been working on a project using Visual Studio Tools for Office 2008 (VSTO) and at one point I needed to get the colors for categories in Outlook 2007. There are actually 3 colors, and they are returned as uint’s–why the .Net wrappers don’t convert to colors for you, I don’t know (to avoid linking to System.Drawing?).

The important thing is to convert them into the friendly System.Drawing.Color objects I know and love. For this task, there exists a handy ColorTranslator class. There is a FromOle method that does the exact chore you need. Here’s a sample of my code:

 

   1: private void GetCategoryColors()
   2: {
   3:     foreach (OutlookLib.Category category in
   4:         Application.ActiveExplorer().Session.Categories)
   5:     {
   6:         CategoryColor color = new CategoryColor(
   7:             ColorTranslator.FromOle((Int32)category.CategoryGradientTopColor),
   8:             ColorTranslator.FromOle((Int32)category.CategoryGradientBottomColor),
   9:             ColorTranslator.FromOle((Int32)category.CategoryBorderColor));
  10:         _categoryCollection[category.Name] = color;
  11:     }
  12: }

Popularity: 10% [?]