Я получил дополнительные доказательства того, что первая идея является наиболее правильной.Если вам нужна просто черная линия - решение довольно простое:
- Измените шаблон элемента управления диаграммы
- Добавьте манекен
LineSeries
, чтобы отобразить Легенду справа отchart.
Вот диаграмма:
<charting:Chart Grid.Row="1">
<charting:Chart.Series>
<charting:LineSeries ItemsSource="{Binding LineItems}" IndependentValuePath="Date" DependentValuePath="Value" />
<charting:LineSeries Title="Middle Line">
<charting:LineSeries.DataPointStyle>
<Style TargetType="Control">
<Setter Property="Background" Value="Black"/>
</Style>
</charting:LineSeries.DataPointStyle>
</charting:LineSeries>
</charting:Chart.Series>
<charting:Chart.Template>
<ControlTemplate TargetType="charting:Chart">
<Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<datavis:Title Content="{TemplateBinding Title}" Style="{TemplateBinding TitleStyle}" />
<Grid Grid.Row="1" Margin="0,15,0,15">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<datavis:Legend x:Name="Legend" Header="{TemplateBinding LegendTitle}" Style="{TemplateBinding LegendStyle}" Grid.Column="1" />
<chartingprimitives:EdgePanel x:Name="ChartArea" Style="{TemplateBinding ChartAreaStyle}">
<Grid Canvas.ZIndex="-1" Style="{TemplateBinding PlotAreaStyle}" />
<Border Canvas.ZIndex="10" BorderBrush="#FF919191" BorderThickness="1" />
<local:LineControl Canvas.ZIndex="11"/>
</chartingprimitives:EdgePanel>
</Grid>
</Grid>
</Border>
</ControlTemplate>
</charting:Chart.Template>
</charting:Chart>
Содержит LineControl
внутри шаблона управления, это UserControl
со следующим кодом:
LineControl.xaml
<Line x:Name="line" Stroke="Black" StrokeThickness="2" />
LineControl.xaml.cs
public LineControl()
{
InitializeComponent();
this.SizeChanged += new SizeChangedEventHandler(LineControl_SizeChanged);
}
void LineControl_SizeChanged(object sender, SizeChangedEventArgs e)
{
this.line.Y1 = this.ActualHeight;
this.line.X2 = this.ActualWidth;
}
Преимущества этого решения:
- работает с любыми типами осей
- автоматически перерисовывается при изменении элементов данных или осей.
Другое решение - использование поведения.Диаграмма XAML имеет несколько изменений: я добавил поведение и удалил UserControl
и среднюю линию LineSeries
<chartingprimitives:EdgePanel x:Name="ChartArea" Style="{TemplateBinding ChartAreaStyle}">
<i:Interaction.Behaviors>
<local:DiagonalLineBehavior/>
</i:Interaction.Behaviors>
Класс поведения:
public class DiagonalLineBehavior : Behavior<EdgePanel>
{
private DateTimeAxis xAxis;
private LinearAxis yAxis;
public Brush LineColor { get; set; }
public DiagonalLineBehavior()
{
if (this.LineColor == null)
this.LineColor = new SolidColorBrush(Color.FromArgb(255, 0, 0, 0));
}
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.Loaded += new RoutedEventHandler(AssociatedObject_Loaded);
}
void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
{
xAxis = this.AssociatedObject.Children.OfType<DateTimeAxis>().FirstOrDefault(ax => ax.Orientation == AxisOrientation.X);
yAxis = this.AssociatedObject.Children.OfType<LinearAxis>().FirstOrDefault(ax => ax.Orientation == AxisOrientation.Y);
if (xAxis == null || yAxis == null)
return;
this.UpdateLine();
}
private void UpdateLine()
{
//Collection with two items: start point and end point
var lineSource = new[] {
new ChartPointModel(xAxis.ActualMinimum, yAxis.ActualMinimum),
new ChartPointModel(xAxis.ActualMaximum, yAxis.ActualMaximum) };
//This code creates a line with many intermediate points
//var pointCount = (int)Math.Ceiling(((TimeSpan)(xAxis.ActualMaximum - xAxis.ActualMinimum)).TotalDays/xAxis.ActualInterval);
//var yInterval = (yAxis.ActualMaximum - yAxis.ActualMinimum).Value / (double)pointCount;
//var lineSource = Enumerable.Range(0, pointCount)
// .Select(i => new ChartPointModel(xAxis.ActualMinimum.Value.AddDays(xAxis.ActualInterval * i), yAxis.ActualMinimum + yInterval * i))
// .ToList();
var chart = GetParent<Chart>(this.AssociatedObject);
//Style with hidden markers and some color
var emptyDataPointStyle = new Style(typeof(DataPoint));
emptyDataPointStyle.Setters.Add(new Setter(DataPoint.OpacityProperty, 0));
emptyDataPointStyle.Setters.Add(new Setter(DataPoint.BackgroundProperty, this.LineColor));
//Line series
chart.Series.Insert(0, new LineSeries()
{
ItemsSource = lineSource,
Title = "Middle Line",
IndependentValuePath = "X",
DependentValuePath = "Y",
DataPointStyle = emptyDataPointStyle
});
}
protected override void OnDetaching()
{
base.OnDetaching();
this.AssociatedObject.Loaded -= AssociatedObject_Loaded;
}
private T GetParent<T>(DependencyObject d) where T : DependencyObject
{
if (d == null)
return null;
var parent = VisualTreeHelper.GetParent(d);
if (parent != null && parent is T)
return (T)parent;
else return GetParent<T>(parent);
}
public class ChartPointModel : DependencyObject
{
public ChartPointModel(DateTime? x, double? y)
{
this.X = x;
this.Y = y;
}
public DateTime? X { get; set; }
public double? Y { get; set; }
}
}
Преимущество только одно:строка действительна и имеет те же свойства, что и DataSeries.Но для этого требуется гораздо больше кода, с каждой стороны имеются пустые места, тесно связанные с типом диаграммы, и он не изменяется после первого появления.
Так что попробуйте первое решение, а если нетчто вы ожидаете - я попытаюсь что-то сделать со вторым решением.