From the Department of Uselessness

How many comments are there when one of the comments has been removed?

In this instance, apparently the count was 2.

SNAGHTML1ed5e447

If a second comment was not a reply to a first comment (which from the structure of the UI, I don’t believe it was), why indicate “this comment has been removed” and include it in the count? 

Aye. Programmers. Can’t live with them. Can’t live without them.

On Twitter, follow wiredprairie.

I’ve been using twitter a bit more recently, and posting less to my blog. I just haven’t been compelled to write much. I’ve got a few things queued up though and as soon as I finish the details, I’ll get some new posts up.

But, in the mean time, feel free to follow me on twitter: wiredprairie. Maybe I’ll see you on twitter!

I promise not to tweet too much. Certainly not too much about bowel movements or the details of the meals that preceded them. Smile

Windows Phone 7 Marketplace: Ditch the Annual Fee for Free App Developers!

Dear Microsoft,

A few facts:

  • I’m a competent Silverlight developer. I’ve even dabbled in XNA.
  • I’m an owner of a iPhone 3GS.
  • I would like a new phone.
  • I’d like to buy a phone powered by the Windows Phone 7 OS when it’s made available.
  • I’d like to make some free applications for my phone and others to use. A few for hobbies (like photography), and a few utilities for myself for work.
  • I don’t however want to spend $99 a year for the privilege of doing so.

Why not open it up for people like myself?

Here’s a few alternatives:

  • Make it free for those who make only free applications
  • Make it free for those who agree to include a Bing-Ad placement component in the application, in a prominent position.
  • Make it free for those who buy a copy of Visual Studio 2010 and Blend (like myself – I don’t use the Express editions).
  • Make it free so that there’s no barrier to entry – that people and companies don’t need to worry about the extra fee – just jump on the Windows Phone 7 bandwagon.

Without this change, I probably won’t buy a Windows Phone 7, and will start building more HTML 5 web apps, that will work just fine on my iPhone 3GS (powered by iOS4). Sad smile

Are DIVs really better than TABLEs?

The screen shot at the end of this post shows some of the HTML behind the main gmail.com page. I never looked before, so it came as a shock to me how many DIVs were used to construct the page. There are more than are visible as the document scrolled and I had only opened a particular sub-branch of the page.

According to the Chrome Developer Tools, there are 590 DIVs (in my inbox)!

image

So, are DIVs really better than TABLEs? Tables would be used to present data, and not just for layout in the case of Gmail.

Gmail has 11 TABLE elements on the page:

image

What would you do if you were creating a messaging application like Gmail?

image

How to bind ListBoxItem.IsSelected to a bound item in Silverlight 4.0

