我想扩展ItemsPanel
,以便我可以显示一个“分层”的视觉结构,其中我有一个具有已知大小和大量叠加的“框架”,类似于制图或插图应用程序。
我遇到的问题是找出如何组合事物,以便一切按预期工作。到目前为止我做了什么:
ItemsControl
的控件;Viewbox
的ItemsPresenter
ItemsPanel
设置为一个由Canvas
组成的ItemsTemplate。所以我希望,在Live Tree Inspection中,我应该看到,在嵌套结构中:
相反,我看到的是:
所以问题是ViewBox包含在Canvas中,与渲染项一起。
那么我的问题是:如何以嵌套顺序为ItemsPresenter-> Viewbox-> Canvas-> Items的方式构建我的LayerContainer控件?
这是我的控制(名称实际上不是LayerContainer
)
<ItemsControl x:Class="Miotec.PressureMapping.UserControls.BaroLayerContainer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Miotec.PressureMapping.UserControls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<ItemsControl.Resources>
<Style TargetType="local:BaroLayerContainer">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<Canvas Width="{Binding Parametros.Colunas}"
Height="{Binding Parametros.Linhas}"
IsItemsHost="True"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
</ItemsControl.Resources>
<Viewbox Stretch="Uniform" x:Name="container">
<ItemsPresenter
Width="{Binding ActualWidth, ElementName=container}"
Height="{Binding ActualHeight, ElementName=container}"/>
</Viewbox>
</ItemsControl>
如果你想要一个如何做到这一点的工作实例,那么看看我的Perfy editor on GitHub,相关部分是在the MainWindow.xaml file。它还展示了如何实现缩放和滚动(如果你想支持两者,那么你实际上不需要ViewBox,只需要一个ScrollViewer父项和ItemsControl上的LayoutTransform)。
要回答您的问题,每个项目都包含在ContentPresenter中,诀窍是在此父项目上设置您的Canvas位置。 ItemsControl公开了ItemContainerStyle
,它允许你这样做:
<ItemsControl.ItemContainerStyle>
<Style TargetType="{x:Type ContentPresenter}">
<Setter Property="Canvas.Left" Value="{Binding X}" />
<Setter Property="Canvas.Top" Value="{Binding Y}" />
</Style>
</ItemsControl.ItemContainerStyle>
特别要注意的是,你不需要自己明确声明一个ItemsPresenter
,这是因为你已经开始使用ItemsControl了。只需将你的ItemsPanel
设置为Canvas,通过ContentPresenter
设置ItemContainerStyle
的样式,然后使用DataTemplates
和/或触发器指定集合项本身的外观。
经过一些思考和谷歌搜索,我意识到我可以“覆盖”我的控制的Template
属性,用ControlTemplate
我将把Viewbox
作为root,并在其中,ItemsPresenter。然后在渲染时,每个项目将被放置在包含ItemsPanelTemplate
的Canvas
中,分配给ItemsPanel
属性。
以下是最终的工作表格。解决方案原则是除了Template
属性(对于Canvas)还设置ItemsPanel
属性(对于ViewBox)。
<ItemsControl x:Class="Miotec.PressureMapping.UserControls.BaroLayerContainer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Miotec.PressureMapping.UserControls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<Grid x:Name="container">
<Viewbox Stretch="Uniform"
Width="{Binding ActualWidth, ElementName=container}"
Height="{Binding ActualHeight, ElementName=container}">
<ItemsPresenter/>
</Viewbox>
</Grid>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Width="{Binding Parametros.Colunas}"
Height="{Binding Parametros.Linhas}"
IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>