Numeric TextBox Control Similar to MS Expression Blend

September 28, 2007

I wanted to create a control like the Numeric Value Editor found in Microsoft Expression Blend which allows you to change the value by dragging the mouse. You can download the source code here (note: change the .doc extension to .zip before extracting the source)

I found that is quite easy, first you need to create a custom control that contains all the increment parameters, described below, the actual value and code to handle the mouse events.

The control exposes the following properties:

  1. Value – The actual value.
  2. SmallChange – Small change increments done by dragging the mouse and pressing the CTRL key.
  3. DefaultChange - Default change increments done by just dragging the mouse.
  4. LargeChange – Large change increments done by dragging the mouse and pressing the Shift key.
  5. Minimum - Lower bound of the value.
  6. Maximum - Upper bound of the value.
  7. MaxPrecision - Number of digits after the decimal point.

For the control appearance you need to create a Template Style. Below there is an example of a template that contains a TextBox, a Rectangle for the dragging area and a property triggers to change the cursor to notify the user that dragging is available.

<Style x:Key="NumricEditorStyle" TargetType="{x:Type ValueEditorSample:ValueEditor}">
     <Setter Property="Template">
         <Setter.Value>
             <ControlTemplate TargetType="{x:Type ValueEditorSample:ValueEditor}">
                 <Grid>
                     <Grid.ColumnDefinitions>
                         <ColumnDefinition Width="0.5*"/>
                         <ColumnDefinition />
                     </Grid.ColumnDefinitions>                      <TextBox x:Name="PART_EDITOR" Text="{Binding Path=Value, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Grid.ColumnSpan="2"/>
                     <Rectangle x:Name="PART_DRAGGER"  Stroke="Transparent" Fill="Transparent" />
                 </Grid>
                 <ControlTemplate.Triggers>
                     <Trigger Property="IsMouseOver" Value="True" SourceName="PART_DRAGGER">
                         <Setter Property="Cursor" Value="SizeAll"/>
                     </Trigger>
                     <Trigger Property="IsDragging" Value="True">
                         <Setter Property="Cursor" Value="SizeAll"/>
                     </Trigger>
                 </ControlTemplate.Triggers>
             </ControlTemplate>
         </Setter.Value>
     </Setter>
 </Style> 


RadioButton IsChecked Binding not working

September 23, 2007

I was trying to bind a group of RadioButtons to a DependencyProperty of type bool, and I notice that when changing the selection of the radio buttons it didn’t change the DependencyProperty. I searched the web for answers and I found only these 2 threads describing the problem.

http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2052600&SiteID=1

http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1429712&SiteID=1

Unfortunately there are no good workarounds to this issue and it is not fixed yet in framework 3.5. The only solution that I found is to register to the Checked and UnChecked RoutedEvents of the RadioButton, and updating my data manually when the events are raised.

The Xaml:

    <Grid>

        <RadioButton GroupName=”MyGroup”

             HorizontalAlignment=”Center”

             Content=”Option A”

Checked=”OnOptionAChecked”
Unchecked
=”OnOptionAUnchecked” />

        <RadioButton GroupName=”MyGroup”

             HorizontalAlignment=”Center”

             Content=”Option B” />

    </Grid>

And the code behind:

private void OnOptionAChecked(object sender,
RoutedEventArgs e)

{

    MyProperty = true;

}

private void OnOptionAUnchecked(object sender, RoutedEventArgs e)

{

    MyProperty = false;

}

I hope that a fix will be introduced to framework 3.5.


Pixel Color Under Mouse

September 21, 2007

This is a feature that I wanted for a tool I’m doing. I have a color selection control that can select the color of the pixel under the mouse position from the entire application window. I searched the web for a solution and I found a cool implementation from theWPFblog, as Lee Brimelow explains:

I tried many different ways of doing this but the cleanest was to use the CroppedBitmap class. As you can see in the code below, I first pull out a 1×1 pixel cropped bitmap from the color picker image that is directly below the mouse. Then it’s just a matter of copying the 1 pixel into a byte array and reading the RGB values. There are 4 bytes in every pixel which corresponds to the RGB colors and 1 byte for alpha. To change the color of the rectangle I simply create a new SolidColorBrush from the RGB values. I can think of many great uses for this! Click on the image at the left to check out the app. The C# source code is listed below so you can check out exactly how I implemented it.

The code can be found here.

Another Alternative

Lee’s solution is not good enough for me because I need a color from a pixel found in the entire client area of my application, and Lee’s solution forces me to have a BitmapSource to take the pixel from it.

I found a cleanest way to do that, maybe not clean in “WPF” speaking but using only three simple Win32 functions:

private struct POINT
{
    public uint X;
    public uint Y;
}

[DllImport("gdi32")]
private static extern int GetPixel(int hdc, int nXPos,int nYPos);
[DllImport("user32")]
private static extern int GetWindowDC(int hwnd);
[DllImport("user32")]
private static extern int GetCursorPos(out POINTAPI lpPoint);
[DllImport("user32")]
private static extern int ReleaseDC(int hWnd, int hDC);

 

And here is the GetPixelColor method implementation:

private static SolidColorBrush GetPixelColor(Point point)
{
    int lDC = GetWindowDC( 0 );
    int intColor = GetPixel( lDC, (int)point.X, (int)point.Y );
    //
    // Release the DC after getting the Color.
    ReleaseDC( 0, lDC );

    //byte a = (byte)( ( intColor >> 0x18 ) & 0xffL );
    byte b = (byte)( ( intColor >> 0x10 ) & 0xffL );
    byte g = (byte)( ( intColor >> 8 ) & 0xffL );
    byte r = (byte)( intColor & 0xffL );
    Color color = Color.FromRgb( r, g, b );
    return new SolidColorBrush( color );
}

With GetWindowDC( 0 )  I ask for the entire window DC, which then I use with GetPixelColor that retrieves the color value from position.

The System.Windows.Media.Color class in WPF doesn’t have a FromArgb method that accepts a integer value of the color as its counterpart from System.Drawing.Color, so I break apart the RGB components from integer value.

Using it:

    protected override void OnMouseMove(MouseEventArgs e)
    {
        POINT point;
        GetCursorPos( out point );
        Point pos = new Point( point.X, point.Y );
        this.StrokeBrush = GetPixelColor( pos );
    }

This is an alternative solution, for getting the color under the mouse position even when you don’t have a BitmapSource to take it from or you are mixing WinForms or Win32 with WPF.

Have fun!


Intro

September 18, 2007

As the subject suggests this blog is going to be about WPF, .NET and other related stuff and other technical things that I deal in my every day work.

I hope that I will keep this blog interesting enough to keep people reading it.

Enjoy,

Andrés Denkberg