如何在运行时在每个 WPF ListBoxItem 中绘制矢量图形?

发布于 2024-10-31 04:57:51 字数 3278 浏览 4 评论 0原文

我想在 WPF ListBoxItem 中绘制基于矢量的图形。 2D 形状非常简单,例如直线或正方形/矩形。但形状和颜色在编译时都是未知的,因此它不可能是图像。

示例屏幕截图: https://i.sstatic.net/EisIQ.jpg (我的微薄代表阻止我内联发布图像...)

我相信这应该可以通过 WPF 实现?如果是这样,怎么可能涉及 Canvas 和 Rectangle 元素?

非常感谢!

编辑

我似乎只找到了向 ListBoxItems 添加图像的各种示例,所以我没有真正深入研究。感谢下面的答案让我顺利起步。

XAML 使用两个 DataTemplate 和一个模板选择器声明,该选择器根据数据选择正确的模板。颜色也与数据绑定(名为LayerColor的属性)

<UserControl.Resources>
    <!-- to convert the color -->
    <src:ColorBrushConverter x:Key="colorConverter"/>
    <!-- to select the correct template based on geom type -->
    <src:LayerListDataTemplateSelector x:Key="layerDataTemplateSelector"/>
    <DataTemplate x:Key="lineLayerTemplate">
        <Border BorderThickness="0" BorderBrush="Gray"
               Padding="5" Name="border" Margin="1" >
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="50"/>
                    <ColumnDefinition />
                </Grid.ColumnDefinitions>

                <Line Margin="5,0,5,0" Height="16"
                 X1="1" Y1="8"
                 X2="35" Y2="8"
                 Stroke="{Binding Path=LayerColor, Converter={StaticResource colorConverter}}"
                 StrokeThickness="2"/>

                <TextBlock Grid.Row="0" Grid.Column="1" Margin="5,0,0,0"
                           Name="layerName" Text="{Binding Path=LayerName}"/>
            </Grid>
        </Border>
    </DataTemplate>
    <DataTemplate x:Key="pointLayerTemplate">
        <Border BorderThickness="0" BorderBrush="Gray"
                Padding="5" Name="border" Margin="1" >
            <Grid>
              <Grid.RowDefinitions>
                <RowDefinition/>
              </Grid.RowDefinitions>
              <Grid.ColumnDefinitions>
                <ColumnDefinition Width="50"/>
                <ColumnDefinition />
              </Grid.ColumnDefinitions>

              <Polygon Grid.Row="0" Grid.Column="0" Margin="5,0,10,0"
                         Fill="{Binding Path=LayerColor, Converter={StaticResource colorConverter}}" 
                         Stroke="Black" StrokeThickness="1"
                         StrokeLineJoin="Round" Width="16" Height="16"
                         Stretch="Fill"
                         Points="8,1 1,8 8,15 15,8 8,1"
                         Visibility="Visible"  Name="diamond"/>

               <TextBlock Grid.Row="0" Grid.Column="1" Margin="5,0,0,0"
                           Name="layerName" Text="{Binding Path=LayerName}"/>
            </Grid>
        </Border>    
    </DataTemplate>
</UserControl.Resources>
<Grid>
    <ListBox x:Name="layerListBox" HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch"
             ItemTemplateSelector="{StaticResource layerDataTemplateSelector}">
    </ListBox>
</Grid>

I would like draw a vector-based graphic within a WPF ListBoxItem. The 2D shapes are very simple, line or square/rectangle, for example. But neither the shapes nor the colors are known at compile-time so it can't be an Image.

Sample screen shot: https://i.sstatic.net/EisIQ.jpg (My meager rep prevents me from posting the image inline...)

I believe this should be possible with WPF? If so how, perhaps involving Canvas and Rectangle elements?

Many thanks in advance!

EDIT

I was thrown off by seemingly only finding various examples of adding images to ListBoxItems, so I hadn't really dug in. Thanks to the below answer for getting me off on the right foot.

XAML using two DataTemplates and a declaration of a template selector which selects the correct template based on the data. Color too is bound to the data (a property called LayerColor)

