Monthly Archives: May 2012

Memorial day reminds us how to treat people

20120528-105656.jpg

Yesterday, I took Ben to the flag display at 95th & Renner. I explained to him how sometimes there are people that want to take away our freedom and that sometimes people have to go fight for our freedom. I went on to tell him that some of those people die during the fight and the flags are there for us to remember them and the great sacrifice they made for us. He didn’t ask any questions and he didn’t totally understand it, but he knew the flags were important.

As a country, we all have different opinions on how wars should or should not be executed. We all have different thresholds for when war is a proper response to an action by a different country. Many feel that it is unnecessary as a whole and that conflicts can be resolved without the loss of life.

However you feel, even those most against war, we all rally around and support our troops. These folks are willing to die for what they believe in, and even if their beliefs do not line up exactly with ours, we support them with everything we have.

How nice it will be to someday live in a world where everybody can have the support that American soldiers receive. Where regardless of your race or beliefs you are treated with the respect you deserve for just being a person.

I support our troops and will teach my kids to do the same. I will also teach them to support human beings. As Christians, we are told to love everybody, not just those who believe in Jesus.

How to exclude trips from reports in ParaPlan

In ParaPlan, trips are performed by a specific program. These programs are typically a funding source of some sort. For example Kroger will pay our clients to drive senior citizens or handicapped people to the store then back home. Medicaid is another common funder.

Often when running reports, users like to see everything except a certain program. We use a minus symbol as a reserved operator to perform that task. So if we wanted a report that showed all the trips in April 2012 except those done under the “grocery” program, our report window would look like this:

How ParaPlan handles changed LogistiCare trips


ParaPlan by EnGraph Software can import trips provided by the brokerage company LogistiCare. They provide a CSV file containing trips that our clients are contracted to perform, and we import them into ParaPlan. It’s a really neat system and it allows companies to provide non-emergency medical transportation to regions that might not otherwise have these services available.

Invariably, trips change before the execution date. Sometimes, they are updated with a different destination, other times, they are completely cancelled. To allow for these situations to be properly handled, LogistiCare included a TripStatus field. This field will be either NEW, MODIFIED or CANCELED.

ParaPlan will handle each case differently:

NEW
A new trip is inserted into ParaPlan.

MODIFIED
ParaPlan looks up the existing trip using the LogistiCareID. If it finds it, it updates the trip and unschedules it if it is already assigned to a Route. If it cannot find the existing trip, it generates a new one and makes it available for scheduling.

CANCELED
ParaPlan looks up the existing trip using the LogistiCareID. If it finds it, it cancels the trip and removes any Route assignment. If it cannot find the existing trip, it creates a new trip with the provided information, then cancels it.

 

Display item count in WPF ListBox and reorder using ButtonSpinner

I ran into a situation the other day where I needed to be able to display Trips to a user in the order that they were going to be executed and have them be able to move them up and down the list. I liked how Netflix tackled the issue, but wanted to give the user a little more control.

As it were, I could not find a decent solution to the problem. Google and StackOverflow mostly turned up hacks that were sure to fall apart. After much trial and error, I was able to use an IMultiValueConverter that accepted a ListBox and an item in the ListBox. From there, I could do an IndexOf and return that value back to a TextBlock for display.

The second issue of reordering I solved using the ButtonSpinner in the WPF Extended Toolkit. I had to trick it because I wanted the “down” spinner to move the item to the next higher index and the “up” spin to actually move the item down the list (from an index’s point of view). This functionality requires that the binding list is an ObservableCollection that exposes a Move event and also fires all the INotifyPropertyChanged events that WPF uses for UI refreshing.

Note that the ButtonSpinner is a content control and looks a little ugly when used by itself. The trick is to set the Padding to zero.

So now we have a ListBox that displays the current order of the items and allows the user to move the items up and down the list (which changes the order label) using the ButtonSpinners.

WPF ListBox

In my production code, I actually hide the ButtonSpinners until the user mouses over them, but I didn’t want to clutter the code. I’ll save that for a later post.

The key parts of the code are listed below. The entire project can be downloaded here. Remember to unblock after downloading.

The Converter that takes a ListBox and an item in the ListBox:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;
using System.Windows.Controls;

namespace ReorderingListBox
{
    public class ListBoxIndexConverter : IMultiValueConverter
    {
        #region IMultiValueConverter Members

        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            var item = values[0];

            if (item == null)
            {
                return null;
            }

            var lb = values[1] as ListBox;
            if (lb == null)
            {
                return null;
            }

            //make it 1 based
            var rv = lb.Items.IndexOf(item) + 1;

