Data binding made simple

September 1, 2011 at 9:51 pm | Posted in Silverlight, Uncategorized, WPF | Leave a comment

Data binding is a very important topic for WPF and Silverlight applications and Microsoft has created a very rich set of functionality in the frameworks to make it work in a variety of ways.  The problem is there are so many ways of doing things that I find the documentation from different sources to be quite confusing.

Today, I was working on a little application which should be very amenable to the use of data binding UI controls (listboxes and textboxes) to data objects.  After being away from WPF for a time, I was struggling to relearn exactly the best way to do it.  The MSDN documentation is thorough but is TMI at times.

I finally ran across a tutorial that captures the essence of what I needed to do in this application as well as others that I have worked on in the past.  If you want a clear example of how to implement data binding for either Silverlight or WPF, I recommend you check out this post. 

Advertisements

Find the color of a point in a LinearGradientBrush

January 28, 2008 at 7:54 am | Posted in .Net, C#, Silverlight, WPF | 6 Comments

I became intrigued by the problem of finding the color at any point of a rectangle that has been filled with a LinearGradientBrush.  There is are techniques for doing this by essentially sampling the pixel at a rendered point but I wanted to approach the problem algorithmically.

I developed the following method which receives a rectangle object that has been filled with a LinearGradientBrush and a point relative to the upper left corner of the rectangle and returns the calculated color at that point.  There are no restrictions on the Start/Stop Points or the number of GradientStops.  The ColorInterpolationMode can be either SRgbLinearInterpolation (default) or ScRgbLinearInterpolation.  The GradientSpreadMethod is required to be the default (Pad).

There are two methods below:

Color GetColorAtPoint(Rectangle r, Point p) – finds the color at any point of a LinearGradientBrush filled rectangle.

private Double dist(Point px, Point po, Point pf) – helper method for GetColorAtPoint.

To use, copy both methods to your class and call GetColorAtPoint() with a rectangle and point.

//Calculates the color of a point in a rectangle that is filled
//with a LinearGradientBrush.
private Color GetColorAtPoint(Rectangle theRec, Point thePoint)
{
    //Get properties
    LinearGradientBrush br = (LinearGradientBrush)theRec.Fill;
 
    double y3 = thePoint.Y;
    double x3 = thePoint.X;
 
    double x1 = br.StartPoint.X * theRec.ActualWidth;
    double y1 = br.StartPoint.Y * theRec.ActualHeight;
    Point p1 = new Point(x1, y1); //Starting point
 
    double x2 = br.EndPoint.X * theRec.ActualWidth;
    double y2 = br.EndPoint.Y * theRec.ActualHeight;
    Point p2 = new Point(x2, y2);  //End point
 
    //Calculate intersecting points 
    Point p4 = new Point(); //with tangent
 
    if (y1 == y2) //Horizontal case
    {
        p4 = new Point(x3, y1);
    }
 
    else if (x1 == x2) //Vertical case
    {
        p4 = new Point(x1, y3);
    }
 
    else //Diagnonal case
    {
        double m = (y2 - y1) / (x2 - x1);
        double m2 = -1 / m;
        double b = y1 - m * x1;
        double c = y3 - m2 * x3;
 
        double x4 = (c - b) / (m - m2);
        double y4 = m * x4 + b;
        p4 = new Point(x4, y4);
    }
 
    //Calculate distances relative to the vector start
    double d4 = dist(p4, p1, p2);
    double d2 = dist(p2, p1, p2);
 
    double x = d4 / d2;
 
    //Clip the input if before or after the max/min offset values
    double max = br.GradientStops.Max(n => n.Offset);
    if (x > max)
    {
        x = max;
    }
    double min = br.GradientStops.Min(n => n.Offset);
    if (x < min)
    {
        x = min;
    }
 
    //Find gradient stops that surround the input value
    GradientStop gs0 = br.GradientStops.Where(n => n.Offset <= x).OrderBy(n => n.Offset).Last();
    GradientStop gs1 = br.GradientStops.Where(n => n.Offset >= x).OrderBy(n => n.Offset).First();
 
    float y = 0f;
    if (gs0.Offset != gs1.Offset)
    {
        y = (float)((x - gs0.Offset) / (gs1.Offset - gs0.Offset));
    }
 
    //Interpolate color channels
    Color cx = new Color();
    if (br.ColorInterpolationMode == ColorInterpolationMode.ScRgbLinearInterpolation)
    {
        float aVal = (gs1.Color.ScA - gs0.Color.ScA) * y + gs0.Color.ScA;
        float rVal = (gs1.Color.ScR - gs0.Color.ScR) * y + gs0.Color.ScR;
        float gVal = (gs1.Color.ScG - gs0.Color.ScG) * y + gs0.Color.ScG;
        float bVal = (gs1.Color.ScB - gs0.Color.ScB) * y + gs0.Color.ScB;
        cx = Color.FromScRgb(aVal, rVal, gVal, bVal);
    }
    else
    {
        byte aVal = (byte)((gs1.Color.A - gs0.Color.A) * y + gs0.Color.A);
        byte rVal = (byte)((gs1.Color.R - gs0.Color.R) * y + gs0.Color.R);
        byte gVal = (byte)((gs1.Color.G - gs0.Color.G) * y + gs0.Color.G);
        byte bVal = (byte)((gs1.Color.B - gs0.Color.B) * y + gs0.Color.B);
        cx = Color.FromArgb(aVal, rVal, gVal, bVal);
    }
    return cx;
}
 
