tom beeby blogs

May 6, 2010

free data (when you need a lot of it)

Filed under: Development — tombeeby @ 12:31 am

i’ve spent a lot of time lately searching around for data sets that are sufficiently big to run search / indexing benchmarks. i’m reading up on lucene.net at the moment, and while it’s all very well to talk about lightening performance, i’m not going to believe it till i see it. finding good data is not as easy as you might think. Here are a couple of good source i’ve been using:

http://www.archive.org/details/ol_data

among other things, archive.org provides library catalogues for download in various formats (json, xml, marc). some of these are very, very big. a particularly good one i’ve used a lot is the ‘open library json dump’ – 20gigs (43,000,000+ records) of juicy data.

http://blog.stackoverflow.com/2009/06/stack-overflow-creative-commons-data-dump/

a big chunk of posts, comments, authors etc. good data and very useful for simulating real-world scenarios

May 5, 2010

otto

Filed under: Uncategorized — tombeeby @ 9:41 pm

Meet Otto @ 4 months.

July 15, 2009

Silverlight 3 Behaviors – Double click selection on a DataGrid

Filed under: Development — Tags: , , — tombeeby @ 10:51 am

If you hadn’t noticed, behaviors created in Silverlight 3 beta will be broken in Silverlight 3 release. The reason for this is that the assembly Microsoft.Expression.Interactivty.dll (that used to be found in C:\Program Files\Microsoft Expression\Blend 3\Libraries\Silverlight\v3.0) no longer exists. Instead, it’s replaced by System.Windows.Interactivity.dll (which is found in C:\Program Files\Microsoft SDKs\Expression\Blend 3\Interactivity\Libraries\Silverlight). Seems simple enough, sure, but it took a good hour (with fists clenched) for me to work this out today since I couldn’t find any docs on it at all.

So, to turn this rant into something useful, I’ll talk about a useful trigger for grabbing a double click on UIElements (such as DataGrid).

The scenario is you have a list of items displayed in a DataGrid and want to select one by double clicking it. We’ll need to code two classes: 1. a trigger that fires on double click; 2. an action that can be fired in response to the trigger (e.g. an action that executes an ICommand).

The first step, is to create the trigger .cs file. Visual Studio 2008 and Blend 3 now provide templates for Triggers, Actions & Behaviors to get you started. Here’s what the template looks like in Visual Studio:

15-07-2009 10-11-13 PM

This creates the class, adds the necessary overrides and adds a reference to System.Windows.Interactivity.dll.

Now to implement the double click trigger. There’s not a lot of mystery about how to do this, and I borrowed the logic from this useful blog post: Silverlight 3 Behaviors : Double Click Trigger – but extended it in several key areas.

Firstly, I used UIElement.Addhandler() to attach the mouse events (MouseLeftButtonDown, MouseLeftButtonUp) in order to ensure the trigger works on UIElements that mark these events handled (like Button for instance).

Secondly, I wanted to be selective and intelligent about the parameter passed in to TriggerBase.InvokeActions(). The important thing here is that, in different circumstances, I’ll want to pass in different parameters. For instance, if the control that fired the trigger is a DataGrid, I’ll want to pass in the SelectedItem; if the control is a Selector, I’ll want to pass in the SelectedItem; or if the control is something else, I may want to pass in the DataContext.

In order to be as generic and extensible as possible, I decided to build a base class that I could inherit other classes from. Here’s my implementation:

using System;
using System.Windows;
using System.Windows.Threading;
using System.Windows.Input;
using System.Windows.Interactivity;

namespace GridClicker.Behaviors
{
    public class DoubleClickTriggerBase : TriggerBase<UIElement>
    {
        private readonly DispatcherTimer _timer;

        public DoubleClickTriggerBase()
        {
            _timer = new DispatcherTimer
            {
                Interval = new TimeSpan(0, 0, 0, 0, 200)
            };
            _timer.Tick += OnTimerTick;
        }

        protected override void OnAttached()
        {
            base.OnAttached();
            AssociatedObject.AddHandler(UIElement.MouseLeftButtonDownEvent,
                                        new MouseButtonEventHandler(OnMouseAction), true);
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
            AssociatedObject.RemoveHandler(UIElement.MouseLeftButtonDownEvent,
                                           new MouseButtonEventHandler(OnMouseAction));
            if (_timer.IsEnabled)
            {
                _timer.Stop();
            }
        }

