Cin-Day Nerd Dinner

March 15th, 2009 by ryan 1 comment »

I’m jumping on the bandwagon and you’re all invited to follow.  I’ve scheduled a Nerd Dinner at Dewey’s Pizza in West Chester on April 2nd.  It’s just off the Tylersville exit on I75. 

I’ll have both the Dayton and Cincinnati User Groups announce the event at their upcoming meetings.  Please try to RSVP so I can warn Dewey’s of the wild crowd.

Scaling ItemsControl Items for Explicit Visible Items in WPF

March 12th, 2009 by ryan No comments »

Another part of the overall solution we were trying to come up with in conjunction my previous post on Scrolling Multiple Content Areas, we also needed to come up with a way to only show X number of items in the visible region of an ItemsControl wrapped in a ScrollViewer.  This was more tricky than I had initially anticipated, but the solution seems to work for us and its got relatively few moving parts. 

The end result of the concept can be visualize in this Xbap example.  By moving the slider at the bottom, you effectively change the width of the ItemsControl containing the colored Ellipses.  In order to do this as a reflection of the number of items contained within, you need another IMultiValueConverter.

Here is the meat of the code for the RelativeSizeConverter I came up with:

public class RelativeSizeConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if( values.Length != 3 )
            throw new InvalidOperationException("Don't do that!");

        double containerSize = System.Convert.ToDouble(values[0]);
        int totalItems = System.Convert.ToInt32(values[1]);
        int visibleItems = System.Convert.ToInt32(values[2]);

        var visibleSubgroupSize = containerSize / visibleItems;

        return totalItems * visibleSubgroupSize;
    }
}

Basically we figure out how wide things would be if we only had the visible items and then we apply that to all the items return.  In order for this to work, there cannot be any sizing between the ItemsControl and the ScrollViewer, but its a small price to pay.  That would look odd any way in my opinion, but maybe I am simply justifying the solution!

Anyways, putting this RelativeSizeConverter to use, we get:

<ScrollViewer x:Name="container" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
    <ItemsControl x:Name="itemsToScale">
        <ItemsControl.Width>
            <MultiBinding Converter="{StaticResource sizeConverter}">
                <Binding ElementName="container" Path="ActualWidth" />
                <Binding ElementName="itemsToScale" Path="Items.Count" />
                <Binding ElementName="scaleSize" Path="Value" />
            </MultiBinding>
        </ItemsControl.Width>
    </ItemsControl>
</ScrollViewer>

<Slider x:Name="scaleSize" Width="100" HorizontalAlignment="Center"
        Minimum="2" Maximum="{Binding ElementName=itemsToScale, Path=Items.Count}"
        Value="{Binding ElementName=itemsToScale, Path=Items.Count, Mode=OneWay}"
        IsSnapToTickEnabled="True" TickFrequency="1" />

Notice we use the ScrollViewer’s ActualWidth as our “containerSize”.  The ItemsControl itself has the “totalItems” count, and finally we are using a Slider with the name “scaleSize” to adjust the “visibleItems” count.

Code for the Xbap sample at the top can be downloaded here.

Scrolling Multiple Content Areas with a single ScrollBar in WPF

March 12th, 2009 by ryan No comments »

I struggled to solve a UI dilemma while at my current client.  For various reasons, we came across a situation in which we needed to scroll two areas of the view based on a single Scrollbar.  You can see what we were attempting and finally achieved here.

The end result is smooth, yet not quite intuitive so I thought I would share the results and steps taken.  The idea is to use a surrogate ScrollViewer as the source for the offset of a TranslateTransform being applied to content within a seperate ScrollViewer.

Unfortunately, the offset values exposed by the ScrollViewer are both readonly and opposite in force to which we would need to apply to the surrogate.  That is, if we scroll 20 units to the right on our ScrollViewer, we would need to offset the surrogate ScrollViewer by that amount in the opposite direction.  To resolve this problem, we use an IValueConverter to multiple the offset by –1.

Here we can see the Xaml used to layout and hookup this scenario:

<StackPanel>
    <ScrollViewer HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden">
        <Grid>
            <Grid.RenderTransform>
                <TranslateTransform X="{Binding ElementName=mainScroller, Path=HorizontalOffset, Converter={StaticResource multiplyConv}, ConverterParameter=-1}" />
            </Grid.RenderTransform>
            <!-- Content Scrolled by another goes here -->
        </Grid>
    </ScrollViewer>
    <ScrollViewer x:Name="mainScroller" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
        <!-- Content Scrolled on its own accord goes here-->
    </ScrollViewer>
</StackPanel>

You can see that we have two ScrollViewers and the one which will be controlled (versus the controller) has a container element with a TranslateTransform applied to its RenderTransform property.  This is what we will be using to move the controlled content in the opposite direction of the ScrollBar.

If you find that your content for each are not the same size, you can always use a MultiBinding to accomodate the relative scrolling distance as applied to the offset.

You can find the source to the sample Xbap here.

STUFF & FOR XML PATH

March 2nd, 2009 by ryan No comments »

