开发者

How to draw a vector graphic within each WPF ListBoxItem at run-time?

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: http://i.stack.imgur.com/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>

              <开发者_StackOverflow中文版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>


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.


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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