这个问题折腾我跨一周了,请路过的朋友帮帮我:
下面是UserControl中的前端代码:
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<lvc:CartesianChart>
<lvc:CartesianChart.Series>
<lvc:LineSeries Values="{Binding RelativeSource={RelativeSource AncestorType=UserControl, Mode=FindAncestor},Path=Values}"/>
</lvc:CartesianChart.Series>
<lvc:CartesianChart.AxisX>
<lvc:Axis MinValue="0"/>
</lvc:CartesianChart.AxisX>
<lvc:CartesianChart.AxisY>
<lvc:Axis MinValue="0" MaxValue="1"/>
</lvc:CartesianChart.AxisY>
</lvc:CartesianChart>
<ListBox Grid.Row="1" ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=UserControl, Mode=FindAncestor},Path=Values}"/>
</Grid>
下面是UserControl中的后端代码:
public List<double> Values
{
get { return (List<double>)GetValue(ValuesProperty); }
set { SetValue(ValuesProperty, value); }
}
// Using a DependencyProperty as the backing store for Values. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ValuesProperty =
DependencyProperty.Register("Values", typeof(List<double>), typeof(UserControl1),
new PropertyMetadata(new List<double>()));
public UserControl1()
{
InitializeComponent();
}
下面是MainView中的前端代码:
<Grid>
<StackPanel>
<local:UserControl1 x:Name="control" MinHeight="400"/>
</StackPanel>
</Grid>
下面是MainView中的后端代码:
InitializeComponent();
Random random = new Random(Guid.NewGuid().GetHashCode());
Task.Run(async() =>
{
while (true)
{
List<double> values = new List<double>();
values.Add(random.NextDouble());
values.Add(random.NextDouble());
values.Add(random.NextDouble());
values.Add(random.NextDouble());
values.Add(random.NextDouble());
Dispatcher.Invoke(() =>
{
control.SetValue(UserControl1.ValuesProperty, values);
});
await Task.Delay(1000);
}
});
问题是:
1,listBxo中,数据是按照每秒一次在随机刷新,但是LiveChart中没有任何变化,这是说明问题呢?
2,另外,在编辑ueserControl的xaml的时候,VS提示“组件“LiveCharts.Wpf.DefaultLegend”不具有由 URI“/LiveCharts.Wpf;component/defaultlegend.xaml”识别的资源”,预览不显示,但是不影响运行,这是什么问题呢?
//ChartControl Memory Leak using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Media; using System.Windows.Threading; using L.Bussiness.Services; using L.Bussiness.画布图元s.读显s.Parts.Charts; using L.Bussiness.设置面板s; using L.CommonCtrls; using L.CommonCtrls.Converters; using L.LModules.Utils; using L.LModules.ViewUtils; using LiveCharts; using LiveCharts.Defaults; using LiveCharts.Definitions.Series; using LiveCharts.Wpf; using LiveCharts.Wpf.Charts.Base; using PropertyChanged; using PropertyTools.DataAnnotations; using PropertyTools.Wpf; namespace L.Bussiness.画布图元s.读显s { public class Primitive图表读取器3 : PrimitivePathBindBase { public class ChartLineBean : IMetric { public string DevAddress { get; set; } [Filed()] [AutoUpdateText] [System.ComponentModel.Category("曲线|基本设置")] [System.ComponentModel.DisplayName("颜色设置")] public Color Color { get; set; } = Colors.Transparent; [Filed()] [AutoUpdateText] [System.ComponentModel.Category("曲线|基本设置")] [System.ComponentModel.DisplayName("曲率0-1")] public bool LineSmoothness { get; set; } [Filed()] public string Path { get; set; } [Filed()] public RwModel RwModel { get; set; } public IConvertible Value { get; set; } public ISeriesView SeriesView { get; set; } } private DispatcherTimer _dispatcherTimerInterval; private DispatcherTimer _dispatcherTimerChart; [Filed] [DoNotCheckEquality] [AutoUpdateText] [SortIndex(10)] [HeaderPlacement(HeaderPlacement.Above)] [CtrlType(CtrlCategory.ChartList)] [Height(160)] [System.ComponentModel.Category("图表相关|基本")] [System.ComponentModel.DisplayName("绑定列表")] [System.ComponentModel.Description("部分支持多个.")] public override ObservableCollection<IMetric> Metrics { get; } = new ObservableCollection<IMetric>(); [Filed(true)] [DoNotCheckEquality] [AutoUpdateText] [SortIndex(3560)] [System.ComponentModel.Category("图表相关|基本")] [System.ComponentModel.DisplayName("动画效果")] [System.ComponentModel.Description("会影响性能.")] public virtual bool CanAnimations { get => _canAnimations; set { _canAnimations = value; if (ChartCtrl != null) { ChartCtrl.DisableAnimations = (!_canAnimations); } } } private int _tickInterval = 1; [Filed(true)] [DoNotCheckEquality] [AutoUpdateText] [SortIndex(5520)] [System.ComponentModel.Category("图表相关|基本")] [System.ComponentModel.DisplayName("周期(秒)")] [System.ComponentModel.Description("至多点数.")] public int TickInterval { get => _tickInterval; set { if (value < 1 || value > 7200) { this.GetWindowScada()?.MsgWarn("超出范围,范围1-7200"); return; } _tickInterval = value; _dispatcherTimerInterval.Interval = TimeSpan.FromSeconds(_tickInterval); } } private int _maxPointsCount = 5; [Filed] [DoNotCheckEquality] [AutoUpdateText] [SortIndex(5620)] [System.ComponentModel.Category("图表相关|基本")] [System.ComponentModel.DisplayName("至多周期数")] [System.ComponentModel.Description("至多点数.")] public int LimitPoints { get => _maxPointsCount; set { if (value < 3 || value > 200) { this.GetWindowScada()?.MsgWarn("超出范围,范围3-200"); return; } _maxPointsCount = value; } } //private int _xLines = 5; //[Filed(true)] //[DoNotCheckEquality] //[AutoUpdateText] //[SortIndex(5720)] //[System.ComponentModel.Category("图表相关|基本")] //[System.ComponentModel.DisplayName("X栅格数")] //[System.ComponentModel.Description("X栅格数.")] //public int XLines //{ // get => _xLines; // set // { // if (value < 3 || value > 20) // { // this.GetWindowScada()?.Alert("超出范围,范围3-50"); // return; // } // _xLines = value; // if (AxisX?.Separator != null) // { // AxisX.Separator.IsEnabled = true; // AxisX.Separator.Step = TimeSpan.FromSeconds(TickInterval * LimitPoints).Ticks / (double)_xLines; // AxisX.Separator.IsEnabled = false; // } // //AxisX.Separator.Step = TimeSpan.FromSeconds(_maxPointsCount * _tickInterval).Ticks; // } //} //private int _yLines = 5; //[Filed(true)] //[DoNotCheckEquality] //[AutoUpdateText] //[SortIndex(5820)] //[System.ComponentModel.Category("图表相关|基本")] //[System.ComponentModel.DisplayName("Y格线数")] //[System.ComponentModel.Description("Y格线数.")] //public int YLines //{ // get => _yLines; // set // { // if (value < 3 || value > 20) // { // this.GetWindowScada()?.Alert("超出范围,范围3-20"); // return; // } // _yLines = value; // } //} private Color _xColor = ThemeDefine.Default.Text0.ToArgbColor(); [Filed] [DoNotCheckEquality] [AutoUpdateText] [SortIndex(6580)] [System.ComponentModel.Category("图表相关|基本")] [System.ComponentModel.DisplayName("X栅线色")] [System.ComponentModel.Description("背景颜色.")] public virtual Color XColor { get => _xColor; set { _xColor = value; if (AxisX?.Separator != null) { AxisX.Separator.Stroke = new SolidColorBrush(value); } } } private Color _xLabelColor = ThemeDefine.Default.Text0.ToArgbColor(); [Filed] [DoNotCheckEquality] [AutoUpdateText] [SortIndex(6570)] [System.ComponentModel.Category("图表相关|基本")] [System.ComponentModel.DisplayName("X轴字色")] [System.ComponentModel.Description("背景颜色.")] public virtual Color XLabelColor { get => _xLabelColor; set { _xLabelColor = value; if (AxisX != null) AxisX.Foreground = new SolidColorBrush(value); } } private double _xLabelAngle = 0; [Filed] [DoNotCheckEquality] [AutoUpdateText] [Slidable(0, 360)] [SortIndex(6590)] [System.ComponentModel.Category("图表相关|基本")] [System.ComponentModel.DisplayName("X字角度")] [System.ComponentModel.Description("背景颜色.")] public double XLabelAngle { get => _xLabelAngle; set { if (value < 0 || value > 360) { this.GetWindowScada()?.MsgWarn("超出范围,范围3-20"); return; } _xLabelAngle = value; if (AxisX != null) AxisX.LabelsRotation = _xLabelAngle; } } private Color _yColor = ThemeDefine.Default.Text0.ToArgbColor(); [Filed(true)] [AutoUpdateText] [SortIndex(6780)] [System.ComponentModel.Category("图表相关|基本")] [System.ComponentModel.DisplayName("Y栅线色")] [System.ComponentModel.Description("背景颜色.")] public virtual Color YColor { get => _yColor; set { _yColor = value; if (AxisY?.Separator != null) { AxisY.Separator.Stroke = new SolidColorBrush(value); } } } private Color _yLabelColor = ThemeDefine.Default.Text0.ToArgbColor(); [Filed] [DoNotCheckEquality] [AutoUpdateText] [SortIndex(6790)] [System.ComponentModel.Category("图表相关|基本")] [System.ComponentModel.DisplayName("Y轴字色")] [System.ComponentModel.Description("背景颜色.")] public virtual Color YLabelColor { get => _yLabelColor; set { _yLabelColor = value; if (AxisY != null) AxisY.Foreground = new SolidColorBrush(value); } } public CartesianChartEx ChartCtrl { get; } private AxisEx AxisX { get; } private Axis AxisY { get; } private const string __XFORMAT = "hh:mm:ss"; public Primitive图表读取器3() { ChartCtrl = new CartesianChartEx(); //ChartCtrl.DisableAnimations = true; //ChartCtrl.AnimationsSpeed = TimeSpan.FromMilliseconds(999); //LiveCharts.Wpf.Components.ChartUpdater updater = (LiveCharts.Wpf.Components.ChartUpdater)ChartCtrl.Model.Updater; AxisX = new AxisEx() { DisableAnimations = true, LabelsRotation = 0, LabelFormatter = d => new DateTime((long)(d < 0 ? 0 : d)).ToString(__XFORMAT) }; AxisX.ShowLabels = true; AxisX.IsEnabled = false; //AxisX.IsMerged = true; AxisX.Unit = 10.0; AxisX.Separator.StrokeThickness = 1.0; var now = RpcHttp.Current.GetTimeNowByServerBase(); //AxisX.Labels = Enumerable.Range(0, 5).Select(t => now.Add(TimeSpan.FromSeconds(t)).ToString(__XFORMAT)).ToList(); ChartCtrl.AxisX = new AxesCollection() { AxisX }; AxisY = new Axis() { DisableAnimations = true, LabelsRotation = 0, LabelFormatter = d => d.ToString() }; AxisY.Separator.StrokeThickness = 1.0; ChartCtrl.AxisY = new AxesCollection() { AxisY }; ChartCtrl.Series = new SeriesCollection(); WidthEx = 300; HeightEx = 200; CanAnimations = false; CornerRadius = new CornerRadius(0); BackgroundEx = 0xff0b3869.ToArgbColor(); WhenMeticsChanged = WhenMeticsChangedMethod; _dispatcherTimerChart = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(999.0) }; _dispatcherTimerInterval = new DispatcherTimer { Interval = TimeSpan.FromSeconds(_tickInterval) }; Loaded += OnLoaded; Unloaded += OnUnloaded; //Mappers.Xy<DateTimePoint>().X() //var mapper1 = Mappers.Xy<TickPoint>() // .X((value, index) => value.Time.Ticks) // .Y(value => value.Value.GetHashCode()); //LiveCharts.Charting.For<TickPoint>(mapper1, SeriesOrientation.Horizontal); } protected override void OnInitContent(ContentPresenter content) { content.Content = ChartCtrl; LimitPoints = LimitPoints; TickInterval = TickInterval; CanAnimations = CanAnimations; XColor = XColor; //XLines = XLines;//dependence on LimitPoints and TickInterval XLabelColor = XLabelColor; XLabelAngle = XLabelAngle; YColor = YColor; YLabelColor = YLabelColor; } private void OnLoaded(object sender, RoutedEventArgs e) { _dispatcherTimerChart.Tick += DispatcherTimerOnTick; _dispatcherTimerChart.Start(); _dispatcherTimerInterval.Tick += DispatcherTimerIntervalOnTick; _dispatcherTimerInterval.Start(); } private void OnUnloaded(object sender, RoutedEventArgs e) { //var updater = (LiveCharts.Wpf.Components.ChartUpdater)ChartCtrl.Model.Updater; //updater.Timer.Tick -= updater.OnTimerOnTick; //updater.Timer.Stop(); //updater.Timer.IsEnabled = false; //updater.Timer = null; //var updater = ChartCtrl.Model.Updater; //foreach (var seriesView in ChartCtrl.Series) //{ // if (seriesView.Values is IDisposable values) // values.Dispose(); //} _dispatcherTimerChart.Tick -= DispatcherTimerOnTick; _dispatcherTimerChart.Stop(); _dispatcherTimerInterval.Tick -= DispatcherTimerIntervalOnTick; _dispatcherTimerInterval.Stop(); ChartCtrl.Series.ForEach(t => { t.Values.Clear(); t.Values.CollectGarbage(t); }); } readonly Dictionary<string, IConvertible> _pathValueLast = new Dictionary<string, IConvertible>(); private void DispatcherTimerIntervalOnTick(object sender, EventArgs e) { var now = RpcHttp.Current.GetTimeNowByServerBase(); Metrics.ToList().ForEach(t => { var bean = t.AsType<ChartLineBean>(); if (bean?.SeriesView == null) return; if (_pathValueLast.ContainsKey(t.Path)) { var val = _pathValueLast[t.Path]; if (val == null) return; bean.SeriesView.Values?.Add(new DateTimePoint(now, val.ToDouble(null))); } while (bean.SeriesView?.Values?.Count > LimitPoints) bean.SeriesView?.Values?.RemoveAt(0); }); } private void DispatcherTimerOnTick(object sender, EventArgs e) { ChartCtrl.Update(false, true); } private int _indexColorUsage = 0; private bool _canAnimations; private void WhenMeticsChangedMethod(object sender, NotifyCollectionChangedEventArgs e) { switch (e.Action) { case NotifyCollectionChangedAction.Add: foreach (IMetric metric in e.NewItems) { var beanMetricAndSeries = metric.AsType<ChartLineBean>(); if (beanMetricAndSeries == null) continue; var series = new LineSeries() { Values = new ChartValues<DateTimePoint>() { new DateTimePoint() }, Title = metric.Path, PointGeometrySize = 4, }; series.DataContext = beanMetricAndSeries; series.Values.Initialize(series); //Enumerable.Range(1,3).ToList().ForEach(t=> series.Values.Add(new DateTimePoint())); series.SetBinding(LineSeries.LineSmoothnessProperty, new Binding(ClassEx.GetPropertyName<ChartLineBean>(t => t.LineSmoothness)) { Converter = new BooleanToDoubleConverter(), Mode = BindingMode.TwoWay }); beanMetricAndSeries.SeriesView = series; if (beanMetricAndSeries.Color == Colors.Transparent) { beanMetricAndSeries.Color = ChartSourceEx.Colors[_indexColorUsage % Chart.Colors.Count]; _indexColorUsage++; } series.SetBinding(LineSeries.StrokeProperty, new Binding(ClassEx.GetPropertyName<ChartLineBean>(t => t.Color)) { Converter = new ColorToBrushConverter(), Mode = BindingMode.TwoWay }); ChartCtrl.Series.Add(series); while (series.Values.Count > 0) series.Values.RemoveAt(0); //ChartCtrl.Update(true, true); } break; case NotifyCollectionChangedAction.Remove: foreach (IMetric metric in e.OldItems) { var beanMetricAndSeries = metric.AsType<ChartLineBean>(); if (beanMetricAndSeries == null) continue; ChartCtrl.Series.Remove(beanMetricAndSeries.SeriesView); beanMetricAndSeries.SeriesView = null; } break; } ChartCtrl.Update(false, true); lock (_pathValueLast) { _pathValueLast.Clear(); Metrics.ToList().ForEach(t => { _pathValueLast.Add(t.Path, t.Value); }); } } protected override void InsertMetric(ObservableCollection<IMetric> metrics, IMetric metric) { //base.InsertMetric(metrics, metric); var metircAndSeries = new ChartLineBean() { Path = metric.Path, RwModel = metric.RwModel, Value = metric.Value }; metrics.Add(metircAndSeries); } public override void OnValueChanged(IPathValue metric) { if (_pathValueLast.ContainsKey(metric.Path)) _pathValueLast[metric.Path] = metric.Value; //var metircAndSeries = Metrics.FirstOrDefault(t => t.Path == metric.Path)?.AsType<Bean>(); //if (metircAndSeries == null) return; //metircAndSeries.SeriesView?.Values?.Add(new DateTimePoint(InternalRestClient.Current.GetTimeNowByServerBase(), metric.Value.ToDouble(null))); //while (metircAndSeries.SeriesView?.Values?.Count > LimitPoints) metircAndSeries.SeriesView?.Values?.RemoveAt(0); } public void Dispose() { ChartCtrl.Series.Clear(); } ~Primitive图表读取器3() { _dispatcherTimerInterval?.Stop(); _dispatcherTimerInterval = null; _dispatcherTimerChart?.Stop(); _dispatcherTimerChart = null; } } }
废弃代码,自行参考。