更新WPF条形图更新数据时的重影/淡入淡出效果

时间:2014-02-23 15:47:23

标签: c# wpf user-interface charts wpftoolkit

我有一个WPF条形图,我每200ms更新一次。它更新了新数据,但有重影效果。因此,当一个条形从1变为0.5时,原始条形区域会出现一个褪色的条形。我不知道为什么会发生这种情况,但我会将其删除,以便条形图移动干净。

MainWindow.xml

<charting:Chart Grid.Column="0" HorizontalAlignment="Stretch" Margin="6,6,6,6" Name="motorPowerChart" VerticalAlignment="Stretch" Title="Motor Power">
                    <charting:ColumnSeries IndependentValueBinding="{Binding Key}"
                                           DependentValueBinding="{Binding Value}"
                                           ItemsSource="{Binding}">
                    </charting:ColumnSeries>
                    <charting:Chart.Axes>
                        <charting:LinearAxis Orientation="Y" Minimum="0" Maximum="1" Title="PWM Frequency"/>
                    </charting:Chart.Axes>
                    <charting:Chart.LegendStyle>
                        <Style TargetType="Control">
                            <Setter Property="Width" Value="0"/>
                            <Setter Property="Height" Value="0"/>
                        </Style>
                    </charting:Chart.LegendStyle>
                </charting:Chart>

MainWindow.xml.cs

