November 2007 - Posts

Sorting the standard ListView control

I've added an example of how to bind to a ListView control in my binding presentation.

While implementing this, it occurred to me that a common scenario would require to be able to sort a column by clicking on the header! While this is a common requirement, ListView doesn't support this by default. There is no event in the ListView class that traps events when the user clicked on the header! Well, this can easily be fixed by using routed events. To add a handler for when the user clicks on the header, just add the following line of code:

ListView1.AddHandler(GridViewColumnHeader.ClickEvent, new RoutedEventHandler(OnHeaderClicked));

Now you should start getting events whenever the user clicks on the header of the ListView. The next step is to sort the list once your received the event. Here is the code snipped:

private void OnHeaderClicked(object sender, RoutedEventArgs e)
{
    GridViewColumnHeader header = e.OriginalSource as GridViewColumnHeader;
    ListView source = e.Source as ListView;
    try
    {
        ICollectionView dataView = CollectionViewSource.GetDefaultView(source.ItemsSource);
        dataView.SortDescriptions.Clear();
        SortDescription description = new SortDescription(header.Content.ToString(), ListSortDirection.Ascending);
        dataView.SortDescriptions.Add(description);
        dataView.Refresh();
    }
    catch (Exception)
    {
    }
}

That wasn't to hard now was it? This code has 1 major flaw thou... It looks at the header.Content.ToString() to determine what property name to sort by!!! What if the header used the more understandable "Phone (Home)" and not the property name "PhoneHome". Well, in my current design only sorting by name and surname will work because these friendly names map directly to the property names! If you need to be able to sort by other headings that do not equal the property names, you sould think about implementing a custom GridViewColumn! There are 2 great resources available to see how to do this:

http://blogs.interknowlogy.com/joelrumerman/archive/2007/04/03/12497.aspx

or download Family.Show by Vertigo from codeplex. Thy implemented a SortListViewColumn and SortListView. Just replace your normal GridViewColumn and ListView with there stuff and you magically have sorting enabled!!!

Posted by rudi | 1 comment(s)
Filed under: ,

Data Binding Explained!!!

As part of our company's internal training programs, I was required to give a presentation about data binding. The presentation is written only in WPF and demos most of the concepts of data binding including: Binding to Elements, XML and CLR Objects. More advanced features like value converters, views and the data context are also demoded!

Each demo has code snippets visually available! The application is available as a clickOnce application here

Posted by rudi | 2 comment(s)
Filed under:

Hey! Designers! Leave them Bindings alone!

Little dramatic I know, but I found an excellent forum post about data bind. The post looks at data bind from multiple views and there are some excellent points raised here.

The basic question is that if the assumption is true that XAML is more for the designer and C# or VB is more for the programmer, then why is binding easier in XAML than in C#? Should the binding and hooking up of event handlers not be left to the developer and NOT to the designer?

http://forums.microsoft.com/msdn/showpost.aspx?postid=2359099&siteid=1&sb=0&d=1&at=7&ft=11&tf=0&pageid=0

 

 

 

Posted by rudi | 1 comment(s)
Filed under:

WPF Bootcamp

What is the best way to learn more about WPF? Search on the web? Reading books? Well, Microsoft hosted a bootcamp and recorded all the content. This is now downloadable for free!!! Over 20 hour's worth of content all about WPF. I already downloaded and watched most of these videos and they are well worth the download! Here is the link:

http://www.visitmix.com/university/wpf/wpfbootcamp.htm

Videos include keynote by Ian Ellison-Taylor and great presentations by Rob Relyea, Ian Griffiths, Beatriz de Oliveira Costa, Tim Sneath and much more...

If you don't want the bandwidth hit, drop me an email and I can write it to disc for you. I will also take some to the Facebook garage tomorrow and the next SA Developer meeting...

 

Posted by rudi | 3 comment(s)
Filed under:

WCF + LINQ?

In an n-tier application, is it possible to send objects created by LINQ between layers? More specifically, is it possible to send LINQ object via a WCF service?

Well, the short answer is yes. I will first show you how to do it then I will try and discuss why I want to do it and try and list the pros and cons!

I am only going to demo how to do this using the designer interface (LINQ to SQL - DBML) but it is also possible to use it in SQLMetal.exe!

I opened an existing project, clicked on the design surface and opened the properties window.  Change the Serialization mode to Unidirectional

This basically indicates that id/idrefs are not to be used and thus make the objects serializable!

Now this object can be passed to and from a standard WCF service.

[ServiceContract]
public interface IContractService
{
    [OperationContract]
    Impilo.DataAccess.LinqToSQL.Contact GetContact(int ContactID);

    [OperationContract]
    Impilo.DataAccess.LinqToSQL.Address GetAddress(int AddressID);
}

OK, this all looks great, but what is the catch? Well, my first issue with this is that it looks like I might have circular references and this kind of breaks my serialization. Let me explain, if I have a Customer and Invoice object, then LINQ tries to make it easy to ask any customer for its invoices and to see who an invoice clients are. This creates a circular reference. Customer links to invoice who links back to customer.  It is possible to specify in LINQ that I don't want this to happen, but this is an "out-of-the-box" feature!

The second issue had me bug checking for a while. When I started, I implemented my service as follows:

public Impilo.DataAccess.LinqToSQL.Address GetAddress(int AddressID)
{
    Console.WriteLine("Request: Get Address for " + AddressID);

    using (ImpiloDataContext dataContext = new ImpiloDataContext(".\\SQLEXPRESS"))
    {
        var ch = (from c in dataContext.Addresses
                  where c.AddressID == AddressID
                  select c).First();

        return ch;
    }
}

This all looked fine and it worked for the first Operation Contract but as soon as I implemented my second operation contract, I started getting errors. I can't explain this yet but here is my solution:

