Setting Canvas Properties in an Itemscontrol Datatemplate

Setting Canvas properties in an ItemsControl DataTemplate

The attached properties only work on direct children of the Canvas. ItemsControl will place ContentPresenter controls as its direct children, so you might want to add a style for that as well:

<ItemsControl ItemsSource="{Binding Path=Nodes}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding Path=XPos}" />
<Setter Property="Canvas.Top" Value="{Binding Path=YPos}" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>

WPF ItemsControl DataTemplate not shown on canvas

The canvas should be inside the itemscontrol as it's itemspanel.

Something very roughly like:

<ItemsControl ItemsSource="{Binding RItems}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
.....
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Canvas.Left" Value="{Binding Left}" />
<Setter Property="Canvas.Top" Value="{Binding Top}" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>

Note also that each item goes inside a container and it is this which has to be positioned on the canvas.

I'm not sure why your grid is bound to the size of the canvas. Put the itemcontrol inside the grid and it'll fill the grid.

Is setting Canvas properties in an ItemsControl's ItemContainerStyle 'Blendable'?

As far as I know this is not possible. Attached properties are not shown in Blend because there are just too many. When an element is placed directly into a canvas left and top properties are displayed, but it would be impossible to have all attached properties available. For example, you could set the Canvas.Left property if the element you set the property on is not inside a canvas.

The only way to set an attached property is to do it by hand in Xaml.

Accessing Canvas properties inside DataTemplate, WPF

If you want to customize the layout of an ItemsControl's children and the available Panels don't deliver what you need, you will probably have to build your own panel. Here is an introduction to the topic: http://www.codeproject.com/Articles/15705/FishEyePanel-FanPanel-Examples-of-custom-layout-pa

The difficulty depends on what your layout will look like. Inside your panel you can then access all elements properties for layout logic. For Example if you wanted to align all multiline textboxes on the right side of the panel and all single line textboxes left, that would be easy to do. :)

If you elaborate a little more what you want to achieve I can give you better guidance.

---- EDIT ---
Canvas.Left and the others are AttachedProperties. You can for example bind against the assigned values inside the template using the following syntax:

MyProperty="{Binding Path=(Canvas.Left), RelativeSource={RelativeSource TemplatedParent}}"

---- EDIT 2 ---

So here's a Sample that should do what you want. In the ViewModel there's a Collection containing Points (X & Y). These get rendered inside an ItemsControl with a Canvas Panel. The tricky part is that around each element there's a ContentPresenter, so binding Canvas values to the Button in the ItemTemplate does not work. Therefore I added the ItemContainerStyle:

MainWindow.Xaml

<Window x:Class="WpfApplication7.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" >
<ItemsControl ItemsSource="{Binding Locations}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="Point">
<Button Content="{Binding}" Width="40" Height="20" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left"
Value="{Binding X}" />
<Setter Property="Canvas.Top"
Value="{Binding Y}" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
</Window>

MainWindow.Xaml.cs:

public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
}

ViewModel:

public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
Locations = new ObservableCollection<Point>
{
new Point(10,10),
new Point(20,20),
new Point(30,30),
new Point(50,60),
};
}

public ObservableCollection<Point> Locations { get; set; }

#region INotifyPropertyChanged Support

public event PropertyChangedEventHandler PropertyChanged;

[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}

#endregion

}

Try that, I believe it should do what your are looking for. :)

When using ItemsControl ItemsControl.ItemsPanel is set to Canvas, ContenPresenter comes in and break my Canvas properties on the children [WPF]

there are several solutions coming to my mind:

  1. use a layout/rendertransform instead of the attached property
  2. use margin instead of the attached property
  3. derive from ItemsControl, and override the behavior how the child containers are generated. (GetContainerForItemOverride, IsItemItsOwnContainerOverride). This article is explaining quite nicely how it works: http://drwpf.com/blog/2008/07/20/itemscontrol-g-is-for-generator/


Related Topics



Leave a reply



Submit