【问题标题】:WPF Draw tree structure with rectanges on top of each otherWPF绘制树结构,矩形相互重叠
【发布时间】:2017-09-05 06:46:27
【问题描述】:

我有一个树结构,我在这样的树视图中使用它

根在ObservableCollection<Component> 对象中。 Component 具有 x、y、width、height、children 和 name 属性。我想使用相同的树结构来绘制每个ComponentRectancle,并在顶部绘制子对象。像这样的

我尝试过这样的 ListBox

<!-- in Resources -->
<DataTemplate DataType="{x:Type m:Component}">
        <Border BorderBrush="LightBlue" BorderThickness="1">
            <Grid Width="{Binding Width}" Height="{Binding Height}">
                <Rectangle Cursor="Hand" Fill="AliceBlue"/>
                <Label Content="{Binding Name}" Margin="5"/>
            </Grid>
        </Border>
    </DataTemplate>



<ListBox ItemsSource="{Binding ComponentsToDraw}"
         x:Name="listBox"
         SelectionMode="Extended"
         SelectionChanged="listBox_SelectionChanged">

    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas Background="Transparent"/>
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>

    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
            <Setter Property="Canvas.Left" Value="{Binding X}"/>
            <Setter Property="Canvas.Top" Value="{Binding Y}"/>
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>

但是除了我的树的第一层之外,它无法绘制任何东西。 还尝试使用 Treeview,但无法停止绘制我的 Component 对象,例如堆栈面板。

希望任何人都有解决方案或更好的方法。

PS。我没有故意在图纸中包含“解决方案”元素。

【问题讨论】:

  • 如何设置 X,Y?全局的还是相对的?
  • UserControl 可能更适合这里,因为您可以更好地控制它。从 Canvases 的 StackPanel 开始,并将每个嵌套项添加到其父 Canvas。
  • @sTrenat 我在考虑是否可以让这个树形结构发挥作用。我猜其他全局也可以工作

标签: c# wpf canvas listbox treeview


【解决方案1】:

如果您可以接受在您的模型中定义 X、Y,您可以使用小样式树视图来执行此操作:

这是 Xaml:

<TreeView ItemsSource="{Binding ComponentsToDraw}">
    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type local:Component}" ItemsSource="{Binding ComponentsToDraw}">
            <Grid Canvas.Left="{Binding X}" Canvas.Top="{Binding Y}" Width="{Binding Width}" Height="{Binding Height}" Background="{Binding Color}">
                <TextBlock Margin="8,5,0,0" FontWeight="Bold" Text="{Binding Name}" />
            </Grid>
        </HierarchicalDataTemplate>
        <Style TargetType="{x:Type TreeViewItem}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type TreeViewItem}">
                        <Canvas>
                            <ContentPresenter x:Name="PART_Header" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" ContentSource="Header">
                                    <ContentPresenter.Style>
                                        <Style TargetType="ContentPresenter">
                                            <Setter Property="Canvas.Left" Value="{Binding Path=X}" />
                                            <Setter Property="Canvas.Top" Value="{Binding Path=Y}" />
                                        </Style>
                                    </ContentPresenter.Style>
                                </ContentPresenter>      
                            <ItemsPresenter/>
                        </Canvas>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </TreeView.Resources>           
</TreeView>

您在此处为 ItemTemplate 设置样式,将 ContentPresenter 设置为 Canvas 和 HierarichalDataTemplate,以使您的 dataTemplate 看起来像带有一些文本的矩形。

这是我使用的模型:

public class Component
{
    public Component() { }
    public ObservableCollection<Component> ComponentsToDraw { set; get; } = new ObservableCollection<Component>();
    public double X { set; get; }
    public double Y { set; get; }
    public double Width { set; get; }
    public double Height { set; get; }
    public Brush Color { set; get; }
    public string Name { set; get; }
}

而且,在 ViewModel 中,您也制作了控件,您可以编写如下内容:

var Solution = new Component() { X = 0, Y = 0, Height = 300, Width = 500, Name = "Solution", Color = new SolidColorBrush(Colors.White)};
var PC = new Component() { X = 0, Y = 0, Height = 300, Width = 245, Name = "PC", Color = new SolidColorBrush(Colors.LightBlue) };
var PC2 = new Component() { X = 255, Y = 0, Height = 195, Width = 245, Name = "PC2", Color = new SolidColorBrush(Colors.LightBlue) };
var SubDrawingComponent = new Component() { X = 50, Y = 50, Height = 200, Width = 150, Name = "Drawing Component", Color = new SolidColorBrush(Colors.GreenYellow) };
var DrawingComponent = new Component() { X = 255, Y = 205, Height = 42.5, Width = 245, Name = "Drawing Component", Color = new SolidColorBrush(Colors.GreenYellow) };
var DrawingComponent2 = new Component() { X = 255, Y = 257.5, Height = 42.5, Width = 200, Name = "Drawing Component2", Color = new SolidColorBrush(Colors.GreenYellow) };
Solution.ComponentsToDraw.Add(PC);
Solution.ComponentsToDraw.Add(PC2);
Solution.ComponentsToDraw.Add(DrawingComponent);
Solution.ComponentsToDraw.Add(DrawingComponent2);
PC.ComponentsToDraw.Add(SubDrawingComponent);
ComponentsToDraw.Add(Solution);

对于Drawing Component 中的每个项目,您声明X 和Y,它们是相对于它的父项。 这是它的外观:

我知道,我用 PascalCase 写了一些字段,对此感到抱歉:D

【讨论】:

  • 我会尽快尝试您的解决方案:)
  • 几乎完美。但由于某种原因,我无法让 z 索引工作。子组件隐藏在其父组件后面
  • 您确定设置正确吗?我的意思是,对于孩子,父母 ZIndex +=1?
  • 您可以复制粘贴该代码,甚至将其粘贴到主窗口中的空应用程序中,然后查看它在屏幕上的工作方式,仅此而已
  • @smok,我现在检查了,即使没有 Z.Index 也可以,我更新了答案以删除它。
猜你喜欢
  • 1970-01-01
  • 2021-03-04
  • 2012-12-28
  • 2018-07-29
  • 2013-03-09
  • 1970-01-01
  • 1970-01-01
  • 2010-09-23
  • 1970-01-01
相关资源
最近更新 更多