On the get the job done front, my client had a question today that, while it makes me cringe a little to answer the way I did, it got him moving again.

[Thanks to Mike Levy for pointing me in the right direction]

My client has a small administrative utility that displays Things.  Things can be applied to 0 or more categories.  Looks kinda’ like this:

image

He’s using a 3rd party control for the grid itself which provides really easy filtering, but it wouldn’t work with the data structures to which he had been binding.  So he wanted to know how he could return the category listing as a delimited string directly from the T-SQL.

Here’s the gist of his schema (nothing fancy):

Schema

 

How we solved it:

SELECT Id, Name, STUFF(
            (SELECT cat.Name + ‘; ‘ AS [text()]
            FROM Category AS cat
            INNER JOIN ItemCategories AS ic ON cat.Id = ic.CategoryId
            WHERE (ic.ItemId = Item.Id) FOR XML PATH(”)
            ), 1, 0, ”
              )
FROM Item

Obviously we would like to move the UI junk out of the DB, but he can deal with that when he understands the 3rd party control a little better.  Right now, he’s giving his customers some more features.

The WPF Mindset

November 3rd, 2008 by ryan 3 comments »

WPF is awesome, but it requires the developer to make a pretty big shift in their thinking of UI.  I’ve had a hard time explaining this to people, but last week, I had an opportunity to work through an example with Steve Gentile.  That’s the basis of this walkthrough.

 

The Scenerio

Steve has an ASP.Net website he maintains called ForgottenSkies.com.  One of the pages displays a map from the game with events that were captured from the server.  You can see the ASP.Net version here.  Steve was looking to create a Silverlight version of this page.

The Wrong Mindset

The initial response from most developers would be to put an image on the “form” and then figure out a way to place some composite control or other image that would denote each event’s location.  If they had the inclination they might use the DataContext, but they likely would also iterate each Event in some collection and manually place these controls within some container.  I believe Steve was trying to place them into a really big grid with lots of Rows and Columns to represent the Latitude and Longitude of the map.

The WPF Mindset

Decomposing this scenario is vital to using WPF properly.  When it comes down to it, the map is really just a way to visualize a collection of Events. If we wanted we could easily make this a list, couldn’t we?  So lets start there:

For the purposes of this demo, the Window.DataContext is set to an instance of an AttackService, which looks like the following:

public class AttackService
{
    public ObservableCollection<Attack> Attacks { get; private set; }
    public int MapSize { get; set; }

    public AttackService()
    {
        this.MapSize = 160;
        this.Attacks = new ObservableCollection<Attack>();

        Random random = new Random();

        for(int index =0; index < 10;index++)
        {
            var attack = new Attack
            {
                Description = string.Format("Attack {0}", index),
                Latitude = random.Next(0, MapSize),
                Longitude = random.Next(0, MapSize),
                Type = (AttackType)random.Next(0, 2)
            };


            this.Attacks.Add(attack);
        }
    }
}

Our goal is to display the Attacks collection, so let’s do that:

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid>
        <ListView ItemsSource="{Binding Attacks}" />
    </Grid>
</Window>

imageWe have a ListView which has it’s ItemsSource bound to our Attacks collection.  Nothing special.  WPF doesn’t know how to display an Attack class so if we would just see a 10 instances of our class name listed.  We’ll get there though.

 

For starters, lets look at these as if they were listed in a table (or GridView). To do this, we’ll tell the ListView to use a style, attacksList.  We’ll place this style definition in our Window’s Resources collection for convenience of our demo.

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Window.Resources>
        <Style x:Key="attacksList" TargetType="ListView">
            <Setter Property="View">
                <Setter.Value>
                    <GridView>
                        <GridViewColumn DisplayMemberBinding="{Binding Description}" />
                        <GridViewColumn Header="Latitude" DisplayMemberBinding="{Binding Latitude}" />
                        <GridViewColumn Header="Longitude" DisplayMemberBinding="{Binding Longitude}" />
                    </GridView>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>

    <Grid>
        <ListView x:Name="attacksList" ItemsSource="{Binding Attacks}" Style="{StaticResource attacksList}" />
    </Grid>
</Window>

What we’ve done is given ourselves a way to set values or properties on the ListView.  imageFor the sample you see here, we set the type of View for the ListView to be a GridView. 

The Map

The ultimate visualization of this information is to display it contextually in a map.  It’s important to remember that this is still a list, we just want to visualize the list differently.  To do this we need to change our attacksListStyle.

<Style x:Key="attacksList" TargetType="ListView">
    <Setter Property="ItemsPanel">
        <Setter.Value>
            <ItemsPanelTemplate>
                <Canvas>
                    <Canvas.Background>
                        <ImageBrush ImageSource="Images\Map.jpg" />
                    </Canvas.Background>
                </Canvas>
            </ItemsPanelTemplate>
        </Setter.Value>
    </Setter>

    <Setter Property="ItemContainerStyle" Value="{StaticResource attackContainerStyle}" />
</Style>

