【问题标题】:Combining Viewbox, Canvas, ItemsPanelTemplate and ItemsPresenter in a user control inheriting from ItemsPanel在继承自 ItemsPanel 的用户控件中结合 Viewbox、Canvas、ItemsPanelTemplate 和 ItemsPresenter
【发布时间】:2019-07-05 08:30:44
【问题描述】:

我想扩展 ItemsPanel 以便我可以显示一个“分层”视觉结构,其中我有一个已知大小的“框架”和许多叠加层,类似于制图或插图应用程序。

我遇到的问题是找出如何组合事物以使一切按预期工作。到目前为止我做了什么:

  • 创建了一个继承自ItemsControl的控件;
  • 在控件内部,放置一个包含ItemsPresenterViewbox
  • 在控件的资源中,创建了一个针对其自身类型的样式,将ItemsPanel 设置为由Canvas 组成的ItemsTemplate。

所以我希望,在 Live Tree Inspection 下,我应该在嵌套结构中看到:

  • LayerContainer(我的控件的类名)
    • 视图框
      • ItemsPresenter
      • 帆布
        • 项目1
        • 项目2

相反,我看到的是:

  • 层容器
    • 边框
      • ItemsPresenter
      • 帆布
        • 视图框
        • 项目1
        • 项目2

所以问题在于 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>

【问题讨论】:

    标签: wpf xaml wpf-controls itemscontrol itemspresenter


    【解决方案1】:

    如果您想要一个如何执行此操作的工作示例,请查看我的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,通过ItemContainerStyle 设置ContentPresenter 的样式,然后使用DataTemplates 和/或触发器来指定集合项目本身的外观。

    【讨论】:

    • 感谢您的回答。虽然你写的一切都是正确的,但这不是我面临的问题。我想要做的是让 ItemsPanel(它是一个 Canvas)inside 一个 ViewBox,我需要将它放在正确的位置。原始代码在 ItemsControl 内容区域“内部”声明了 ViewBox,它在项目旁边呈现(即在 Canvas 中)。我需要做的是声明一个自定义 ControlTemplate 并将带有 ItemsPresenter 的 ViewBox 放入其中,然后一切都按我的需要工作。再次感谢!
    【解决方案2】:

    经过一番思考和谷歌搜索,我意识到我可以“覆盖”我的控件的Template 属性,使用ControlTemplateViewbox 作为根,并在其中放置ItemsPresenter。然后在渲染时,每个项目将被放置在包含CanvasItemsPanelTemplate 中,分配给ItemsPanel 属性。

    所以下面是最终的工作形式。解决方案的原则是同时设置Template 属性(用于 ViewBox)除了ItemsPanel 属性(用于画布)。

    <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>
    

    【讨论】:

      猜你喜欢
      • 2011-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-01
      • 2013-09-03
      • 2023-03-10
      • 1970-01-01
      相关资源
      最近更新 更多