This technique requires the Blend 4.0 SDK (which is included in Blend 4.0 and is also available as a free download.

Someone on StackOverflow asked how to bind a collection of items to a ListBox in Silverlight where the IsSelected property of the ListBoxItem is bound to an IsSelected property of the data item.

WPF has the native ability within a style to set the a style’s setter property IsSelected to a value of the two way binding to an IsSelected Property. Slick.

Silverlight, has no such thing unfortunately.

But, there’s a work around that isn’t too awful. Seriously.

image

What I’ve done is mapped the look and feel of the ListBoxItem selection to the DataTemplate for the item and removed it from the standard ListBoxItemContainer style:

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:TestSilverlightTodoListItem" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" x:Class="TestSilverlightTodoListItem.MainPage"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <UserControl.Resources>        

        <local:PeopleList x:Key="PeopleListDataSource" d:IsDataSource="True"/>        

        <Style x:Key="ListBoxItemStyle1" TargetType="ListBoxItem">
            <Setter Property="Padding" Value="3"/>
            <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
            <Setter Property="VerticalContentAlignment" Value="Top"/>
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="TabNavigation" Value="Local"/>            
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ListBoxItem">
                        <Grid Background="{TemplateBinding Background}">
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="CommonStates">
                                    <VisualState x:Name="Normal"/>
                                    <VisualState x:Name="MouseOver">
                                    </VisualState>
                                    <VisualState x:Name="Disabled">
                                    </VisualState>
                                </VisualStateGroup>
                                <VisualStateGroup x:Name="SelectionStates">
                                    <VisualState x:Name="Unselected"/>
                                    <VisualState x:Name="Selected">
                                    </VisualState>
                                </VisualStateGroup>
                                <VisualStateGroup x:Name="FocusStates">
                                    <VisualState x:Name="Focused">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetProperty="Visibility" Storyboard.TargetName="FocusVisualElement">
                                                <DiscreteObjectKeyFrame KeyTime="0">
                                                    <DiscreteObjectKeyFrame.Value>
                                                        <Visibility>Visible</Visibility>
                                                    </DiscreteObjectKeyFrame.Value>
                                                </DiscreteObjectKeyFrame>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Unfocused"/>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}"/>
                            <Rectangle x:Name="FocusVisualElement" RadiusY="1" RadiusX="1" Stroke="#FF6DBDD1" StrokeThickness="1" Visibility="Collapsed"/>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <DataTemplate x:Key="PersonTemplate">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <i:Interaction.Behaviors>
                    <ei:DataStateBehavior Binding="{Binding IsSelected, Mode=TwoWay}" Value="True" TrueState="Selected" FalseState="Unselected"/>                    
                </i:Interaction.Behaviors>
                <VisualStateManager.VisualStateGroups>
                    <VisualStateGroup x:Name="Selection">
                        <VisualStateGroup.Transitions>
                            <VisualTransition GeneratedDuration="0:0:0.25"/>
                        </VisualStateGroup.Transitions>
                        <VisualState x:Name="Selected">
                            <Storyboard>
                                <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="fillColor" d:IsOptimized="True"/>
                                <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="fillColor2" d:IsOptimized="True"/>
                            </Storyboard>
                        </VisualState>
                        <VisualState x:Name="Unselected"/>
                    </VisualStateGroup>
                </VisualStateManager.VisualStateGroups>
                <VisualStateManager.CustomVisualStateManager>
                    <ei:ExtendedVisualStateManager/>
                </VisualStateManager.CustomVisualStateManager>
                <Rectangle x:Name="fillColor" Fill="#FFBADDE9" IsHitTestVisible="False" Opacity="0" RadiusY="1" RadiusX="1" Grid.ColumnSpan="2"/>
                <Rectangle x:Name="fillColor2" Fill="#FFBADDE9" IsHitTestVisible="False" Opacity="0" RadiusY="1" RadiusX="1" Grid.ColumnSpan="2"/>
                <CheckBox IsChecked="{Binding IsSelected, Mode=TwoWay}" Grid.ColumnSpan="1"/>
                <TextBlock x:Name="textBlock" Text="{Binding Name}" Grid.Column="1"/>
            </Grid>
        </DataTemplate>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="White" DataContext="{Binding Source={StaticResource PeopleListDataSource}}" >
        <ListBox x:Name="myList" ItemsSource="{Binding}" 
            ItemContainerStyle="{StaticResource ListBoxItemStyle1}" 
            ItemTemplate="{StaticResource PersonTemplate}" 
            SelectionMode="Multiple" />
    </Grid>
</UserControl>

The real magic is using the DataStateBehavior (which is included in the Blend 4.0 SDK):

<i:Interaction.Behaviors>
    <ei:DataStateBehavior Binding="{Binding IsSelected, Mode=TwoWay}" Value="True" TrueState="Selected" FalseState="Unselected"/>                    
</i:Interaction.Behaviors>

This ties the IsSelected property of the Person class (see below) to two VisualStates that I defined in the DataTemplate. A “Selected” and an “Unselected” state.

I grabbed the rectangle from the standard ListBoxItem container template template.

In the code behind, I wired up the selection changed event:

public partial class MainPage : UserControl
{
    private PeopleList _items = new PeopleList();

    public MainPage()
    {
        this.DataContext = _items;
        InitializeComponent();
        myList.SelectionChanged += new SelectionChangedEventHandler(myList_SelectionChanged); 
    }

    void myList_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        // these both just need to toggle 
        foreach (object o in e.AddedItems)
        {
            Person p = o as Person;
            p.IsSelected = !p.IsSelected;
        }
        foreach (object o in e.RemovedItems)
        {
            Person p = o as Person;
            p.IsSelected = !p.IsSelected;
        }
    }

    void myList_KeyUp(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Space  )
        {
            if (e.OriginalSource is ListBoxItem)
            {
                Person p = (e.OriginalSource as ListBoxItem).DataContext as Person;
                if (p != null)
                {
                    p.IsSelected = !p.IsSelected;
                }
            }
        }
    }
}

The selection changed toggles the state of each item. Without doing that, the selection doesn’t behave correctly. The SelectedItems list on the listbox no longer reflects the reality of the bound data items – but that shouldn’t matter in this case as the property of the item reflects the real state accurately.

For testing:

public class PeopleList : ObservableCollection<Person>
{
    public PeopleList()
    {
      this.Add( new Person { Name = "Henry", IsSelected = true });
      this.Add(new Person { Name = "Bonnie", IsSelected = true });
      this.Add( new Person { Name = "Clyde", IsSelected = false });
      this.Add( new Person { Name = "Ervin", IsSelected = false });
      this.Add( new Person { Name = "Timmy", IsSelected = true });
      this.Add( new Person { Name = "Jane", IsSelected = true });

    }
}

And:

public class Person : INotifyPropertyChanged
{
    private bool _isSelected;
    private string _name;

    public string Name
    {
        get { return _name; }
        set
        {
            if (value != _name)
            {
                _name = value;
                RaisePropertyChanged("Name");
            }
        }
    }

    public bool IsSelected
    {
        get { return _isSelected; }
        set
        {
            if (_isSelected != value)
            {
                _isSelected = value;
                RaisePropertyChanged("IsSelected");
            }
        }
    }

    private void RaisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

    }

    public event PropertyChangedEventHandler PropertyChanged;
}