简体   繁体   中英

Problems rendering a WPF custom control within a Canvas via an ItemsControl

I would like to render a bunch of usercontrols on a Canvas, but each usercontrol should be rendered as the content of a custom content control.

The custom content control is called Window and provides a border, some buttons etc and allows the user to drag the window around the canvas. I've defined the canvas and its children like this:

<ItemsControl Grid.Column="2" Grid.Row="1" ItemsSource="{Binding Views}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <controls:Window Title="Test" Width="300" Height="300" Content="{Binding}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.ItemContainerStyle>
        <Style>
            <Setter Property="Canvas.Top" Value="50"/>
            <Setter Property="Canvas.Left" Value="50"/>
        </Style>
    </ItemsControl.ItemContainerStyle>
</ItemsControl>

But when each item is rendered, it's shown without the surrounding Window content control. In fact it doesn't even hit the Window constructor. This says to me that it's ignoring the DataTemplate and just adding the usercontrol to the canvas directly, but I'm not sure why.

Any suggestions?

UPDATED

Found a solution to this on another Stack thread Using binding to a List <UserControl> how can I do for not showing the controls

Basically as you've already found when you bind to a list of <UserControl> s you get Error 26 and the <DataTemplate> is ignored. The simple work around is to wrap the <UserControl> in another class so that it doesn't get detected as a control. You can then bind the <UserControl> in the <DataTemplate> using the property on the wrapper.

So to elaborate I created a wrapper class as below:

public class ViewWrapper
{
    public UserControl View { get; set; }
}

I then changed the list on my control to use ViewWrapper:

public ObservableCollection<ViewWrapper> ViewWrappers { get; set; } 

Now I can bind my list to the <ItemsControl> without it ignoring my <DataTemplate> . I use the View property of the wrapper to access the View.

        <ItemsControl ItemsSource="{Binding ViewWrappers}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <ContentControl Content="{Binding View}"/>
                        <Label Content="End of this item." />
                    </Grid>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>

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