heltonbiker
heltonbiker

Reputation: 27575

Position objects relative to container size in WPF

I have an ObservableCollection<Point> that is displayed with an ItemsControl, where I set the ItemsPanelTemplate, ItemsPanel and ItemTemplate properties in XAML.

I want my points to represent normalized positions inside a bounding box. So, if I have a Point(0.5, 0.5), it will be in the exact middle of the container. Now if it is Point(0.25, 0.75), it will be positioned at 25% of the container width, and 75% of the container height.

The question is: how I make it happen in WPF? Should I put a ValueConverter in the ItemContainerStyle Bindings? Should I use a Behavior, a DataTemplate, an ElementBinding, a MultiBinding...?

I'm a bit lost...

XAML code, working with absolute positioning (not what I want):

            <ItemsControl x:Name="MarcadoresSelecionadosZoom" ItemsSource="{Binding ListaPontos}" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="{x:Null}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Canvas IsItemsHost="True" />
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>                      
                <ItemsControl.ItemContainerStyle>
                    <Style TargetType="{x:Type FrameworkElement}">
                        <Setter Property="Canvas.Left" Value="{Binding X}" />
                        <Setter Property="Canvas.Top" Value="{Binding Y}" />
                    </Style>                
                </ItemsControl.ItemContainerStyle>
                <ItemsControl.ItemTemplate>
                    <DataTemplate DataType="Point">
                        <Ellipse Fill="Blue"
                            Width="8"
                            Height="8"
                            Margin="-4,-4,4,4" />
                    </DataTemplate>             
                </ItemsControl.ItemTemplate>
            </ItemsControl>

Upvotes: 0

Views: 713

Answers (1)

heltonbiker
heltonbiker

Reputation: 27575

Well, I got it working with a relatively simple (although verbose as always with XAML) solution involving MultiBinding and MultiValueConverter. I changed the ItemContainerStyle alone, and created the Converter in codebehind:

XAML:

                <ItemsControl.ItemContainerStyle>
                    <Style TargetType="{x:Type FrameworkElement}">
                        <Setter Property="Canvas.Left">
                            <Setter.Value>
                                <MultiBinding Converter="{StaticResource NormalConverter}">
                                    <Binding Path="X"/>
                                    <Binding ElementName="MarcadoresSelecionados" Path="ActualWidth"/>
                                </MultiBinding>
                            </Setter.Value>
                        </Setter>
                        <Setter Property="Canvas.Top">
                            <Setter.Value>
                                <MultiBinding Converter="{StaticResource NormalConverter}">
                                    <Binding Path="Y"/>
                                    <Binding ElementName="MarcadoresSelecionados" Path="ActualHeight"/>
                                </MultiBinding>
                            </Setter.Value>
                        </Setter>
                    </Style>                
                </ItemsControl.ItemContainerStyle>

Converter:

public class NormalConverter : IMultiValueConverter
{
    public object Convert(object[] values,
                          System.Type targetType,
                          object parameter,
                          System.Globalization.CultureInfo culture)
    {
        double menor = (double)values[0];
        double maior = (double)values[1];
        return maior * menor;
    }

    public object[] ConvertBack(object value, System.Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new System.NotImplementedException();
    }
}

Upvotes: 1

Related Questions