//Helper method for GetColorAtPoint
//Returns the signed magnitude of a point on a vector with origin po and pointing to pf
private double dist(Point px, Point po, Point pf)
{
    double d = Math.Sqrt((px.Y - po.Y) * (px.Y - po.Y) + (px.X - po.X) * (px.X - po.X));
    if (((px.Y < po.Y) && (pf.Y > po.Y)) ||
        ((px.Y > po.Y) && (pf.Y < po.Y)) ||
        ((px.Y == po.Y) && (px.X < po.X) && (pf.X > po.X)) ||
        ((px.Y == po.Y) && (px.X > po.X) && (pf.X < po.X)))
    {
        d = -d;
    }
    return d;
}

The method works by projecting the input point onto the vector that is described by the LinearGradientBrush Start/Stop points.  There are special cases for horizontal and vertical lines.  The width of the line is calculated as well as the relative distance of the projected point from the StartPoint (using the dist() method).  The GradientStops are ordered and two stops are found that are the closest the projected point.  The color channel values are interpolated based on the relative position of the projected point and these two stops.  The values are assembled into a color and returned.

You can download a demo of this method here.

No Events Tab in WPF Designer — No Problem!

January 12, 2008 at 11:52 am | Posted in Cider, Visual Studio 2008, WPF | Leave a comment

When I first encountered ‘Cider’, the designer for WPF, I was somewhat shocked and disappointed that the Properties window did not have an Events tab as in the Windows Forms designer where one can easily browse the available events and simply double-click to hook one up to an automatically generated event handler stub.  Was I going to have to now rely on the documentation to find the events and carefully type in the connection code and handler?

I said, “Very inconvenient!  Too much work.  I’ll stick to Forms!”  From the forums, I see that I was not alone.

Fortunately, Intellisense makes this a non-issue.  Just know the technique:

In Xaml, put your cursor after the control’s tag (Button, Ellipse, Grid etc) and press the spacebar.  Intellisense will list all of the properties and events that are available.  Note the events are marked with the lightning bolt.  Select an event from the list and hit the tab key twice.  This will add the event to the control’s attribute list and add an event handler stub in your code behind. 

Simple.

Note that the effort is almost identical to using the Events tab in Windows Forms.  The only difference is that you have to scroll through a combined list of properties and events and instead of double clicking, you ‘double tab’.

Or, if you wish, in the code behind, in the window (or page) constructor, type the name of the control (button1 for example) then a ‘.’.  Intellisense will list all properties, methods and events.  Select the event.  Then type ‘+=’ and hit the tab key twice.  Your event will be hooked up along with an event handler stub.  (This is the same as designing with Forms.)

Of course there are some common default events that can be hooked up just by double clicking on the object in the designer.  That is, if you double click on a button in the designer, you get a Button_Click event hookup.

The only thing that is really lacking is the little synopsis of what the event does that is provided by the Properties/Events window in the Forms designer; however, the event names are usually pretty self explanatory.

Hooking up events in the WPF designer are no big deal thanks to the Intellisense support and a little knowledge of how to use it.

Kaxaml: The XAML editor for me

January 11, 2008 at 8:38 am | Posted in Silverlight, WPF | Leave a comment

I highly recommend Kaxaml for your XAML editor.  Not only does it look and work great but it also has some very useful features not found on other XAML editors.

I won’t bother listing all of the features that you can read about here, but my favorites are Intellisense support (with code completion!), snippets including a generous collection of simple control styles and the ability to create and save your own, drag and drop, a beautiful color picker, and a XAML scrubber.

With other XAML editors, I thought, “what’s the point? Just use the designer in Visual Studio.”  But Kaxaml is one tool that I will use first to build and customize my UIs–largely due to its snippets, colorpicker and ease of use.  (I don’t use Blend.)

Download Kaxaml here: www.kaxaml.com

Generating Reports in Visual C# 2008 Express Edition

January 3, 2008 at 7:18 pm | Posted in C#, Visual Studio 2008, WPF | 8 Comments

A common question on the MSDN C# Express forum is how do I generate reports?  That is, how does one get a printout of data?  The Standard and higher editions of Visual Studio have reporting services that allow reports to be easily designed in a WYSIWYG way.  But Express users must either buy a third party application (à la Crystal Reports–about $300 USD) or programmatically create the report using C# and GDI+ Classes.

Now with Visual C# 2008 Express Edition, there is a new option.  Windows Presentation Foundation (WPF) provides a set of classes for converting markup (XAML) to Microsoft’s XML Page Specification (XPS).  XPS documents can then be printed directly from your application or saved an viewed and printed by other applications and platforms.

