1
votes

So I have a collection of objects that may be of multiple type. For example a base class with B, and descendents C,D,E.

All this will be in an ItemsControl, however with a custom (somehow random) logic. Therefore I create an ItemsControl in the XAML, specify the DataTemplates binding them to types and let the Silverlight implicit datatemplate engine handle the rest.

The position of the elements inside the ItemsControl presenter is somehow random, and available only at runtime as a dependency property in the element itself (part of the Base class).

My problem is that by default the ItemsControl wraps the items in a ContentPresenter Object, therefore setting the Canvas.Left and Canvas.Top in the data templates has no effect. Because this should be set on the ContentPresenter level instead. However, if I define the ContentPresenter style, the datasource of this is the ItemsControl itself, and not the items. Therefore, I cannot bind that way the positions of the items.

Any ideas, how can I bind the item position properties to the ContentPresenters Canvas.Left property?

In code terms:

<ItemsControl HorizontalAlignment="Stretch" Grid.Row="0" Grid.ColumnSpan="3"
                  x:Name="CardItems" ItemsSource="{Binding CardList}" ScrollViewer.HorizontalScrollBarVisibility="Disabled"
                  ScrollViewer.VerticalScrollBarVisibility="Disabled">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="SizeChanged">
                <ei:CallMethodAction MethodName="WndSizeChanged" TargetObject="{Binding}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>
<UserControl.Resources>
    <DataTemplate DataType="Card:AdCardViewModel">
        <Canvas d:DesignHeight="300" d:DesignWidth="150" Width="{Binding CardSize.Width}" Height="{Binding CardSize.Height}" Background="Red">
            <Canvas.Projection>
                <PlaneProjection RotationY="{Binding Path=Rotation}"/>
            </Canvas.Projection>
            <Viewbox>
                <StackPanel>
                    <StackPanel.Background>
                        <SolidColorBrush Color="{StaticResource OriginalRecommendationColor}"/>
                    </StackPanel.Background>
                    <TextBlock Text="{Binding AdCard}" Foreground="CadetBlue"/>
                </StackPanel>
            </Viewbox>
        </Canvas>
    </DataTemplate>
</UserControl.Resources>

PS. I am using the MVVM Light, so I would rather avoid using the code behind file.

LE:

This seems to work, however for some reason the Visual Studio Intellisense has not idea about it. Runtime it seems to be okay, however nothing at design time. Any ideas, how to make all this working in Blend too?

          <ItemsControl.Resources>
            <Style TargetType="ContentPresenter">
                <Setter Property="Canvas.Left"  Value="{Binding  Path=Position.Height}"/>
                <Setter Property="Canvas.Top"  Value="{Binding  Path=Position.Width}"/>
                <Setter Property="Width" Value="Auto"/>
                <Setter Property="Height" Value="Auto"/>
                <Setter Property="HorizontalAlignment" Value="Stretch"/>
                <Setter Property="VerticalAlignment" Value="Stretch"/>
            </Style>
        </ItemsControl.Resources>

The viewModelLocator:

    static ViewModelLocator()
    {
        ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

        // Step #1 - Register the data providing services, design and runtime versions
        if (ViewModelBase.IsInDesignModeStatic)
        {
            SimpleIoc.Default.Register<ICardService, DesignCardService>();
        }
        else
        {

            SimpleIoc.Default.Register<ICardService, CardService>();

        }

        // Step#2 Register the ViewModels
        SimpleIoc.Default.Register<CardSlideShowViewModel>();
    }


    /// <summary>
    ///     Gets the Video property.
    /// </summary>
    [SuppressMessage("Microsoft.Performance",
        "CA1822:MarkMembersAsStatic",
        Justification = "This non-static member is needed for data binding purposes.")]
    public CardSlideShowViewModel CardSlideShowSlideShow
    {
        get { return ServiceLocator.Current.GetInstance<CardSlideShowViewModel>(); }
    }

Thanks,

2

2 Answers

0
votes

A Design Time View Model should do the trick. You just need to create a simple representation of your runtime vm - initialising the CardViewModel collection in it's constructor.

Then you bind the ViewModel at design time like this:

<UserControl x:Class="MyView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         d:DataContext="{d:DesignInstance local:MyViewModel,
                                          IsDesignTimeCreatable=True}"
0
votes

Well, not really an answer, however the closest I come to this. It seems to me that VS 2010 does not support this, yet. However it works in VS 2012. So if you can do the upgrade.