Instead of setting the View of our ListView, we are now setting the ItemsPanel to a Canvas.  This tells the ListView to place all of the items its charged with listing into the Canvas.  We have chosen canvas, because we will want to place each item via coordinates (X/Y, Left/Type) rather than stacking, row/column, etc.  The background of our Canvas is going to be a JPG version of our map.  Backgrounds and Foregrounds are always brushes, so we are using an ImageBrush to draw our map on the Canvas background.

The second property we are setting is the ItemContainerStyle to the attackContainerStyle.  The ListView places each item into a container rather than displaying it directly.  In order to place it correctly, we need to set the Top and Left properties of this ItemContainer.

<Style x:Key="attackContainerStyle">
    <Setter Property="Canvas.Top" Value="{Binding Latitude}" />
    <Setter Property="Canvas.Left" Value="{Binding Longitude}" />
</Style>

This binds the Canvas.Top and Canvas.Left DependencyProperties to the Attack.Latitude and Attack.Longitude properties respectively.  To bring this together, we have our ListView bound to a collection of Attacks and the ItemContainer contains each Attack and has its DataContext set to that Attack it is meant to contain.

At this point we have most of what we want.  imageEach little black image you see below represents an attack.  This is done by setting the DataTemplate for the Attack type.

<DataTemplate DataType="{x:Type local:Attack}">
    <Image Source="Images\AlliedTerritory.gif" />
</DataTemplate>

The problem you will find is that if you allow the Window to be scaled beyond the size of the map size as it existed when creating the Attack Latitude and Longitude, the points on the map will not scale or move with the map.  I dealt with this by implementing an IMultiValueConverter.  I won’t go into it here as it doesn’t pertain to our Mindset discussion, but I’ve included it in the attacked source code.

Summary

If you come into WPF trying to create cool graphics or visualizations from the outset, you will miss the power and productivity of the platform.  WPF and the oft-sited Designer/Developer scenario actually thrive when you begin to simplify your application into the basics and then apply visualizations.

Get the source for this project here:  Source Code.  The Xaml for this is literally only 67 lines with spaces.  There is 1 line of custom code in code behind, and you saw the AttackService above.  It’s dead simple.

Why VMWare over Virtual PC

October 21st, 2008 by ryan No comments »

I just found the reason why I’m going to slap down almost $200 bucks for VMWare Workstation over Virtual PC: Unity.  I am using a coworkers VM to help on a project he’s been working on, but he uses VMWare and I use Virtual PC.  Instead of buy a license I’m using VMWare Player.  Well I found option under VMWare called Unity so of course I clicked it.   Well it’s possibly the coolest thing I’ve seen ever. 

Here is my desktop with VMWare running as normal:

VMWare Normal

 

and here it is with Unity:

image

All of the windows/applications that were active inside the VM are now native windows in my host.  Also, when you go down to the start button, a second Start Button with the name of the VM becomes visible that allows you to start other apps in this same mode.  I don’t care what you say, that’s just awesome.

Gates/Seinfeld Commercial

September 5th, 2008 by ryan No comments »

So everyone is hating on the new Gates/Seinfeld commercial (you can see it on Windows.com).  Maybe I like Seinfeld humor too much, but I think it’s hilarious.  It doesn’t inundate me with Windows or Vista glare, it’s not over the top, it’s just funny.  I mean, Bill Gates just wiggled his rear end on national television!

I guess I’m just easy to please.

TFS Screencasts – Part 2 – Scrum For Team System Features

September 4th, 2008 by ryan No comments »

One of the things we are using here at SDS for our TFS installation and projects is the Scrum for Team System which provides a new Sharepoint Portal layout, Reporting Services reports and graphs, Work Item Templates, and an awesome Process Guidance reference

In this screencast, I try to point out some of these features and how to get to them.  It’s short (just over 2 minutes) and I’ll dive into each as we continue our storyline.

Shoutout to Camtasia which is sooo simple to use.

TFS Screencasts – Part 1 – Create a Team Project

August 27th, 2008 by ryan No comments »

One of the projects I’m working on for my company, Strategic Data Systems, is our internal Team Foundation Server 2008 solution.  I’m working with some of the guys who head up our Agile Development Center to make sure things fit well with what they are doing.  It’s been difficult to find overlapping free time, so I have started putting together screencasts to highlight our procedures and what I consider best-practices.  We’ve published written documentation internally, but these are so much more palatable.

These are geared toward our organization in content, but should be generally relevant to anyone interested in TFS.  This particular screencast walks through creating a Team Project and specifying permissions for implementing Scrum roles.

 Direct Link

p.s This is hosted, for free (as in beer), by Silverlight Streaming Services.  It took all of 20 seconds to sign up and 5 minutes to upload the video made with Camtasia.

Outlook 2007 does the little things

August 26th, 2008 by ryan 2 comments »

People give Microsoft Outlook a lot of crap, but if you’re willing to think outside the box, you’ll realize they did all the little things that make life easy.  For instance, I rarely use the calendar popup for creating new appointments.  No, if I have a meeting next Wednesday, I type “next wed” and hit tab.  It’s at 1pm, well, type 1 and hit tab.

Done.

New Appt. Screenshot