With this system, there are a couple of options:  First, you can specify the report document directly in C# code much like you would using GDI+.  That is, you could place a textBlock or graphic at a specific x,y coordinate on a page using the properties of these elements.  The second option is almost as good as having a report designer like in the higher Visual Studio editions.  You can use the designer in Visual Studio to layout your report in a WPF grid so you can see exactly how your report should look when it is rendered.  Then it is a very simple matter to pass the name of this grid to XPS generating classes for printing or saving.

Printing and XPS in WPF are covered thoroughly in Chapter 15 of Sells & Griffiths, Programming WPF, O”Reilly.

The following example shows the routine for saving a grid1 (and all that it contains) to an XPS file.

private void button1_Click(object sender, RoutedEventArgs e)
{
    Microsoft.Win32.SaveFileDialog dialog = new Microsoft.Win32.SaveFileDialog();
    if (dialog.ShowDialog() == true)
    {
        string xpsOutputPath = dialog.FileName;
        using (XpsDocument xpsFile = new XpsDocument(xpsOutputPath, FileAccess.Write))
        {
            XpsDocumentWriter xpsdw = XpsDocument.CreateXpsDocumentWriter(xpsFile);
            xpsdw.Write(grid1);
        }
    }

}

 

This routine requires adding a couple of references to the solution: ReachFramework and System.Printing.  You will need to also add some namespace references:

using System.Windows.Xps;
using System.IO;
using Microsoft.Win32;
using System.Windows.Xps.Packaging;

The code for printing directly is not much more complex and is described in the book.

With WPF one should be able to quickly and easily create a rich looking data report that can be printed or saved.

Using custom controls in WPF applications

December 6, 2007 at 10:43 am | Posted in Visual Studio 2008, WPF | 14 Comments

One thing that has frustrated me in both Silverlight and WPF applications is the use of custom controls–not their creation but how to add them to my project.  With all of the namespaces, assemblies, references that have to be used just right, my success rate has been about 50-50.  Every time I think I know the technique, I get floored by some mysterious error.  And God help you if you try to change the namespace of something!  I can easily get my solution in an unrecoverable state!

Google to the rescue?  Hardly. While there are many sites with examples of custom controls, they usually go into great detail about the creation but not how to successfully add it to your project.  This piece of magic is assumed to be obvious.  When the application is shown, the namespaces and assembly names are often the same as the project or other names in the solution so it was not so clear which name is the important reference.

So this post is my attempt to help anyone else who might have this problem by documenting the rules (that seem to work for me) for adding a custom (or user) control to your project.

Scenario 1: Add new User Control

This should be the easiest to do.

  1. 1. Project > Add User Control
  2. 2. In the dialog box now is the time to name the control.  In my example it will be LocalUserControl .  This will add the .xaml and .cs files for the control which can be used to create the control
  3. 3. In the .xaml file for the application that is going to use the control, add a reference to the namespace that is used by the UserControl like this:  xmlns:local=”clr-namespace:AddingControls”  Unless you have made namespace changes to the UserControl, this will be the same namespace as your application. 
  4. 4. Refer to the UserControl in your xaml file with the local tag: <local:LocalUserControl /> (The designer may not show the control immediately.  You may have to run the application one time.)
  5. 5. If you add an x:Name attribute to the control in the .xaml, you can reference it in the .cs file.

Scenario 2: Add existing User Control to your solution

Suppose you have an application with a local UserControl that you would like to use and possibly modify in a new application.  You want to add the source code of this control to your project.

  1. 1. Project > Add Existing Item
  2. 2. Browse to the solution folder that you are going to get the control from and select both the .xaml and .cs files for the control.  These should be added to your new solution.
  3. 3. In the .xaml file for the application that is going to use the control, add a reference to the namespace that is used by the UserControl like this:  <xmlns:local=”clr-namespace:AnotherUserControlProj”/>  Note that this will probably be different than the namespace for the application you are creating. 
  4. 4. Refer to the UserControl in your xaml file with the local tag: <local:AnExistingControl /> (The designer may not show the control immediately.  You may have to run the application one time.)
  5. 5. If you add an x:Name attribute to the control in the .xaml, you can reference it in the .cs file.

Scenario 3: Using an externally referenced control (.dll)

User controls may be supplied in .dll form.  This is how you will get third party controls, most likely.

  1. 1. Project > Add Reference…
  2. 2. Browse to the .dll to be used and add it.
  3. 3. In the .xaml file for the application that is going to use the control, add a reference to the namespace of the control and to its assembly like this: <xmlns:local3=”clr-namespace:Microsoft.Samples.CustomControls;assembly=ColorPicker” /> Both of these items will have to be provided in order to use the control.
  4. 4. Refer to the UserControl in your xaml file with the local tag: <local:ColorThumb />
  5. 5. If you add an x:Name attribute to the control in the .xaml, you can reference it in the .cs file.
Next Page »

Create a free website or blog at WordPress.com.
Entries and comments feeds.