简体   繁体   中英

WPF - Items Collection Dynamic Margins

i want to render several elements inside a full width border and to compute programmatically margins so i get rectangles in a grid with appropriate margins. This would be the rendering that i want to get:

在此处输入图片说明

The margins should be computed using an algorithm based on the data-bound values. To explain the idea, let's assume i have a list of strings containing "One", "Two" and "Three" that i am binding to my control. Let's assume my algorithm is very simple and assigns +100 to each next element margin. So i would have three rectangles:

  • Rectangle for element "One" - Margin: 100
  • Rectangle for element "Two" - Margin: 200
  • Rectangle for element "Three" - Margin: 300

All the rectangles are the same, the only difference is the computed margin.

My initial idea was to use an ItemsControl and use a MultiBinding to compute the margins for each element.

However, when i use an ItemsControl with a MultiBinding to compute the Dynamic Margin, i can't get the rectangles to render properly.

 <ItemsControl>
                <ItemsControl.ItemsSource>
                    <x:Array Type="sys:String" 
        xmlns:sys="clr-namespace:System;assembly=mscorlib">
                        <sys:String>One</sys:String>
                        <sys:String>Two</sys:String>
                        <sys:String>Three</sys:String>
                    </x:Array>
                </ItemsControl.ItemsSource>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Grid>
                            <Rectangle Name="InnerRectangle" VerticalAlignment="Stretch" Fill="Blue" Width="2" Height="120">
                                <Rectangle.Margin>
                                    <MultiBinding Mode="OneWay" Converter="{StaticResource MultiMarginConverter}">
                                        <Binding Path="ActualWidth" RelativeSource="{RelativeSource AncestorType={x:Type Border}}"></Binding>
                                        <Binding Path=""></Binding>
                                    </MultiBinding>
                                </Rectangle.Margin>
                            </Rectangle>
                        </Grid>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>

If i run this, the margins compute correctly in the converter, but the rectangles render as stacked on top of each other?

The algorithm to compute the margins will use several values from the current context, so i need to use several property values, and that is why i use a multi-binding.

Here is the converter just to get some dynamic margins for the sake of trying out the concept:

 public class MultiBindingMarginConverter : IMultiValueConverter
{
    List<Double> margins = new List<Double>() { 110, 220, 333, 444, 555, 666, 777 };

    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        var randomizer = new Random();;

        // I just get a random margin to try the concept. The margin will be computed by a more complex algorithm
        var computedMargin = margins.ElementAt(randomizer.Next(1, 7));

        return new Thickness(computedMargin, 0, 0, 0);
    }

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

Note: When i just run the app it doesn't render the rectangles properly. However, when i debug and set a breakpoint in the multibinding converter, the margins get applied and the rectangles render correctly?!

I think the general approach should work, but i can't figure out what i am doing wrong in the rendering that would cause the rectangles to render with the wrong margins, even if they are computed correctly in the converter.

Thanks

Not sure if I correctly understood your question, but in case you wanted to put all those Rectangles into the same Grid cell you would have to set the ItemsControl's ItemsPanel to a Grid:

<ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
        <Grid/>
    </ItemsPanelTemplate>
</ItemsControl.ItemsPanel>

Similarly you may also use a Canvas as ItemsPanel and set the Canvas.Left property (instead of Margin ) on each item Rectangle.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM