0
votes

I have a DataTemplate for text and I use an ItemControl to place the text inside a canvas. How to access canvas properties inside the data template? In case if it is difficult I want to access individual textbox properties inside ItemControl. The reason is I need to do some textcontrol alignment. Both of my DataTemplate and ItemControl code is below

<DataTemplate
    DataType="{x:Type local:Text}">
    <TextBlock Text="{Binding Description}"
               FontSize= "{Binding Thickness}" 
               RenderTransformOrigin="0.5,0.5" 
               Foreground="#FFF63AFF" 
               FontWeight="Bold" >  
    <TextBlock.RenderTransform>
        <TransformGroup>
            <TranslateTransform X= "{Binding StartPoint.X}" Y= "{Binding StartPoint.Y}"  />                   
            <RotateTransform Angle= "{Binding Angle}"  />
        </TransformGroup>   
    </TextBlock.RenderTransform>  
    </TextBlock>
</DataTemplate>  


<ItemsControl ItemsSource="{Binding Path = TextList}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate> 
            <Canvas HorizontalAlignment="Center" VerticalAlignment="Center"
                Width="0" Height="0">  
                <Canvas.RenderTransform>
                <TransformGroup>                     
                    <ScaleTransform ScaleX="1" ScaleY="1"/>                                
                </TransformGroup>
                </Canvas.RenderTransform>
            </Canvas>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl> 
1

1 Answers

2
votes

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. :)