        private void OnMouseAction(object sender, MouseButtonEventArgs e)
        {
            if (!_timer.IsEnabled)
            {
                _timer.Start();
                return;
            }
            _timer.Stop();
            DoInvoke();
        }

        private void OnTimerTick(object sender, EventArgs e)
        {
            _timer.Stop();
        }

        protected virtual void DoInvoke()
        {
            InvokeActions(null);
        }
    }
}

The key thing here is the virtual DoInvoke() method that can be overridden in descendent classes if a special value need to be passed as parameter to InvokeActions().

Here’s an inherited class, DataGridDoubleClickTrigger.cs:

using System.Windows.Controls;

namespace GridClicker.Behaviors
{
    public class DataGridDoubleClickTrigger : DoubleClickTriggerBase
    {
        protected override void DoInvoke()
        {
            var dg = AssociatedObject as DataGrid;
            var o = dg == null ? null : dg.SelectedItem;
            if (o != null)
            {
                InvokeActions(o);
            }
        }
    }
}

This simply passes in the SelectedItem of the DataGrid as the InvokeAction() parameter. Of course you could make any number of classes that inherit from DoubleClickTriggerBase. I should point out that there is an assumption here that the user will double click on a row of the DataGrid and not the header, though it will not break in any case. If a user does double click on the header of the DataGrid, if the SelectedItem is not null it will be returned, otherwise nothing will happen.

Now a trigger is no good without an action to fire, so here is a very quick and simplistic action that executes an ICommand. Firstly, create the action in Visual Studio:

15-07-2009 11-27-48 PM

And here’s the implementation:

using System.Windows;
using System.Windows.Input;
using System.Windows.Interactivity;

namespace GridClicker.Behaviors
{
    public class ExecuteCommandAction : TriggerAction<FrameworkElement>
    {
        public string CommandName { get; set; }

        protected override void Invoke(object o)
        {
            if (CommandName == null) return;
            var dataContext = AssociatedObject.DataContext;
            if (dataContext == null) return;
            var command = dataContext.GetType().GetProperty(CommandName).GetValue(dataContext, null) as ICommand;
            if (command != null && command.CanExecute(o))
            {
                command.Execute(o);
            }
        }
    }
}

Even though TriggerAction is a DependencyObject, it doesn’t seem to want to let you make CommandName a DependencyProperty and bind it’s value. No idea why this is, hence the roundabout route to grab the command.

To put it altogether, here is the XAML:

<StackPanel x:Name="ContentStackPanel">

    <TextBlock x:Name="HeaderText" Style="{StaticResource HeaderTextStyle}"
                       Text="Home"/>

    <data:DataGrid ItemsSource="{Binding Categories}" IsReadOnly="True">
        <i:Interaction.Triggers>
            <b:DataGridDoubleClickTrigger>
                <b:ExecuteCommandAction CommandName="SelectCommand" />
            </b:DataGridDoubleClickTrigger>
        </i:Interaction.Triggers>
    </data:DataGrid>

    <Button Content="Double Click Button" Margin="10" VerticalAlignment="Center" HorizontalAlignment="Center">
        <i:Interaction.Triggers>
            <b:DoubleClickTriggerBase>
                <b:ExecuteCommandAction CommandName="ButtonCommand"/>
            </b:DoubleClickTriggerBase>
        </i:Interaction.Triggers>
    </Button>

</StackPanel>

Note that I also put in a Button that demonstrates that the base class – DoubleClickTriggerBase – is useful in instances where you have no need to pass a parameter to the InvokeActions().

Finally, to round things off, here is the view’s presenter:

public class HomePresenter : INotifyPropertyChanged
{
    public ICommand SelectCommand { get; private set; }
    public ICommand ButtonCommand { get; private set; }

    public HomePresenter()
    {
        SelectCommand = new DelegateCommand<object>(o =>
        {
            var cat = o as Category;
            var dw = new DetailsWindow {Width = 300.0, Height = 300.0};
            var g = dw.FindName("LayoutRoot") as Grid;
            g.Children.Add(new TextBlock()
            {
                Text = "Category Name: " + cat.CategoryName,
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center
            });
            dw.Show();
        });

        ButtonCommand = new DelegateCommand<object>(o => HtmlPage.Window.Alert("Button was double clicked!"));
    }

    public ObservableCollection<Category> Categories
    {
        get { return CategoryHelper.GetCategories(); }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

In the example I am using Prism’s DelegateCommand implementation of ICommand.

There you have it!

Older Posts »

Blog at WordPress.com.