I found a way how it could work, it's not the best but in that way you can override that the arrangement of the items is done by the parent-control.
your class:
public class Data
{
public BitmapImage Image { get; set; }
public string Name { get; set; }
public double xIndex { get; set; }
public double yIndex { get; set; }
}
ViewModel:
public class ViewModel
{
private readonly ObservableCollection<Data> images = new ObservableCollection<Data>();
public ObservableCollection<Data> Images
{
get { return images; }
}
public ViewModel()
{
Images.Add(new Data
{
Image = new BitmapImage(new Uri("ms-appx:///../Assets/StoreLogo.scale-100.png")),
Name = "Image1",
xIndex = 50,
yIndex = 50
});
Images.Add(new Data
{
Image = new BitmapImage(new Uri("ms-appx:///../Assets/SmallLogo.scale-100.png")),
Name = "Image2",
xIndex = 250,
yIndex = 250
});
Images.Add(new Data
{
Image = new BitmapImage(new Uri("ms-appx:///../Assets/SplashScreen.scale-100.png")),
Name = "Image3",
xIndex = 500,
yIndex = 500
});
}
}
Page:
<Page
x:Class="App8.MainPage"
DataContext="{Binding ViewModel, RelativeSource={RelativeSource Self}}"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App8"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Margin="0 100 0 0">
<ItemsControl ItemsSource="{Binding Images}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentPresenter x:Name="Test" Canvas.Left="{Binding xIndex}" Canvas.Top="{Binding yIndex}">
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<Image Height="50" Source="{Binding Image}"/>
</StackPanel>
</ContentPresenter>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<local:MyCanvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
</Page>
You need your own ItemsPanelTemplate to override the arrangement.
public class MyCanvas : Canvas
{
protected override Size ArrangeOverride(Size finalSize)
{
var children = this.GetDescendantsOfType<ContentPresenter>();
foreach (var item in children)
{
var data = item.Content as Data;
if (data != null)
{
Canvas.SetLeft(item, data.xIndex);
Canvas.SetTop(item, data.yIndex);
}
}
return base.ArrangeOverride(finalSize);
}
}
GetDescendantsOfType is part of the VisualTreeHelperExtensions from the WinRT XAML Toolkit.
public static class VisualTreeHelperExtensions
{
/// <summary>
/// Gets the descendants of the given type.
/// </summary>
/// <typeparam name="T">Type of descendants to return.</typeparam>
/// <param name="start">The start.</param>
/// <returns></returns>
public static IEnumerable<T> GetDescendantsOfType<T>(this DependencyObject start) where T : DependencyObject
{
return start.GetDescendants().OfType<T>();
}
/// <summary>
/// Gets the descendants.
/// </summary>
/// <param name="start">The start.</param>
/// <returns></returns>
public static IEnumerable<DependencyObject> GetDescendants(this DependencyObject start)
{
if (start == null)
{
yield break;
}
var queue = new Queue<DependencyObject>();
var popup = start as Popup;
if (popup != null)
{
if (popup.Child != null)
{
queue.Enqueue(popup.Child);
yield return popup.Child;
}
}
else
{
var count = VisualTreeHelper.GetChildrenCount(start);
for (int i = 0; i < count; i++)
{
var child = VisualTreeHelper.GetChild(start, i);
queue.Enqueue(child);
yield return child;
}
}
while (queue.Count > 0)
{
var parent = queue.Dequeue();
popup = parent as Popup;
if (popup != null)
{
if (popup.Child != null)
{
queue.Enqueue(popup.Child);
yield return popup.Child;
}
}
else
{
var count = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < count; i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
yield return child;
queue.Enqueue(child);
}
}
}
}
}