用双线绘制椭圆线/折线

时间:2019-12-09 03:46:37

标签: wpf charts shapes

我一直在使用this示例来绘制条形图。条形部分已完成,它代表交易中的数量/数量。它是一个介于20到30之间的关联价格。我现在想要绘制点以表示与数量相关的价格并将这些点连接起来。我在链接示例的EDIT部分中进行了两项更改(1)从TextBlock的{​​{1}}中删除了DataTemplate,并添加了ItemsControl并编辑了(2)在画布上添加价格/体积轴标签。这是现在的样子:

enter image description here

如何在适当的位置添加Ellipse并将其与Ellipse / Line连接?

编辑

这就是我现在在PolyLine中遇到的事情:

ItemsControl

哦!我忘了添加那些ValueConverters,这是这些:

<ItemsControl ScrollViewer.CanContentScroll="True"
            Height="135"
            ItemsSource="{Binding RectCollection}"
            Margin="50 0 50 0">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Canvas Width="20">
                <Canvas.LayoutTransform>
                    <ScaleTransform ScaleY="-1"/>
                </Canvas.LayoutTransform>
                <Rectangle Width="18" 
                Margin="0 0 2 0" 
                VerticalAlignment="Bottom"
                Opacity=".5" Fill="LightGray">
                    <Rectangle.Height>
                        <MultiBinding Converter="{StaticResource VConverter}">
                            <Binding Path="ActualHeight"
                                    RelativeSource="{RelativeSource AncestorType=ItemsControl}"/>
                            <Binding Path="DataContext.HighestPoint"
                                    RelativeSource="{RelativeSource AncestorType=ItemsControl}"/>
                            <Binding Path="Volume"/>
                        </MultiBinding>
                    </Rectangle.Height>
                </Rectangle>

                <Line Stroke="DarkGreen" StrokeThickness="1"
                    X1="10" X2="30"
                    Y2="{Binding PreviousPrice, Converter={StaticResource PConverter}}"
                    Y1="{Binding CurrentPrice, Converter={StaticResource PConverter}}">
                    <Line.Style>
                        <Style TargetType="Line">
                            <Style.Triggers>
                                    <DataTrigger Binding="{Binding Path=PreviousPrice}" Value="{x:Null}">
                                    <Setter Property="Visibility" Value="Collapsed"/>
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </Line.Style>
                </Line>
                <Ellipse Fill="Red" Width="6" Height="6" Margin="-3" Canvas.Left="10"
                    Canvas.Top="{Binding CurrentPrice, Converter={StaticResource PConverter}}"/>
            </Canvas>
        </DataTemplate>
    </ItemsControl.ItemTemplate>

    <ItemsControl.Template>
        <ControlTemplate>
            <ScrollViewer
            VerticalScrollBarVisibility="Hidden"
            Background="{TemplateBinding Panel.Background}">
                <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
            </ScrollViewer>
        </ControlTemplate>
    </ItemsControl.Template>

    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

和它的样子:

enter image description here

根据public class VolumeConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { var height = (double)values[0]; var higest = (double)values[1]; var value = (double)values[2]; return value * height / higest; } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } public class PriceConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (!(value is double)) return null; var price = (double)value; var remainingHeight = 90; var priceRange = 30 - 20.0; return 45 + ((price - 20) * remainingHeight / priceRange); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } 的建议,如果在@Clemens上使用double?而不是Insert(0, ... )来添加{最后一项放在首位,并删除了ObservableCollection东西。

1 个答案:

答案 0 :(得分:1)

以下示例使用垂直翻转的Canvas反转y轴顺序,使其向上移动。因此PConverter应该返回正y值。

除了Rectangle和Ellipse元素外,它还通过值绑定中的Line从前一个数据值到当前值绘制了一个RelativeSource={RelativeSource PreviousData}元素。它还在AlternationIndex上使用DataTrigger来隐藏第一行。

<ItemsControl ... AlternationCount="2147483647">
...

<ItemsControl.ItemTemplate>
    <DataTemplate>
        <Canvas Width="20">
            <Canvas.LayoutTransform>
                <ScaleTransform ScaleY="-1"/>
            </Canvas.LayoutTransform>

            <Rectangle Fill="LightGray" Margin="1" Width="18"
                       Height="{Binding Value1, Converter={StaticResource PConverter}}"/>

            <Line Stroke="DarkGreen" StrokeThickness="3"
                  X1="-10" X2="10"
                  Y1="{Binding Price,
                       Converter={StaticResource PConverter},
                       RelativeSource={RelativeSource PreviousData}}"
                  Y2="{Binding Price,
                       Converter={StaticResource PConverter}}">
                <Line.Style>
                    <Style TargetType="Line">
                        <Style.Triggers>
                            <DataTrigger
                                Binding="{Binding Path=(ItemsControl.AlternationIndex),
                                    RelativeSource={RelativeSource
                                        AncestorType=ContentPresenter}}"
                                Value="0">
                                <Setter Property="Visibility" Value="Collapsed"/>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </Line.Style>
            </Line>

            <Ellipse Fill="Red" Width="6" Height="6" Margin="-3" Canvas.Left="10"
                     Canvas.Top="{Binding Price, Converter={StaticResource PConverter}}"/>
        </Canvas>
    </DataTemplate>
</ItemsControl.ItemTemplate>

由于现在还要求值转换器使用不存在的值(对于第一项的PreviousData),因此必须确保它检查传递的值是否实际上是双精度值:

public object Convert(
    object value, Type targetType, object parameter, CultureInfo culture)
{
    if (!(value is double)) return 0d;
    ...
}