我有一组数据点,它们存储X和Y值以及两个坐标:点本身和下一个点的像素位置。
然后我有一个ItemsControl,它绑定到集合并绘制一条线,将当前点连接到下一个点,形成存储在集合中的所有数据点的折线图。
<ItemsControl x:Name="GraphCanvas"
ItemsSource="{Binding LineChartData}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Canvas>
<Canvas.Resources>
<local:BindingProxy x:Key="proxy" Data="{Binding}" />
</Canvas.Resources>
<Path Stroke="Black" StrokeThickness="1">
<Path.Data>
<GeometryGroup>
<PathGeometry>
<PathFigure StartPoint="{Binding Source={StaticResource proxy}, Path=Data.CurrentPoint}">
<PathFigure.Segments>
<LineSegment Point="{Binding Source={StaticResource proxy}, Path=Data.NextPoint}"/>
</PathFigure.Segments>
</PathFigure>
</PathGeometry>
</GeometryGroup>
</Path.Data>
</Path>
</Canvas>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
一切正常但是我想知道是否有更好的方法来做到这一点,因为当我必须调整我的控制时,我必须遍历每个数据点并重新计算它们的当前点和下一个点,如下所示:
Point currentPoint;
Point nextPoint = getCanvasPoint(lineChartData[0]);
for (int i = 1; i < lineChartData.Count; i++)
{
var dataPoint = lineChartData[i];
currentPoint = nextPoint;
nextPoint = getCanvasPoint(dataPoint);
dataPoint.CurrentPoint = currentPoint;
dataPoint.NextPoint = nextPoint;
}
这是一个相当缓慢的过程,并使调整大小非常紧张。我想知道是否有更好的方法来绑定X&amp;列表Y值为itemscontrol,以便我可以在屏幕上绘制它们。
答案 0 :(得分:2)
我一直在使用MultiBinding。
在视图中,我绑定到:
<Grid x:Name="root" RenderTransformOrigin="0.5 0.5">
<Grid.RenderTransform>
<ScaleTransform ScaleY="-1"/>
</Grid.RenderTransform>
<Path Stroke="Brown" StrokeThickness="0.5"
Stretch="Fill"
StrokeEndLineCap="Round" StrokeLineJoin="Round">
<Path.Data>
<MultiBinding Converter="{StaticResource SinalToGeometryConverter}">
<Binding ElementName="root" Path="ActualWidth"/>
<Binding ElementName="root" Path="ActualHeight"/>
<Binding Path="Samples"/>
</MultiBinding>
</Path.Data>
</Path>
</Grid>
然后在转换器中我生成一个或多或少像这样的路径:
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Any(v => v == null) &&
values.Any(v => v == DependencyProperty.UnsetValue))
return null;
double viewportWidth = (double)values[0];
double viewportHeight = (double)values[1];
IEnumerable<int> samples= values[2] as IEnumerable<int>;
var sb = new StringBuilder("M");
int x_coord = 0; // could be taken from sample if available
foreach (var y_coord in samples)
sb.AppendFormat(" {0} {1}", x_coord++, y_coord);
var result = Geometry.Parse(sb.ToString());
return result;
}
然后,每当其中一个绑定的东西发生变化时,由于数据源更改或视口更改,您将获得一个全新的路径。如果数据点数少于plotterControl.ActualWidth
,则速度相对较快。
答案 1 :(得分:0)
我使用Clemens评论来构建我的解决方案就是我如何做到的:
我将PolyLineSegment的Points属性绑定到ViewModel中的点集合。然后我使用变换组来缩放和平移路径以适应轴。
以下是代码:
<Canvas Background="Transparent" Grid.Row="1" Grid.Column="2" x:Name="GraphCanvas">
<Path Stroke="Black" StrokeThickness="1">
<Path.Data>
<PathGeometry>
<PathGeometry.Transform>
<TransformGroup>
<ScaleTransform ScaleX="{Binding xScale}" ScaleY="{Binding yScale}"/>
<TranslateTransform Y="{Binding yAxisTranslation}"/>
</TransformGroup>
</PathGeometry.Transform>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure StartPoint="{Binding FirstPoint}">
<PathFigure.Segments>
<PathSegmentCollection>
<PolyLineSegment Points="{Binding Points}"/>
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
<Path Stroke="Black" StrokeThickness="1">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure StartPoint="0,0">
<LineSegment Point="{Binding OriginPoint}"/>
<LineSegment Point="{Binding xAxisEndPoint}"/>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
</Canvas>
我真的很喜欢这个解决方案,它似乎比原始代码快得多,特别是在调整大小时。