Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Canvas as the ItemsPanel for an ItemsControl in Silverlight 3

I am trying to set the Canvas properties in an ItemsControl DataTemplate with Silverlight 3. According to this post, the only way of doing that is to set it using the ItemsContainerStyle for the ContentPresenter type, since the Canvas properties only take effect on direct children of the Canvas. This doesn't seem to work in SL3, since the ItemsControl doesn't have an ItemsContainerStyle property, so I tried a ListBox as advised by this article, but it still doesn't work. From the XAML below, I would expect to see a green square, with the numbers 10, 30, 50, 70 cascading from "NW" to "SE" direction. Can anyone tell me why they are all stacked on top of eachother in the NW corner?

<UserControl x:Class="TestControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:System="clr-namespace:System;assembly=mscorlib" >
    <StackPanel>
        <ListBox>
            <ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas Background="Green" Width="100" Height="100" />
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBox Text="{Binding}" />
                </DataTemplate>                
            </ListBox.ItemTemplate>
            <ListBox.ItemContainerStyle>
                <Style TargetType="ContentPresenter">
                    <Setter Property="Canvas.Left" Value="{Binding}" />
                    <Setter Property="Canvas.Top" Value="{Binding}" />
                </Style>
            </ListBox.ItemContainerStyle>
            <ListBox.Items>
                <System:Int32>10</System:Int32>
                <System:Int32>30</System:Int32>
                <System:Int32>50</System:Int32>
                <System:Int32>70</System:Int32>
            </ListBox.Items>
        </ListBox>
    </StackPanel>
</UserControl>
like image 352
skb Avatar asked Mar 05 '10 00:03

skb


3 Answers

I'm not sure if it will work in your scenario, but I've accomplished this in the past using the RenderTransform.

<ItemsControl>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas Background="Green" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <TextBox Text="{Binding}">
                <TextBox.RenderTransform>
                    <TranslateTransform X="100" Y="100" />
                </TextBox.RenderTransform>
            </TextBox>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.Items>
        <System:Int32>10</System:Int32>
        <System:Int32>30</System:Int32>
        <System:Int32>50</System:Int32>
        <System:Int32>70</System:Int32>
    </ItemsControl.Items>
</ItemsControl>

Or in the case of binding you will need to use a converter

<ItemsControl>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas Background="Green" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <TextBox Text="{Binding}" RenderTransform="{Binding Converter={StaticResource NumberToTransformGroupConverter}}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.Items>
        <System:Int32>10</System:Int32>
        <System:Int32>30</System:Int32>
        <System:Int32>50</System:Int32>
        <System:Int32>70</System:Int32>
    </ItemsControl.Items>
</ItemsControl>

Converter

public void ConvertTo(object value, ...)
{
    int intValue = int.Parse(value.ToString());

    return new TransformGroup()
    {
        Children = new TransformCollection()
        {
            new TranslateTransform { X = intValue, Y = intValue }
        }
    };
}
like image 110
bendewey Avatar answered Nov 07 '22 13:11

bendewey


Old post but I went into the same problem but now with SL5 that now allows Binding in style setters. I was trying to avoid to use the ListBox (because it handles selection and so on) and the ItemsControl still doesn't have an ItemContainerStyle. So I tried a few things.

I haven't found many subject discussing this problem so let me share my solution (sorry if it duplicates)

In fact, I found a very convenient way to solve the problem by adding an unnamed Style in the ItemsControl resources :

<ItemsControl ItemsSource="{Binding Path=MyData}">
    <ItemsControl.Resources>
        <Style TargetType="ContentPresenter">
            <Setter Property="Canvas.Top" Value="{Binding Path=Bounds.Top}"/>
            <Setter Property="Canvas.Left" Value="{Binding Path=Bounds.Left}"/>
            <Setter Property="Width" Value="{Binding Path=Bounds.Width}"/>
            <Setter Property="Height" Value="{Binding Path=Bounds.Height}"/>
        </Style>
    </ItemsControl.Resources>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate DataType="my:DataType">
            ...
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

Works like a charm in SL5 :)

like image 2
xum59 Avatar answered Nov 07 '22 13:11

xum59


Silverlight4 does not bind to attached properties in style. I suggest using David Anson's approach described here.

    <UserControl.Resources>
    <Style  x:Key="ScreenBindStyle" TargetType="ListBoxItem">
        <Setter Property="Helpers:SetterValueBindingHelper.PropertyBinding">
            <Setter.Value>
                <Helpers:SetterValueBindingHelper>
                    <Helpers:SetterValueBindingHelper Type="Canvas" Property="Left" Binding="{Binding LocationField.Value.X}" />
                    <Helpers:SetterValueBindingHelper Type="Canvas" Property="Top" Binding="{Binding LocationField.Value.Y}" />
                    <Helpers:SetterValueBindingHelper Type="Canvas" Property="ZIndex" Binding="{Binding ZIndex.Value}" />
                </Helpers:SetterValueBindingHelper>
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ListBoxItem">
                    <ContentPresenter/>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</UserControl.Resources>

And in listbox:

ItemContainerStyle="{StaticResource ScreenBindStyle}"
like image 3
Ben Avatar answered Nov 07 '22 12:11

Ben