public partial class MainWindow : Window
        {
        DispatcherTimer _statusUpdateTimer;
        public ObservableCollection<KeyValuePair<string, double>> MotorPowerGraphData = new ObservableCollection<KeyValuePair<string, double>>();
        public ObservableCollection<KeyValuePair<string, double>> PIDGraphData = new ObservableCollection<KeyValuePair<string, double>>();

        public MainWindow()
        {
              InitializeComponent();

              _statusUpdateTimer = new DispatcherTimer();
              _statusUpdateTimer.Interval = new TimeSpan(0, 0, 0, 0, 200);
              _statusUpdateTimer.Tick += new EventHandler(updateStatus);

              motorPowerChart.DataContext = MotorPowerGraphData;
              pidChart.DataContext = PIDGraphData;
        }

        private void updateStatus(Object myObject, EventArgs myEventArgs)
        {

              double[] status = SerialCommunications.GetStatus();

              MotorPowerGraphData.Clear();
              MotorPowerGraphData.Add(new KeyValuePair<String, double>("Motor1", status[0]));
              MotorPowerGraphData.Add(new KeyValuePair<String, double>("Motor2", status[1]));
              MotorPowerGraphData.Add(new KeyValuePair<String, double>("Motor3", status[2]));
              MotorPowerGraphData.Add(new KeyValuePair<String, double>("Motor4", status[3]));

              PIDGraphData.Clear();
              PIDGraphData.Add(new KeyValuePair<String, double>("Yaw", status[8]));
              PIDGraphData.Add(new KeyValuePair<String, double>("Pitch", status[9]));
              PIDGraphData.Add(new KeyValuePair<String, double>("Roll", status[10]));

        }

任何人都可以帮我吗?

由于

修改

我已经减慢了定时器的速度,所以它每秒滴答一次,并尝试从更新状态函数中输入虚拟数据,我仍然看到相同的行为。它在10Hz看起来更糟糕,因为在下一个渲染到顶部之前,条形没有时间褪色。

这是我的新更新状态功能

int i = 0;
        private void updateStatus(Object myObject, EventArgs myEventArgs)
        {

              /*double[] status = SerialCommunications.GetStatus();

              MotorPowerGraphData.Clear();
              MotorPowerGraphData.Add(new KeyValuePair<String, double>("M1 " + Math.Round(status[0], 3), status[0]));
              MotorPowerGraphData.Add(new KeyValuePair<String, double>("M2 " + Math.Round(status[1], 3), status[1]));
              MotorPowerGraphData.Add(new KeyValuePair<String, double>("M3 " + Math.Round(status[2], 3), status[2]));
              MotorPowerGraphData.Add(new KeyValuePair<String, double>("M4 " + Math.Round(status[3], 3), status[3]));

              PIDGraphData.Clear();
              PIDGraphData.Add(new KeyValuePair<String, double>("Yaw " + Math.Round(status[8], 0), status[8]));
              PIDGraphData.Add(new KeyValuePair<String, double>("Pitch " + Math.Round(status[9], 0), status[9]));
              PIDGraphData.Add(new KeyValuePair<String, double>("Roll " + Math.Round(status[10], 0), status[10]));

              IMUGraphData.Clear();
              IMUGraphData.Add(new KeyValuePair<String, double>("Yaw " + Math.Round(status[4],0), status[4]));
              IMUGraphData.Add(new KeyValuePair<String, double>("Pitch " + Math.Round(status[5], 0), status[5]));
              IMUGraphData.Add(new KeyValuePair<String, double>("Roll " + Math.Round(status[6], 0), status[6]));

              if (status[7] == 1) batteryStatusLabel.Content = "Battery Level: Charged";
              else batteryStatusLabel.Content = "Battery Level: Empty";*/

              if (i == 5) i = 0;
              else
              {
                    IMUGraphData.Clear();
                    IMUGraphData.Add(new KeyValuePair<String, double>("Yaw " + i*30, i*30));
                    IMUGraphData.Add(new KeyValuePair<String, double>("Pitch " + i*-30, i*-30));
                    IMUGraphData.Add(new KeyValuePair<String, double>("Roll " + i * 15, i * 15));
                    i++;
              }

        }

我已将视频上传到youtube,因此您可以在更新时看到图表的样子

修改

我在使用图表控件的Win窗体中尝试了这个并且它工作得很好但是我想使用WPF,因为我想渲染一个根据偏航,俯仰和滚动以及从我读过的内容在空间中旋转的立方体这在WPF中很容易做到

修改

如果没有人知道为什么这不起作用,有人可以推荐一些其他方式来显示我的数据吗?

我编辑了这些值而不是删除它们并将它们添加到可观察集合中。

 public partial class MainWindow : Window
        {

        DispatcherTimer _statusUpdateTimer;
        public ObservableCollection<KeyValuePair<string, double>> _motorPowerGraphData = new ObservableCollection<KeyValuePair<string, double>>();
        public ObservableCollection<KeyValuePair<string, double>> _ratePIDGraphData = new ObservableCollection<KeyValuePair<string, double>>();
        public ObservableCollection<KeyValuePair<string, double>> _stabPIDGraphData = new ObservableCollection<KeyValuePair<string, double>>();
        public ObservableCollection<KeyValuePair<string, double>> _imuGraphData = new ObservableCollection<KeyValuePair<string, double>>();

        public MainWindow()
        {
              InitializeComponent();

              _motorPowerGraphData.Clear();
              _motorPowerGraphData.Add(new KeyValuePair<string, double>("M1 0", 0));
              _motorPowerGraphData.Add(new KeyValuePair<string, double>("M2 0", 0));
              _motorPowerGraphData.Add(new KeyValuePair<string, double>("M3 0", 0));
              _motorPowerGraphData.Add(new KeyValuePair<string, double>("M4 0", 0));

              _ratePIDGraphData.Clear();
              _ratePIDGraphData.Add(new KeyValuePair<String, double>("Yaw 0", 0));
              _ratePIDGraphData.Add(new KeyValuePair<String, double>("Pitch 0", 0));
              _ratePIDGraphData.Add(new KeyValuePair<String, double>("Roll 0", 0));

              _stabPIDGraphData.Clear();
              _stabPIDGraphData.Add(new KeyValuePair<String, double>("Yaw 0", 0));
              _stabPIDGraphData.Add(new KeyValuePair<String, double>("Pitch 0", 0));
              _stabPIDGraphData.Add(new KeyValuePair<String, double>("Roll 0", 0));

              _imuGraphData.Clear();
              _imuGraphData.Add(new KeyValuePair<String, double>("Yaw 0", 0));
              _imuGraphData.Add(new KeyValuePair<String, double>("Pitch 0",  0));
              _imuGraphData.Add(new KeyValuePair<String, double>("Roll 0",  0));

              _statusUpdateTimer = new DispatcherTimer();
              _statusUpdateTimer.Interval = new TimeSpan(0, 0, 0, 0, 200);
              _statusUpdateTimer.Tick += new EventHandler(updateStatus);

              motorPowerChart.DataContext = _motorPowerGraphData;
              ratePIDChart.DataContext = _ratePIDGraphData;
              stabPIDChart.DataContext = _stabPIDGraphData;
              imuChart.DataContext = _imuGraphData;
        }

        private void updateStatus(Object myObject, EventArgs myEventArgs)
        {

              double[] status = SerialCommunications.GetStatus();

              _motorPowerGraphData[0] = new KeyValuePair<String, double>("M1 " + Math.Round(status[0], 3), status[0]);
              _motorPowerGraphData[1] = new KeyValuePair<String, double>("M2 " + Math.Round(status[1], 3), status[1]);
              _motorPowerGraphData[2] = new KeyValuePair<String, double>("M3 " + Math.Round(status[2], 3), status[2]);
              _motorPowerGraphData[3] = new KeyValuePair<String, double>("M4 " + Math.Round(status[3], 3), status[3]);

              _ratePIDGraphData[0] = new KeyValuePair<String, double>("Yaw " + Math.Round(status[8], 0), status[8]);
              _ratePIDGraphData[1] = new KeyValuePair<String, double>("Pitch " + Math.Round(status[9], 0), status[9]);
              _ratePIDGraphData[2] = new KeyValuePair<String, double>("Roll " + Math.Round(status[10], 0), status[10]);

              _stabPIDGraphData[0] = new KeyValuePair<String, double>("Yaw " + Math.Round(status[8], 0), status[11]);
              _stabPIDGraphData[1] = new KeyValuePair<String, double>("Pitch " + Math.Round(status[9], 0), status[12]);
              _stabPIDGraphData[2] = new KeyValuePair<String, double>("Roll " + Math.Round(status[10], 0), status[13]);

              _imuGraphData[0] = new KeyValuePair<String, double>("Yaw " + Math.Round(status[4],0), status[4]);
              _imuGraphData[1] = new KeyValuePair<String, double>("Pitch " + Math.Round(status[5], 0), status[5]);
              _imuGraphData[2] = new KeyValuePair<String, double>("Roll " + Math.Round(status[6], 0), status[6]);

              if (status[7] == 1) batteryStatusLabel.Content = "Battery Level: Charged";
              else batteryStatusLabel.Content = "Battery Level: Empty";

              double armed = status[14];
              if (armed == 1)
              {
                    armButton.Content = "Disarm";
                    armedLabel.Content = "Armed: True";
              }
              else
              {
                    armButton.Content = "Arm";
                    armedLabel.Content = "Armed: False";
              }

              double rateMode = status[16];
              double stabMode = status[17];
              if (rateMode == 1 && stabMode == 0)
              {
                    modeLabel.Content = "Mode: Rate";
                    modeButton.Content = "Set Mode To Stability";
              }
              else
              {
                    modeLabel.Content = "Mode: Stability";
                    modeButton.Content = "Set Mode To Rate";
              }

              double initialised = status[15];
              if (initialised == 1) initialisedLabel.Content = "Initialised: True";
              else initialisedLabel.Content = "Initialised: False";
        }

1 个答案:

答案 0 :(得分:3)

查看WPFToolkit中的源代码,看起来BarDataPoint有一个“Reveal”VisualState,可以从0开始显示不透明度 - >超过0.5秒。我的猜测是,因为你正在为条形图添加和删除KeyValuePairs,工具包正在“揭示”新的BarDataPoints,就像它们是新数据一样。

<VisualStateGroup x:Name="RevealStates">
  <VisualStateGroup.Transitions>
    <VisualTransition GeneratedDuration="0:0:0.5" />
  </VisualStateGroup.Transitions>
  <VisualState x:Name="Shown">
    <Storyboard>
      <DoubleAnimation Storyboard.TargetName="Root" Storyboard.TargetProperty="Opacity" To="1" Duration="0" />
    </Storyboard>
  </VisualState>
  <VisualState x:Name="Hidden">
    <Storyboard>
      <DoubleAnimation Storyboard.TargetName="Root" Storyboard.TargetProperty="Opacity" To="0" Duration="0" />
    </Storyboard>
  </VisualState>
</VisualStateGroup>

我可以想象两种可能的解决方案:

  1. 直接修改绑定数据。而不是添加/删除您的KeyValuePairs,而是更新它们。获取绑定更新可能有点棘手,具体取决于绑定源的设置方式。
  2. 覆盖BarDataPoints的DefaultStyle。或者,直接修改WPFToolkit的源代码(假设您自己构建它)以尝试删除有问题的“RevealStates”。