How can I position ViewModels in an ItemsControl
Asked Answered
P

1

1

My mainwindow ViewModel has an ObservableCollection of ViewModels, called ViewModels.

The Mainwindow XAML has an ItemsControl with ItemsSource bound to ViewModels.

When I have

<ItemsControl ItemsSource="{Binding ViewModels}" />

The Views associated with each ViewModel in the collection are rendered one below the other. The Views are UserControls, displaying dataGrids.

How can I position them in a customizable way, for example such that VM1 is on the left, and VM2 and VM3 are stacked one on top of the other to the right of VM1.

Each VieModel has PosX, PosY, Width and Height properties, and I've been trying various templating methods but no success so far.

I have found examples of how to this with Observable collections of images, but one thing I'm struggling is that my collection is of ViewModels.

Precipitation answered 10/3, 2011 at 15:10 Comment(2)
I need to show different views associated with different view models in itemsControls using observablecollections as what you did. I am new to WPF. Can you share your code with me!Noneffective
@Manish Dubey, see the code in the accepted answer belowPrecipitation
P
6

Make your ItemsControl.ItemsPanel into a Canvas, and set your Top/Left/Height/Width in the ItemTemplate.

<ItemsControl ItemsSource="{Binding ViewModels}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <!-- Height, Width, and Background are required to render size correctly -->
            <Canvas Height="600" Width="800" Background="White" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>

    <ItemsControl.ItemContainerStyle>
        <Style TargetType="{x:Type FrameworkElement}">
            <Setter Property="Canvas.Top" Value="{Binding Top}" />
            <Setter Property="Canvas.Left" Value="{Binding Left}" />
            <Setter Property="Height" Value="{Binding Height}" />
            <Setter Property="Width" Value="{Binding Width}" />
        </Style>
    </ItemsControl.ItemContainerStyle>

    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <ContentControl>
                <ContentPresenter ClipToBounds="True" Content="{TemplateBinding Content}"/>
            </ContentControl>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>
Proprioceptor answered 10/3, 2011 at 15:25 Comment(5)
Thanks Rachel, but dont i need a DataTemplate too. Running with your solution i get a blank canvas, whilst as i said above, omitting all the ItemsControl internal stuff, i get my ViewModels stacked on top of each other.Precipitation
@Precipitation Yes you need a DataTemplate. I thought you had that covered, sorry. I'll add it inProprioceptor
Almost there, with your gracious help... Now I'm getting the first viewmodel to display OK, but the second one which I've set at left=VM1.width, is not displaying. Any ideas? And what does ClipToBounds do in this context?Precipitation
@Precipitation Is VM2.Left, Top, Height, and Width all set correctly? I'd verify the values are correct first. Second, check and make sure the Canvas is large enough to fit its content. I usually do this by setting the background color of the Canvas so I can see the space it is using. The ClipToBounds is just there since I copy/pasted that line from some code I have and didn't both removing it. It clips the object if the size exceeds the available space in the canvas.Proprioceptor
Obviously I checked and double checked... But now, at your urging, i checked again, and for VM2, the values were being set in a function that was not being called... Thanks for all your help.Precipitation

© 2022 - 2024 — McMap. All rights reserved.