如何在画布上绘制路径列表?

时间:2014-07-31 16:25:47

标签: c# wpf xaml mvvm wpf-controls

在我的WPF MVVM 应用程序中,我有ListBox Canvas作为其ItemsPanel。 ListBox的项目是用户点击按钮时动态创建的 - ListBox.ItemsSourceElements中存储的MainViewModel(自定义类型)列表,即DataContext我的MainWindow

目前,我的Element类描述了具有X和Y坐标的简单对象(以便可以在我的ListBox的Canvas上绘制)和一些名为ShapeGeometry的数据作为路径绘制。这是DataTemplate

<DataTemplate DataType="{x:Type localvm:Element}">
    <Control IsEnabled="{Binding IsSelected,RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}">
        <Control.Template>
            <ControlTemplate TargetType="Control">
                <Viewbox Stretch="Uniform"> <!-- Paths need to be wrapped in a Canvas + Viewbox to be movable, stretchable and rotatable -->
                    <Canvas>
                        <Path x:Name="Path" Fill="#FFAA0000" Data="{Binding ShapeGeometry}" Stretch="Uniform"/>
                    </Canvas>
                </Viewbox>
                <ControlTemplate.Triggers>
                    <DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}" Value="True">
                        <Setter TargetName="Path" Property="IsHitTestVisible" Value="False"/>
                    </DataTrigger>                                    
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Control.Template>
    </Control>
</DataTemplate>

如您所见,这允许我每个ListBoxItem只绘制一个特定的Path。相反,我希望我的ListBoxItem是一个包含ComplexElement项列表的Element,这意味着绘制的项目现在将包含不同数量的路径。现在,我关于如何实现这一目标的想法是将ListBoxItem定义为ListBoxViewBox + Canvas作为ItemsPanel,就像在ListBoxItem上一样上层,但它似乎过于复杂,或许可能被证明有点低效(我打算有几十个,如果不是几百个项目)。有更简单的方法吗?我可以以某种方式避免在每个{{1}}中使用ListBoxes吗?

2 个答案:

答案 0 :(得分:0)

如果你想减少开销并拥有一个列表,你应该可以用一个DataGrid控件替换ListBox。

然后将Canvas添加到RowDetailsTemplate。或者您可以在RowDetailsTemplate中放置第二个ListBox。

答案 1 :(得分:0)

我建议您使用自定义控件(具有ListBox或任何您想要的)作为ListBox.ItemTemplate的DataTemplate。这样,您可以降低ListBox的复杂性,并且cutomized控件可以满足您的需求实现自己的逻辑。

1.定义控件类

public class MyListItem : Control
{
   //Define the property/event/control logic you want

   static MyListItem ()
   {
     //Remeber this to override the default style
     DefaultStyleKeyProperty.OverrideMetadata(typeof(MyListItem ), new FrameworkPropertyMetadata(typeof(MyListItem )));
   }
}

2.定义模板

<Style TargetType="{x:Type my:MyListItem}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type my:MyListItem}">
                <Border>
                   <ListBox ItemsSource={Binding YourDetailList}>
                      <ListBox.ItemTemplate>
                       //Anything you want here
                      </ListBox.ItemTemplate>
                   </ListBox>
                </Boder>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

3.使用

<ListBox>
  <ListBox.ItemTemplate>
    <DataTemplate>
      <my:MyListItem/>
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>

顺便说一句

1.我建议你不要使用canvas作为ListBox的ItemsPanel,它可能会禁用虚拟化,这可能会降低ItemsSource庞大时的性能。

2.似乎你想要一个嵌套的ListBox,所以如果ItemTemplate变化,你可以使用'ItemTemplateSelector',检查这个MSDN。但是记住选择器可能是'static',这意味着datatemplate可能在初始化时只选择一次。

3.此外,如果您希望Item在某些情况下更改自己的行为,请尝试使用模板中的触发器或在定义类中执行此操作。