Archives for: March 2007

Pages: 1 2 >>

31/03/07

Permalink 09:57:50 pm
Categories: General

WPF: IntSequence helper class updated, including dependency properties

This struck me right after my recent post about binding to arbitrary sequences: my helper class was implemented with traditional .NET properties, which isn't optimal for use with WPF. One thing specifically isn't good for my purpose, which is the fact that a "normal" property can't be the target of WPF data binding. Like in this case:

<Window.Resources>
	<engine:Grid x:Key="gameGrid" />
	<helpers:IntSequence x:Key="rowDummyList" EndVal="{Binding Source={StaticResource gameGrid}, Path=RowCount}" />
</Window.Resources>

In this case I'm trying to bind the EndVal of the sequence to a value obtained from a different object, and that didn't work using the standard properties. So I have created an updated version of the IntSequence class, which uses dependency properties to make this kind of binding possible. Here it is:

public class IntSequence : DependencyObject, IEnumerable<int> {
	public static readonly DependencyProperty StartValProperty;
	public static readonly DependencyProperty EndValProperty;

	static IntSequence( ) {
		StartValProperty = DependencyProperty.Register("StartVal",
			typeof(int), typeof(IntSequence), new PropertyMetadata(1));
		EndValProperty = DependencyProperty.Register("EndVal",
			typeof(int), typeof(IntSequence), new PropertyMetadata(10));
	}

	public int StartVal {
		get { return (int) GetValue(StartValProperty); }
		set { SetValue(StartValProperty, value); }
	}

	public int EndVal {
		get { return (int) GetValue(EndValProperty); }
		set { SetValue(EndValProperty, value); }
	}

	IEnumerator<int> IEnumerable<int>.GetEnumerator( ) {
		for (int val = StartVal; val <= EndVal; val++)
			yield return val;
	}

	IEnumerator IEnumerable.GetEnumerator( ) {
		foreach (int item in this)
			yield return item;
	}
}
Permalink 09:20:18 pm
Categories: General

WPF: Binding to a sequence

In certain contexts I have always found it useful to bind to a sequence of numbers, or sometimes even just a dummy collection with a certain number of elements. It's like a for-loop, just for data binding. I've found three good ways of doing that in XAML, as the following two source code snippets show:

<Window x:Class="WPFSequenceBinding.Window1"
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	xmlns:sys="clr-namespace:System;assembly=mscorlib"
	xmlns:local="clr-namespace:WPFSequenceBinding"
	Title="WPFSequenceBinding" Height="300" Width="300">
	<Window.Resources>
		<x:Array x:Key="list1" Type="{x:Type sys:Int32}">
			<sys:Int32>1</sys:Int32>
			<sys:Int32>2</sys:Int32>
			<sys:Int32>3</sys:Int32>
			<sys:Int32>4</sys:Int32>
			<sys:Int32>5</sys:Int32>
		</x:Array>
		<ObjectDataProvider x:Key="list2" ObjectType="{x:Type sys:Array}" MethodName="CreateInstance">
			<ObjectDataProvider.MethodParameters>
				<sys:Type>sys:Int32</sys:Type>
				<sys:Int32>5</sys:Int32>
			</ObjectDataProvider.MethodParameters>
		</ObjectDataProvider>
		<local:IntSequence x:Key="list3" StartVal="1" EndVal="5" />
	</Window.Resources>
	<StackPanel>
		<ListBox ItemsSource="{Binding Source={StaticResource list1}}" />
		<ListBox ItemsSource="{Binding Source={StaticResource list2}}" />
		<ListBox ItemsSource="{Binding Source={StaticResource list3}}" />
	</StackPanel>
</Window>
public class IntSequence : IEnumerable<int> {
	private int startVal = 1;
	public int StartVal {
		get { return startVal; }
		set { startVal = value; }
	} 

	private int endVal = 10;
	public int EndVal {
		get { return endVal; }
		set { endVal = vlue; }
	} 

	IEnumerator<int> IEnumerable<int>.GetEnumerator( ) {
		for (int val = startVal; val <= endVal; val++)
			yield return val;
	} 

	IEnumerator IEnumerable.GetEnumerator( ) {
		foreach (int item in this) 
			yield return item;
	}
}

All these approaches come with their own advantages and disadvantages. The x:Array block can be defined completely in XAML and is obviously not restricted to sequential values. Then again, for a simple sequence, there's a lot of typing and/or copying/pasting to be done and the result is extremely verbose. The ObjectDataProvider with the dynamically created array is an interesting approach, but the array is not actually initialized with values (so it contains a bunch of zeros) and the XAML code is also quite verbose. Finally the IntSequence looks great in XAML, but it requires a helper class, however simple. Well, there's something for everyone here...

Permalink 08:50:14 pm
Categories: General

WPF: Bottom dwelling with an ItemsControl

 Here's something I just stumbled upon. Not quite intuitive, so I thought I'd write it down. Consider this piece of XAML (you can paste it into XamlPad to try it out):

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
	<DockPanel LastChildFill="False">
		<Button DockPanel.Dock="Bottom" Background="Yellow" Content="X" />
		<Button DockPanel.Dock="Bottom" Background="Red" Content="X" />
		<Button DockPanel.Dock="Bottom" Background="Blue" Content="X" />
		<Button DockPanel.Dock="Bottom" Background="Green" Content="X" />
		<Button DockPanel.Dock="Bottom" Background="Magenta" Content="X" />
		<Button DockPanel.Dock="Bottom" Background="Black" Content="X" />
		<Button DockPanel.Dock="Bottom" Background="Orange" Content="X" />
	</DockPanel>
</Page>

What it does is pretty obvious: it creates a bunch of buttons and docks them all to the bottom of the panel.

Now look at the following XAML. It uses an ItemsControl to create a dynamic structure based on data binding, that also contains a number of buttons. Similar to before, the buttons are children of a DockPanel and they have the DockPanel.Dock attribute attached and set to the value Bottom.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:sys="clr-namespace:System;assembly=mscorlib"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
	<Page.Resources>
		<x:Array x:Key="sequence" Type="sys:Int32">
			<sys:Int32>1</sys:Int32>
			<sys:Int32>2</sys:Int32>
			<sys:Int32>3</sys:Int32>
			<sys:Int32>4</sys:Int32>
			<sys:Int32>5</sys:Int32>
			<sys:Int32>6</sys:Int32>
			<sys:Int32>7</sys:Int32>
			<sys:Int32>8</sys:Int32>
		</x:Array>
	</Page.Resources>
	<ItemsControl ItemsSource="{Binding Source={StaticResource sequence}}">
		<ItemsControl.ItemsPanel>
			<ItemsPanelTemplate>
				<DockPanel LastChildFill="False" />
			</ItemsPanelTemplate> 
		</ItemsControl.ItemsPanel>
		<ItemsControl.ItemTemplate>
			<DataTemplate>
				<Button Content="{Binding}" DockPanel.Dock="Bottom" />
			</DataTemplate>
		</ItemsControl.ItemTemplate> 
	</ItemsControl>
</Page>

If you paste this code into XamlPad, you might be as surprised as I was initially to find that this is the output:

So why is that? The answer can also be found in XamlPad, comparing an important part of the visual trees for both examples:

As you can see, the visual tree for the databound case is quite a bit more complex, and most importantly, the Button instances are wrapped in ContentPresenter instances before being included in the DockPanel. So the reason why the docking doesn't work is because the DockPanel.Dock property is not attached to the actual children of the DockPanel!

Here's the solution I found for this problem. It is possible to configure the style for the ContentPresenter that is wrapped around the items, and to attach the property to it instead of the Button itself. The ItemsControl has a property called ItemContainerStyle, and it can be used like this:

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:sys="clr-namespace:System;assembly=mscorlib"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
	<Page.Resources>
		<x:Array x:Key="sequence" Type="sys:Int32">
			<sys:Int32>1</sys:Int32>
			<sys:Int32>2</sys:Int32>
			<sys:Int32>3</sys:Int32>
			<sys:Int32>4</sys:Int32>
			<sys:Int32>5</sys:Int32>
			<sys:Int32>6</sys:Int32>
			<sys:Int32>7</sys:Int32>
			<sys:Int32>8</sys:Int32>
		</x:Array>
	</Page.Resources>
	<ItemsControl ItemsSource="{Binding Source={StaticResource sequence}}">
		<ItemsControl.ItemsPanel>
			<ItemsPanelTemplate>
				<DockPanel LastChildFill="False" />
			</ItemsPanelTemplate> 
		</ItemsControl.ItemsPanel>
		<ItemsControl.ItemTemplate>
			<DataTemplate>
				<Button Content="{Binding}" />
			</DataTemplate>
		</ItemsControl.ItemTemplate> 
		<ItemsControl.ItemContainerStyle>
			<Style>
				<Setter Property="DockPanel.Dock" Value="Bottom" />
			</Style>
		</ItemsControl.ItemContainerStyle>
	</ItemsControl>
</Page>

With this change, the result is finally what I want - all the buttons are docked to the bottom correctly.

There may be a second possible solution, by making the ItemControl somehow skip creating that additional wrapper altogether, but I haven't tried doing that.

16/03/07

Permalink 05:55:18 pm
Categories: General, Programming, .NET

Cross tables in Windows Forms - data binding magic

I have this sample from a recent talk at Basta! conference in Germany, which shows (among other things) how to bind a cross table to a DataGridView (the standard .NET 2 data grid). A cross table is basically the result of transposing some data and using one of the fields for a second dimension.

The sample I have works on two tables of data. It doesn't actually use a database and the reference that points from the list of votes to that of features is implemented as an object reference, but the relationship is like this:

 Now, let's assume there's this data in the two tables/lists:

Features
ID Name
1 Synthesize out-of-the-box supply-chains
2 Syndicate vertical mindshare
  

Votes
ID Feature_ID Year Priority
1 1 2004 30
2 1 2005 40
3 1 2006 70
4 2 2004 70
5 2 2005 60
6 2 2006 30

In a cross table the same data could look like this:

Feature/Year 2004 2005 2006
Synthesize out-of-the-box supply-chains 30 40 70
Syndicate vertical mindshare 70 60 30

This is exactly the kind of transformation demonstrated in my sample. Now, there are a number of other things in that program, so don't be confused. I suggest you focus on the workings of the VoteValuePropertyDescriptor class.

Here's the download: FeatureVoting.zip

 

13/03/07

Permalink 10:33:02 am
Categories: General

MSDN Roadshow and food, Zi Makki style

March 21st is the date of the MSDN Roadshow in London. Should be interesting to hear some news about LINQ, the Entity Framework, AJAX and XAML… I’ll be there, and hoping to meet a few of you! Registration is apparently still open, so follow this link if you haven’t signed up yet.

After the event, there’s another fabulous geek dinner organized by the every more experienced geek-dinner-organizer Zi Makki :-) If you’re interested in meeting some of the other guys you read about in the blog-o-sphere (or maybe you just think you’re going to be hungry <g&gt;), be there! Sign-up is here.

1 2 >>

Enter your email address:

Search

Oliver
MVP logo
March 2007
Sun Mon Tue Wed Thu Fri Sat
 << < Current> >>
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31