"实时图表" x轴不随时间WPF更新c#

时间:2016-11-29 11:33:18

标签: c# wpf visual-studio livecharts

我刚开始探索实时图表库,但似乎无法随着时间的推移更新x轴。我已经一次又一次地走过去,似乎无法找到问题所在。数据点正确更新,这是我发现令人困惑的!

我将在以后用计时器替换DateTime,该计时器显示测试运行了多长时间,如果这使得解决方案更简单?

我的一部分认为这一定是我想念的简单事情!?

我感谢你对此提供任何帮助!

public partial class MainWindow : Window
{

    private double _axisMax;
    private double _axisMin;
    Stopwatch stopwatch = new Stopwatch();


    public MainWindow()
    {
        InitializeComponent();
        //To handle live data easily, in this case we built a specialized type
        //the MeasureModel class, it only contains 2 properties
        //DateTime and Value
        //We need to configure LiveCharts to handle MeasureModel class
        //The next code configures MEasureModel  globally, this means
        //that livecharts learns to plot MeasureModel and will use this config every time
        //a ChartValues instance uses this type.
        //this code ideally should only run once, when application starts is reccomended.
        //you can configure series in many ways, learn more at http://lvcharts.net/App/examples/v1/wpf/Types%20and%20Configuration


        var mapper = Mappers.Xy<MeasureModel>()
            .X(model => model.DateTime.Ticks)   //use DateTime.Ticks as X
            .Y(model => model.Value);           //use the value property as Y

        //lets save the mapper globally.
        Charting.For<MeasureModel>(mapper);


        //the values property will store our values array
        ChartValues = new ChartValues<MeasureModel>();

        //lets set how to display the X Labels
        DateTimeFormatter = value => new DateTime((long)value).ToString("hh:mm:ss");

        AxisStep = TimeSpan.FromSeconds(1).Ticks;
        SetAxisLimits(DateTime.Now);

        //The next code simulates data changes every 300 ms
        Timer = new DispatcherTimer
        {
            Interval = TimeSpan.FromMilliseconds(300)
        };
        Timer.Tick += TimerOnTick;
        IsDataInjectionRunning = false;
        R = new Random();
        DataContext = this;
    }

    public ChartValues<MeasureModel> ChartValues { get; set; }
    public Func<double, string> DateTimeFormatter { get; set; }

    public double AxisStep { get; set; }

    public double AxisMax
    {
        get { return _axisMax; }
        set
        {
            _axisMax = value;
            OnPropertyChanged("AxisMax");
        }
    }
    public double AxisMin
    {
        get { return _axisMin; }
        set
        {
            _axisMin = value;
            OnPropertyChanged("AxisMin");
        }
    }

    public DispatcherTimer Timer { get; set; }
    public bool IsDataInjectionRunning { get; set; }
    public Random R { get; set; }

    private void RunDataOnClick(object sender, RoutedEventArgs e)
    {
        if (IsDataInjectionRunning)
        {
            stopwatch.Stop();
            Timer.Stop();
            IsDataInjectionRunning = false;
        }
        else
        {
            stopwatch.Start();
            Timer.Start();
            IsDataInjectionRunning = true;
        }
    }

    private void TimerOnTick(object sender, EventArgs eventArgs) // Class is referencing from here!
    {
        var now = DateTime.Now;

        ChartValues.Add(new MeasureModel
        {
            DateTime = DateTime.Now,
            Value = R.Next(0, 10)
        });

        SetAxisLimits(DateTime.Now);

        //lets only use the last 30 values
        if (ChartValues.Count > 30) ChartValues.RemoveAt(0);
    }

    private void SetAxisLimits(DateTime now)
    {
        AxisMax = now.Ticks + TimeSpan.FromSeconds(20).Ticks; // lets force the axis to be 100ms ahead
        AxisMin = now.Ticks - TimeSpan.FromSeconds(8).Ticks; //we only care about the last 8 seconds
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName = null)
    {
        if (PropertyChanged != null) // if subrscribed to event
            PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}
public class MeasureModel
{
    public DateTime DateTime { get; set; }
    public double Value { get; set; }
}
<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:graph_test_6"
    xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
    xmlns:chart="http://mindfusion.eu/charting/wpf" x:Class="graph_test_6.MainWindow"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">
    <Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition Height="*"></RowDefinition>
    </Grid.RowDefinitions>
    <Button Grid.Row="0" Height="30" Click="RunDataOnClick">
        Inject/Stop Data
    </Button>
    <lvc:CartesianChart Grid.Row="1">
        <lvc:CartesianChart.Series>
            <lvc:LineSeries Values="{Binding ChartValues}" PointGeometrySize="18" StrokeThickness="4" />
        </lvc:CartesianChart.Series>
        <lvc:CartesianChart.AxisX>
            <lvc:Axis LabelFormatter="{Binding DateTimeFormatter}" 
                      MaxValue="{Binding AxisMax}" 
                      MinValue="{Binding AxisMin}"
                      DisableAnimations="True">
                <lvc:Axis.Separator>
                    <lvc:Separator Step="{Binding AxisStep}"></lvc:Separator>
                </lvc:Axis.Separator>
            </lvc:Axis>
        </lvc:CartesianChart.AxisX>
    </lvc:CartesianChart>
    <TextBox x:Name="textBox" HorizontalAlignment="Left" Height="23" Margin="323,-71,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>
</Grid>

Screen shot of problem

1 个答案:

答案 0 :(得分:3)

在Xaml中,您将绑定AxisX属性MaxValue和MinValue:

 MaxValue="{Binding AxisMax}" 
 MinValue="{Binding AxisMin}"

当窗口加载时,WPF机制会读取绑定的值:这就是获取X轴初始值的方式。稍后您将在代码中更改这些值:

 AxisMax = now.Ticks + TimeSpan.FromSeconds(20).Ticks; // lets force the axis to be 100ms ahead
 AxisMin = now.Ticks - TimeSpan.FromSeconds(8).Ticks; //we only care about the last 8 seconds

Xaml应该收到有关这些更改的通知,并通过以下方式完成:

 OnPropertyChanged("AxisMin");
 OnPropertyChanged("AxisMax");

问题是窗口控件本身没有声明,它支持更改通知:它缺少INotifyPropertyChanged

所以要解决您的问题更改

public partial class MainWindow : Window

 public partial class MainWindow  : Window, INotifyPropertyChanged