首页 新闻 会员 周边

WPF使用LiveChart的两个问题

0
悬赏园豆:50 [待解决问题]

这个问题折腾我跨一周了,请路过的朋友帮帮我:

下面是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”识别的资源”,预览不显示,但是不影响运行,这是什么问题呢?

zch半缘修道半缘君的主页 zch半缘修道半缘君 | 菜鸟二级 | 园豆:256
提问于:2021-07-04 01:32
< >
分享
所有回答(1)
0
//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;
        }
    }
}

废弃代码,自行参考。

花飘水流兮 | 园豆:13560 (专家六级) | 2021-07-06 10:00
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册