<UserControl.Resources>
    <!-- to convert the color -->
    <src:ColorBrushConverter x:Key="colorConverter"/>
    <!-- to select the correct template based on geom type -->
    <src:LayerListDataTemplateSelector x:Key="layerDataTemplateSelector"/>
    <DataTemplate x:Key="lineLayerTemplate">
        <Border BorderThickness="0" BorderBrush="Gray"
               Padding="5" Name="border" Margin="1" >
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="50"/>
                    <ColumnDefinition />
                </Grid.ColumnDefinitions>

                <Line Margin="5,0,5,0" Height="16"
                 X1="1" Y1="8"
                 X2="35" Y2="8"
                 Stroke="{Binding Path=LayerColor, Converter={StaticResource colorConverter}}"
                 StrokeThickness="2"/>

                <TextBlock Grid.Row="0" Grid.Column="1" Margin="5,0,0,0"
                           Name="layerName" Text="{Binding Path=LayerName}"/>
            </Grid>
        </Border>
    </DataTemplate>
    <DataTemplate x:Key="pointLayerTemplate">
        <Border BorderThickness="0" BorderBrush="Gray"
                Padding="5" Name="border" Margin="1" >
            <Grid>
              <Grid.RowDefinitions>
                <RowDefinition/>
              </Grid.RowDefinitions>
              <Grid.ColumnDefinitions>
                <ColumnDefinition Width="50"/>
                <ColumnDefinition />
              </Grid.ColumnDefinitions>

              <Polygon Grid.Row="0" Grid.Column="0" Margin="5,0,10,0"
                         Fill="{Binding Path=LayerColor, Converter={StaticResource colorConverter}}" 
                         Stroke="Black" StrokeThickness="1"
                         StrokeLineJoin="Round" Width="16" Height="16"
                         Stretch="Fill"
                         Points="8,1 1,8 8,15 15,8 8,1"
                         Visibility="Visible"  Name="diamond"/>

               <TextBlock Grid.Row="0" Grid.Column="1" Margin="5,0,0,0"
                           Name="layerName" Text="{Binding Path=LayerName}"/>
            </Grid>
        </Border>    
    </DataTemplate>
</UserControl.Resources>
<Grid>
    <ListBox x:Name="layerListBox" HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch"
             ItemTemplateSelector="{StaticResource layerDataTemplateSelector}">
    </ListBox>
</Grid>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

云雾 2024-11-07 04:57:51

首先要确定的是关于应该绘制什么的知识位于何处。

如果可以预先绘制所有可能的绘图,则可以将它们放入数据模板中,并将颜色、画笔和大小等内容绑定到正在显示的数据。

然后使用项目模板选择器根据数据选择正确的数据模板。

如果绘图来自数据库,您可能需要将它们作为资源加载,并将数据模板中的图像绑定到加载位图。

总而言之,在采用 C# 代码方式之前尝试使用模板和绑定,因为此类代码比数据模板更难维护。

The first thing to determine is where the knowledge resides about what should be drawn.

If all possible drawings can be drawn upfront you put them in data templates and bind things like colors, brushes and sizes to the data that is being displayed.

Then use an item template selector to select the correct datatemplate based on the data.

If the drawings are coming out of a database you might need to load them as resources and bind an image in the data template to a load bitmap.

All in all, try to use templates and bindings before going the C# code way because such code is much harder to maintain than a datatemplate.

泅人 2024-11-07 04:57:51

您可以使用基于类型的 DataTemplate 或基于模型上某些属性的 DataTemplateSelector。以下是使用数据类型来确定在数据旁边绘制什么内容的粗略示例。

<ListBox>
  <ListBox.Resources>
    <DataTemplate DataType="{x:Type sys:Int32}">
      <StackPanel Orientation="Horizontal">
        <Rectangle Fill="Blue" Height="5" Width="5"/>
        <TextBlock Text="{Binding}" Margin="4,0,0,0"/>
      </StackPanel>
    </DataTemplate>
    <DataTemplate DataType="{x:Type sys:String}">
      <StackPanel Orientation="Horizontal">
        <Rectangle Fill="Cyan" Height="2" Width="6"/>
        <TextBlock Text="{Binding}" Margin="4,0,0,0"/>
      </StackPanel>
    </DataTemplate>
  </ListBox.Resources>
  <sys:Int32>1</sys:Int32>
  <sys:String>testing testing 1 2 3</sys:String>
</ListBox>

You can use DataTemplates based on types or a DataTemplateSelector based on some property on a model. The following is a crude example of using the type of the data to determine what to draw next to the data.

<ListBox>
  <ListBox.Resources>
    <DataTemplate DataType="{x:Type sys:Int32}">
      <StackPanel Orientation="Horizontal">
        <Rectangle Fill="Blue" Height="5" Width="5"/>
        <TextBlock Text="{Binding}" Margin="4,0,0,0"/>
      </StackPanel>
    </DataTemplate>
    <DataTemplate DataType="{x:Type sys:String}">
      <StackPanel Orientation="Horizontal">
        <Rectangle Fill="Cyan" Height="2" Width="6"/>
        <TextBlock Text="{Binding}" Margin="4,0,0,0"/>
      </StackPanel>
    </DataTemplate>
  </ListBox.Resources>
  <sys:Int32>1</sys:Int32>
  <sys:String>testing testing 1 2 3</sys:String>
</ListBox>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文