为什么我的 2 个 Livecharts 笛卡尔实例不起作用?
Why my 2 instances of Livecharts cartesian not working?
我目前的代码有问题。
基本上我需要在我的应用程序的一个网格中显示 2 个图表,但它似乎不起作用。
问题是一张图会显示,而第二张图不会绘制。
下面是使用的代码:
XAML:
<Grid>
<lvc:CartesianChart x:Name="cartchartdb" Series="{Binding SeriesCollection}" LegendLocation="Right" Margin="10,249,578.4,218.2" >
<lvc:CartesianChart.AxisY>
<lvc:Axis Title="Average Gap (Meter)" LabelFormatter="{Binding YFormatter}"></lvc:Axis>
</lvc:CartesianChart.AxisY>
<lvc:CartesianChart.AxisX>
<lvc:Axis Title="Time" Labels="{Binding Labels}"></lvc:Axis>
</lvc:CartesianChart.AxisX>
</lvc:CartesianChart>
</Grid>
<Grid>
<lvc:CartesianChart Series="{Binding SeriesCollection2}" LegendLocation="Right" Margin="792,160,9.8,238" >
<lvc:CartesianChart.AxisY>
<lvc:Axis Title="Sales" LabelFormatter="{Binding YFormatter2}"></lvc:Axis>
</lvc:CartesianChart.AxisY>
<lvc:CartesianChart.AxisX>
<lvc:Axis Title="Month" Labels="{Binding Labels2}"></lvc:Axis>
</lvc:CartesianChart.AxisX>
</lvc:CartesianChart>
</Grid>
C#:
public MainWindow(){
cartchartinit();
cartchartinit2();
}
private void cartchartinit2()
{
SeriesCollection2 = new SeriesCollection
{
new LineSeries
{
Title = "Series 1",
Values = new ChartValues<double> { 4, 6, 5, 2 ,7 }
},
new LineSeries
{
Title = "Series 2",
Values = new ChartValues<double> { 6, 7, 3, 4 ,6 }
}
};
Labels2 = new[] { "Jan", "Feb", "Mar", "Apr", "May" };
YFormatter2 = value => value.ToString("C");
//modifying the series collection will animate and update the chart
SeriesCollection2.Add(new LineSeries
{
Values = new ChartValues<double> { 5, 3, 2, 4 },
LineSmoothness = 0 //straight lines, 1 really smooth lines
});
//modifying any series values will also animate and update the chart
SeriesCollection2[2].Values.Add(5d);
DataContext = this;
}
public SeriesCollection SeriesCollection2 { get; set; }
public string[] Labels2 { get; set; }
public Func<double, string> YFormatter2 { get; set; }
private void cartchartinit()
{
SeriesCollection = new SeriesCollection
{
new LineSeries
{
Title = "Average Vehicles Gap",
Values = null
},
/* new LineSeries
{
Title = "Avg Gap (Metre)",
Values = null
},*/
/*new LineSeries
{
Title = "Series 3",
Values = new ChartValues<double> { 4,2,7,2,7 },
PointGeometry = DefaultGeometries.Square,
PointGeometrySize = 15
}*/
};
Labels = null;
YFormatter = value => value.ToString("");
DataContext = this;
}
public SeriesCollection SeriesCollection { get; set; }
public string[] Labels { get; set; }
public Func<double, string> YFormatter { get; set; }
当我只使用 cartchartinit() 方法时,它起作用了。但是当我添加 cartchartinit2() 时,它只会为后面的图表绘制图形。我做错了吗?
将不胜感激。
谢谢
第一个图表是空的,因为绑定源也是如此。
你评论了 SeriesCollection
属性 的初始化,并将唯一系列项目的 LineSeries.Values
属性 设置为 null
==> 这里没有数据集显示。您还遇到 属性 更改未报告给绑定引擎的问题。
您的代码存在几个问题。解决最重要的问题:
布局
不要将每个控件包装成 Grid
。
这只会增加渲染性能成本。包装网格绝对是多余的。 Grid
是一个布局 Panel
,但目前您没有使用它来排列元素。
不要使用 Margin
来定位您的网格。
这不允许您的应用程序缩放,并且基于边距的布局实施起来很麻烦。
如果您需要绝对定位,请使用 Canvas
。如果您需要相对定位,请使用 Panel
,例如 Grid
,例如用于基于列和行的布局或 StackPanel
用于简单的垂直或水平排列的元素。
仅使用 Margin
进行小的调整,最好调整到它们的相对屏幕位置。
从页边空白看,您希望图表显示为两行两列(从左上角到右下角的对角线)。在这种情况下使用 Grid
:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<lvc:CartesianChart Grid.Row="0" Grid.Column="0"
Series="{Binding SeriesCollection}"
LegendLocation="Right">
...
</lvc:CartesianChart>
<lvc:CartesianChart Grid.Row="1" Grid.Column="1"
Series="{Binding SeriesCollection2}"
LegendLocation="Right">
...
</lvc:CartesianChart>
</Grid>
如果您想将图表彼此对齐,只需使用 StackPanel
:
<StackPanel Orientation="Horizontal">
<lvc:CartesianChart Series="{Binding SeriesCollection}"
LegendLocation="Right">
...
</lvc:CartesianChart>
<lvc:CartesianChart Series="{Binding SeriesCollection2}"
LegendLocation="Right">
...
</lvc:CartesianChart>
</StackPanel>
数据绑定
您使用数据绑定将图表数据分配给图表。那很好。
但是在 初始化 XAML 绑定表达式之后,您正在设置绑定源 。由于您的所有源属性(例如 SeriesCollection
和 SeriesCollection2
既不是 DependencyProperty
也不会引发 INotifyPropertyChanged.PropertyChanged
事件,因此这些属性中的 changes/assignments 不会被绑定引擎。在你的情况下它有效,但只是因为你在每次 属性 更改后由 re-assigning this.DataContext = this
刷新 Binding.Source
。
这将强制您视图中的每个绑定再次初始化。
在更复杂的应用程序中,这将显着增加启动时间或导致缓慢 UI。
默认情况下,WPF 沿可视化树继承 DataContext
属性 值(有例外,例如 DataTemplate
):每个子元素隐式共享其父元素的相同 DataContext
。
这意味着刷新此 属性 会影响完整的可视化树! ==> 不要仅仅因为 Binding.Path
更新了就刷新 Binding.Source
(尤其是 DataContext
)。
让绑定引擎处理这些更改:
每当绑定的源 属性 预计会动态更改时,源对象必须将这些属性实现为 DependencyProperty
或者如果此对象不是 DependencyObject
,则必须实施 INotifyPropertyChanged
.
见Data binding overview in WPF and Dependency properties overview
Window
是一个 DependencyObject
,因此 MainWindow
应该将所有用作绑定源或绑定目标的属性实现为 DependencyProerty
:
partial class MainWindow : Window
{
public static readonly DependencyProperty SeriesCollectionProperty = DependencyProperty.Register(
"SeriesCollection",
typeof(SeriesCollection),
typeof(MainWindow),
new PropertyMetadata(default(SeriesCollection)));
public SeriesCollection SeriesCollection
{
get => (SeriesCollection) GetValue(MainWindow.SeriesCollectionProperty);
set => SetValue(MainWindow.SeriesCollectionProperty, value);
}
public static readonly DependencyProperty SeriesCollection2Property = DependencyProperty.Register(
"SeriesCollection2",
typeof(SeriesCollection),
typeof(MainWindow),
new PropertyMetadata(default(SeriesCollection)));
public SeriesCollection SeriesCollection2
{
get => (SeriesCollection) GetValue(MainWindow.SeriesCollection2Property);
set => SetValue(MainWindow.SeriesCollection2Property, value);
}
... // Do this for all properties that serve as binding source or target
public MainwWindow()
{
InitializeComponent();
this.DataContext = this;
}
private void cartchartinit()
{
// Aside from their slightly clumsy definition,
// dependency properties are used like common CLR properties
SeriesCollection = new SeriesCollection();
}
}
我目前的代码有问题。
基本上我需要在我的应用程序的一个网格中显示 2 个图表,但它似乎不起作用。 问题是一张图会显示,而第二张图不会绘制。
下面是使用的代码:
XAML:
<Grid>
<lvc:CartesianChart x:Name="cartchartdb" Series="{Binding SeriesCollection}" LegendLocation="Right" Margin="10,249,578.4,218.2" >
<lvc:CartesianChart.AxisY>
<lvc:Axis Title="Average Gap (Meter)" LabelFormatter="{Binding YFormatter}"></lvc:Axis>
</lvc:CartesianChart.AxisY>
<lvc:CartesianChart.AxisX>
<lvc:Axis Title="Time" Labels="{Binding Labels}"></lvc:Axis>
</lvc:CartesianChart.AxisX>
</lvc:CartesianChart>
</Grid>
<Grid>
<lvc:CartesianChart Series="{Binding SeriesCollection2}" LegendLocation="Right" Margin="792,160,9.8,238" >
<lvc:CartesianChart.AxisY>
<lvc:Axis Title="Sales" LabelFormatter="{Binding YFormatter2}"></lvc:Axis>
</lvc:CartesianChart.AxisY>
<lvc:CartesianChart.AxisX>
<lvc:Axis Title="Month" Labels="{Binding Labels2}"></lvc:Axis>
</lvc:CartesianChart.AxisX>
</lvc:CartesianChart>
</Grid>
C#:
public MainWindow(){
cartchartinit();
cartchartinit2();
}
private void cartchartinit2()
{
SeriesCollection2 = new SeriesCollection
{
new LineSeries
{
Title = "Series 1",
Values = new ChartValues<double> { 4, 6, 5, 2 ,7 }
},
new LineSeries
{
Title = "Series 2",
Values = new ChartValues<double> { 6, 7, 3, 4 ,6 }
}
};
Labels2 = new[] { "Jan", "Feb", "Mar", "Apr", "May" };
YFormatter2 = value => value.ToString("C");
//modifying the series collection will animate and update the chart
SeriesCollection2.Add(new LineSeries
{
Values = new ChartValues<double> { 5, 3, 2, 4 },
LineSmoothness = 0 //straight lines, 1 really smooth lines
});
//modifying any series values will also animate and update the chart
SeriesCollection2[2].Values.Add(5d);
DataContext = this;
}
public SeriesCollection SeriesCollection2 { get; set; }
public string[] Labels2 { get; set; }
public Func<double, string> YFormatter2 { get; set; }
private void cartchartinit()
{
SeriesCollection = new SeriesCollection
{
new LineSeries
{
Title = "Average Vehicles Gap",
Values = null
},
/* new LineSeries
{
Title = "Avg Gap (Metre)",
Values = null
},*/
/*new LineSeries
{
Title = "Series 3",
Values = new ChartValues<double> { 4,2,7,2,7 },
PointGeometry = DefaultGeometries.Square,
PointGeometrySize = 15
}*/
};
Labels = null;
YFormatter = value => value.ToString("");
DataContext = this;
}
public SeriesCollection SeriesCollection { get; set; }
public string[] Labels { get; set; }
public Func<double, string> YFormatter { get; set; }
当我只使用 cartchartinit() 方法时,它起作用了。但是当我添加 cartchartinit2() 时,它只会为后面的图表绘制图形。我做错了吗?
将不胜感激。
谢谢
第一个图表是空的,因为绑定源也是如此。
你评论了 SeriesCollection
属性 的初始化,并将唯一系列项目的 LineSeries.Values
属性 设置为 null
==> 这里没有数据集显示。您还遇到 属性 更改未报告给绑定引擎的问题。
您的代码存在几个问题。解决最重要的问题:
布局
不要将每个控件包装成 Grid
。
这只会增加渲染性能成本。包装网格绝对是多余的。 Grid
是一个布局 Panel
,但目前您没有使用它来排列元素。
不要使用 Margin
来定位您的网格。
这不允许您的应用程序缩放,并且基于边距的布局实施起来很麻烦。
如果您需要绝对定位,请使用 Canvas
。如果您需要相对定位,请使用 Panel
,例如 Grid
,例如用于基于列和行的布局或 StackPanel
用于简单的垂直或水平排列的元素。
仅使用 Margin
进行小的调整,最好调整到它们的相对屏幕位置。
从页边空白看,您希望图表显示为两行两列(从左上角到右下角的对角线)。在这种情况下使用 Grid
:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<lvc:CartesianChart Grid.Row="0" Grid.Column="0"
Series="{Binding SeriesCollection}"
LegendLocation="Right">
...
</lvc:CartesianChart>
<lvc:CartesianChart Grid.Row="1" Grid.Column="1"
Series="{Binding SeriesCollection2}"
LegendLocation="Right">
...
</lvc:CartesianChart>
</Grid>
如果您想将图表彼此对齐,只需使用 StackPanel
:
<StackPanel Orientation="Horizontal">
<lvc:CartesianChart Series="{Binding SeriesCollection}"
LegendLocation="Right">
...
</lvc:CartesianChart>
<lvc:CartesianChart Series="{Binding SeriesCollection2}"
LegendLocation="Right">
...
</lvc:CartesianChart>
</StackPanel>
数据绑定
您使用数据绑定将图表数据分配给图表。那很好。
但是在 初始化 XAML 绑定表达式之后,您正在设置绑定源 。由于您的所有源属性(例如 SeriesCollection
和 SeriesCollection2
既不是 DependencyProperty
也不会引发 INotifyPropertyChanged.PropertyChanged
事件,因此这些属性中的 changes/assignments 不会被绑定引擎。在你的情况下它有效,但只是因为你在每次 属性 更改后由 re-assigning this.DataContext = this
刷新 Binding.Source
。
这将强制您视图中的每个绑定再次初始化。
在更复杂的应用程序中,这将显着增加启动时间或导致缓慢 UI。
默认情况下,WPF 沿可视化树继承 DataContext
属性 值(有例外,例如 DataTemplate
):每个子元素隐式共享其父元素的相同 DataContext
。
这意味着刷新此 属性 会影响完整的可视化树! ==> 不要仅仅因为 Binding.Path
更新了就刷新 Binding.Source
(尤其是 DataContext
)。
让绑定引擎处理这些更改:
每当绑定的源 属性 预计会动态更改时,源对象必须将这些属性实现为 DependencyProperty
或者如果此对象不是 DependencyObject
,则必须实施 INotifyPropertyChanged
.
见Data binding overview in WPF and Dependency properties overview
Window
是一个 DependencyObject
,因此 MainWindow
应该将所有用作绑定源或绑定目标的属性实现为 DependencyProerty
:
partial class MainWindow : Window
{
public static readonly DependencyProperty SeriesCollectionProperty = DependencyProperty.Register(
"SeriesCollection",
typeof(SeriesCollection),
typeof(MainWindow),
new PropertyMetadata(default(SeriesCollection)));
public SeriesCollection SeriesCollection
{
get => (SeriesCollection) GetValue(MainWindow.SeriesCollectionProperty);
set => SetValue(MainWindow.SeriesCollectionProperty, value);
}
public static readonly DependencyProperty SeriesCollection2Property = DependencyProperty.Register(
"SeriesCollection2",
typeof(SeriesCollection),
typeof(MainWindow),
new PropertyMetadata(default(SeriesCollection)));
public SeriesCollection SeriesCollection2
{
get => (SeriesCollection) GetValue(MainWindow.SeriesCollection2Property);
set => SetValue(MainWindow.SeriesCollection2Property, value);
}
... // Do this for all properties that serve as binding source or target
public MainwWindow()
{
InitializeComponent();
this.DataContext = this;
}
private void cartchartinit()
{
// Aside from their slightly clumsy definition,
// dependency properties are used like common CLR properties
SeriesCollection = new SeriesCollection();
}
}