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



我有一个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>

主窗口.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";
}

从WPFToolkit中的源代码来看,BarDataPoint似乎有一个"Reveal"VisualState,它在0.5秒内对从0到>1的不透明度进行动画化。我的猜测是,由于您添加和删除了条形图的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">

最新更新