public class ContractService : IContractService
{
    private ImpiloDataContext dataContext = new ImpiloDataContext(".\\SQLEXPRESS"); 

    public Impilo.DataAccess.LinqToSQL.Address GetAddress(int AddressID)
    {
        Console.WriteLine("Request: Get Address for " + AddressID);

        var ch = (from c in dataContext.Addresses
                  where c.AddressID == AddressID
                  select c).First();

        return ch;
    }
}

Next, let's discuss the WHY. Everybody would probably have different opinions about this but I will only discuss why I would want to do this. Please note that I am by no means an expert on n-tier applications and would love to hear your opinions about this. The first thing to note is that I only serialize the data contract and NEVER the data context (I don't even think it is possible to serialize it). Any other layer will then not be possible to do anything with this object in a way I have not intended it because it will always need the data context to do anything useful. I also believe that a LINQ object serialized is "cheaper" than coping from a LINQ object to a business entity. You lose a little flexibility in the fact that you are now tied to LINQ but for my specific need, I know I will only use MS SQL and LINQ.

The biggest plus of using this is that I get INotifyPropertyChanging and INotifyPropertyChanged for free! This simplifies binding.

Like I said earlier, I am no expert and would love to hear your opinions about this. Currently I don't think there are any best practices yet on how to use LINQ and WCF together...

 

Posted by rudi | 3 comment(s)
Filed under: ,

Subtle background effect using Radial Gradient Brush in WPF

Recently I needed to create a background for a WPF application that looks like it has a lens flare in the bottom right hand corner. This is a relatively simple effect that can create great looking backgrounds. It is similar to the background effect used in the XBOX 360.

When I started, I first tried to do this in blend. Blend has no easy method of changing the center of a Radial Gradient Brush so I flipped back to VS (For the Intelli-sense) and started testing...

RadialGradientBush basically has 4 properties you need to use:

Center

The Center property is of the type Point and has a default value of (0.5,0.5)

RadiusX

The RadiusX is the horizontal radii and has a default value of 0.5

RadiusY

The RadiusY is the vertical radii and has a default value of 0.5

GradientOrigin

The GradientOrigin is similar to the Center also of the type Point and has a default value of (0.5,0.5)

I changed the Center and GradientOrigin both to (0.85,0.85) and the RadiusX and RadiusY to 0.75 and this is the effect I ended up with:

 

Also play around with the colors and the opacity of each gradient stop to customize the effect even more!

A great way to actually test these type of features is to bind each value you might need to change to a slider. Here is the XAML

<Window x:Class="Background.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:src="clr-namespace:Background"
    Title="Radial gradient background" Height="600" Width="800">
    <Window.Resources>
        <src:PointConverter x:Key="conv" />
    </Window.Resources>
    <Grid>
        <Grid.Background>
            <RadialGradientBrush 
                Center="{Binding ElementName=Center, Path=Value, Converter={StaticResource conv} }" 
                RadiusX="{Binding ElementName=RadiusX, Path=Value}" 
                RadiusY="{Binding ElementName=RadiusY, Path=Value}" 
                GradientOrigin="{Binding ElementName=GradientOrigin, Path=Value, Converter={StaticResource conv} }"> 
                    <GradientStop Color="#FAFAFAFA" Offset="0"/>
                    <GradientStop Color="#B2171F6E" Offset="0.971"/>
            </RadialGradientBrush>
        </Grid.Background>
        <StackPanel>
            <TextBlock Text="Center" />
            <Slider x:Name="Center" Minimum="0" Maximum="1" Value="0.5" Width="300" HorizontalAlignment="Left" />
            <TextBlock Text="RadiusX" />
            <Slider x:Name="RadiusX" Minimum="0" Maximum="1" Value="0.5" Width="300" HorizontalAlignment="Left"/>
            <TextBlock Text="RadiusY" />
            <Slider x:Name="RadiusY" Minimum="0" Maximum="1" Value="0.5" Width="300" HorizontalAlignment="Left" />
            <TextBlock Text="GradientOrigin" />
            <Slider x:Name="GradientOrigin" Minimum="0" Maximum="1" Value="0.5" Width="300" HorizontalAlignment="Left"/>
        </StackPanel>
    </Grid>
</Window>

I just created a convertor that takes a double value (default of the slider) and convert it to a Point value. I make X and Y of the point equal but it is also possible to bind a slider to the X and another to the Y.

    public class PointConverter : IValueConverter
    {
        public object Convert(object value, Type typeTarget, object param, CultureInfo culture)
        {
            return new Point((double) value, (double) value);
        }
        public object ConvertBack(object value, Type typeTarget, object param, CultureInfo culture)
        {
            Point p = (Point) value;
            return p.X;
        }
    }

And now you can play with your exact settings for fine-tuning the effect

Posted by rudi | 1 comment(s)
Filed under:

IEI Conference

The company that I work for is presenting a conference on Wednesday about industrial computing. One of our biggest suppliers (http://www.ieiworld.com/) will be visiting us and they are giving some talks about new products they have. Topics to be covered include Single Board Computers, Panel PCs, Windows XPe, Video Capture Cards and more...

If you have an interested in any of these products, please send me an email and I can send you an invite. I will also be presenting an introduction into XPE and a guide on how to select the correct video capture card for your solution

 

 

Posted by rudi | 2 comment(s)
Filed under: ,

Spell check in WPF Text Controls

A very nice new feature supported by all WPF text controls is spellchecking. To enable spellchecking in your controls, just add the following:

<TextBox SpellCheck.IsEnabled="True" />

Once the spellchecking is enabled, a wavy line will appear under every misspelled word. Right-clicking on this word will display a context sensitive help menu with spelling suggestions (like Word)

 

Posted by rudi | 4 comment(s)
Filed under: