tags:

views:

32

answers:

3

I'm new to WPF and before I dive in solving a problem in completely the wrong way I was wondering if WPF is clever enough to handle something for me.

Imagine I have a collection containing objects. Each object is of the same known type and has two parameters. Name (a string) and Picked (a boolean).

The collection will be populated at run time.

I would like to build up a UI element at run time that will represent this collection as a series of checkboxes. I want the Picked parameter of any given object in the collection updated if the user changes the selected state of the checkbox.

To me, the answer is simple. I iterate accross the collection and create a new checkbox for each object, dynamically wiring up a ValueChanged event to capture when Picked should be changed.

It has occured to me, however, that I may be able to harness some unknown feature of WPF to do this better (or "properly"). For example, could data binding be employed here?

I would be very interested in anyone's thoughts.

Thanks,

E

FootNote: The structure of the collection can be changed completely to better fit any chosen solution but ultimately I will always start from, and end with, some list of string and boolean pairs.

+1  A: 

You can use Data Templates. Here's a good post about it.

Martinho Fernandes
Thanks for that link. Looks like a good post.
elggarc
+1  A: 

This is exactly the kind of scenario WPF simplifies. Event-handlers- bah! Data-binding and data templates make this a cinch. I have constructed an example illustrating how you can do this.

Here is the code-behind, which declares a class to represent your items- PickedItem. I then create a collection of these items and populate it with some samples.

public partial class DataBoundCollection : Window
{
    public DataBoundCollection()
    {
        Items = new ObservableCollection<PickedItem>();
        Items.Add(new PickedItem("Item 1"));
        Items.Add(new PickedItem("Item 2"));
        Items.Add(new PickedItem("Item 3"));

        InitializeComponent();
    }

    public ObservableCollection<PickedItem> Items
    {
        get;
        set;
    }
}

public class PickedItem
{
    public PickedItem(string name)
    {
        Name = name;
        Picked = false;
    }

    public string Name
    {
        get;
        set;
    }

    public bool Picked
    {
        get;
        set;
    }
}

Now, let's look at the XAML mark-up for this window:

<Window x:Class="TestWpfApplication.DataBoundCollection"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DataBoundCollection" Height="300" Width="300"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
    <ListBox ItemsSource="{Binding Items}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <CheckBox IsChecked="{Binding Picked}" Margin="5"/>
                    <TextBlock Text="{Binding Name}" VerticalAlignment="Center"/>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>

I create a ListBox to hold the items, and bind its ItemsSource property to the collection I created in the code-behind. Then, I provide the ListBox with an ItemTemplate, which determines how each PickedItem will be rendered. The DataTemplate in this case is as simple as a check-box and some text, both bound to the member variables on PickedItem. Now, when I check any of these items, the data in the underlying collection is modified, in real-time, with no event handlers needed. Ta-da!

alt text

Charlie
+1 Excellent answer. Also, I haven't seen the trick of implementing properties in the window class and then setting the windows data context to itself before. That's another one of those obvious things that never would have occurred to me to try.
Robert Rossney
+1  A: 

I would strongly recommend the ItemsControl, its behaviour is as close as you can get to the ASP.Net repeater control so it is very flexible.

Declare the item control as:

        <ItemsControl Name="YourItemsControl" 
                      ItemsSource="{Binding Path=YourCollection}" 
                      ItemTemplate="{StaticResource YourTemplate}">
        </ItemsControl>   

Then you can use the datatemplate to organise the data into a display format for the user

    <DataTemplate x:Key="ProjectsTemplate">

        <StackPanel Margin="0,0,0,10">
            <Border CornerRadius="2,2,0,0" Background="{StaticResource ItemGradient}" d:LayoutOverrides="Width, Height">
                <local:ItemContentsUserControl Height="30"/>
            </Border>
     ...

Useful ItemsControl Links

I hope this helps you.

Burt
Charlie's answer was easier to follow for someone new to WPF but ultimately the ItemsControl appears to provide better functionality in this case that ListBox or ListView. E
elggarc