            //very important because control
            //we are binding to is expecting a string
            return rv.ToString();
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}

The XAML with the ListBox and ButtonSpinner:

<Window x:Class="ReorderingListBox.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:converters="clr-namespace:ReorderingListBox"
        xmlns:wpf="http://schemas.xceed.com/wpf/xaml/toolkit"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.Resources>
            <!--reference to our multi converter-->
            <converters:ListBoxIndexConverter x:Key="listBoxIndexConverter" />
            <!--this defines how each item in the listbox will layout-->
            <DataTemplate x:Key="placesTemplate">
                <StackPanel Orientation="Horizontal">
                    <!--shows the current order in the listbox-->
                    <TextBlock Width="15" Name="textBlockOrder">
                        <TextBlock.Text>
                            <!--this is a multibinding, we are into the converter-->
                            <!--the current object that we are bound to (a place)-->
                            <!--and the listbox that it lives in-->
                            <MultiBinding Converter="{StaticResource listBoxIndexConverter}">
                                <Binding />
                                <Binding ElementName="listBox" />
                            </MultiBinding>
                        </TextBlock.Text>
                    </TextBlock>
                    <!--control from http://wpftoolkit.codeplex.com/-->
                    <!--note the padding has to be explicitly set-->
                    <!--otherwise it looks horrible more info about that-->
                    <!--http://timhibbard.com/blog/2012/05/08/default-padding-issue-with-buttonspinner/-->
                    <wpf:ButtonSpinner Padding="0"
                                       Margin="3"
                                       Spin="spinner_Spin" />
                    <TextBlock Text="{Binding}" />
                </StackPanel>
            </DataTemplate>
        </Grid.Resources>
        <ListBox Name="listBox"
                 ItemTemplate="{StaticResource placesTemplate}" />

    </Grid>
</Window>

The code behind that constructs the list that binds to the ListBox and the event that listens to the ButtonSpinner.Spin event:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using Xceed.Wpf.Toolkit;

namespace ReorderingListBox
{
    ///
<summary> /// Interaction logic for MainWindow.xaml
 /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            //construct our backing list to bind to
            var placesIWantToLive = new ObservableCollection
            {
                "Minneapolis",
                "San Diego",
                "Charleston",
                "Philadelphia"
            };

            this.listBox.ItemsSource = placesIWantToLive;
        }

        private void spinner_Spin(object sender, SpinEventArgs e)
        {
            ButtonSpinner spinner = sender as ButtonSpinner;
            //this will find the textblock in the same listbox item
            TextBlock textOrder = spinner.FindName("textBlockOrder") as TextBlock;
            ObservableCollection places = this.listBox.ItemsSource as ObservableCollection;
            //back to zero based - remember we store the current index in this textblock
            int current = int.Parse(textOrder.Text) - 1;
            int destination = 0;
            switch (e.Direction)
            {
                case SpinDirection.Decrease:
                    //because we want it to go "down" the list
                    destination = current + 1;
                    break;
                case SpinDirection.Increase:
                    //because we want it to go "up" the list
                    destination = current - 1;
                    break;
                default:
                    //we'll never hit here, but else statements are ugly
                    //and not as obvious as switch statements
                    break;
            }
            if (destination < 0)             
            {                 
                 //can't more the first item any higher so exit                 
                 return;             
            }             
            if (destination > places.Count + 1)
            {
                //can't move it any more down so exit
                return;
            }

            //this is where the magic happens
            places.Move(current, destination);
            //this refreshes the textblocks holding the index
            this.listBox.Items.Refresh();
            //highlight the item that was moved so it is obvious to the user
            this.listBox.SelectedIndex = destination;
        }
    }
}

Default Padding issue with ButtonSpinner

The Extended WPF Toolkit plugs a large hole in the WPF framework and we use it extensively at EnGraph. Every now and then, you find a little odd thing. I ran into an issue this morning where the ButtonSpinner looked very odd if you didn’t specify any child content to be inside the spinner.

It’s not really a bug because the control was designed to have content, but I needed it to be by itself.

<wpf:ButtonSpinner />

It produced that ugly border to the left of the control where the content would be. Digging through the properties, I found that the default value for Padding was set to 2. So I changed that to be 0 and now we get the excepted result:

<wpf:ButtonSpinner Padding="0" />


Perfect.

Buying his own toy

Last week, Ben won $5.00 from our neighbor in a game of checkers. While I don’t encourage gambling (from a statistical, not philosophical point of view), I do want to stress the value of money early with our kids, so we took that money to the store tonight so Ben could buy a toy with his money. He initially picked out a red race car. After some prodding, he decided it was the one he wanted over all the other toys.

With all the pride a 3 year old can muster, he handed the check-out lady the item and his five dollar bill. She rang him up, handed him his receipt and his change. He was especially tickled with getting the receipt. I guess because I usually take the receipt and put it in my wallet. This time, he was getting something back and he needed to keep it.

I’m not sure any life lessons of the value of the dollar were passed on tonight, but it was neat to see him as a participant in the lifecycle of commerce.

The spoils:

20120507-202039.jpg

20120507-202053.jpg