Benutzer mit den meisten Antworten
Problem mit ObservableCollection und Tollkit Chart

Frage
-
Hallo,ich habe eine ObservableCollection an ein Toolkit:Chart gebunden und ändere die Werte im Hintergrund.Funktioniert ganz gut, eine Zeit lang. Dann beginnen die Balken zu fliegen. Ich denke es ist ein Paint Fehler, denn wenn ich das Browserfenster nur ein Pixel in der Größe ändere, werden die Balken wieder richtig gemalt.Was mache ich den falsch?Hier ist das Sample hierMan muss eine Zeit lang warten oder das Browserfenster maximieren und wieder verkleinern.XAML
<UserControl xmlns:ctk="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit" xmlns:datvis="clr-namespace:System.Windows.Controls.DataVisualization;assembly=System.Windows.Controls.DataVisualization.Toolkit" x:Class="SilverlightMiniApp.MainPage" 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" mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480"> <Grid x:Name="LayoutRoot"> <ctk:Chart Name="MainChart" > <ctk:Chart.Series> <ctk:ColumnSeries DependentValueBinding="{Binding Path=Value}" IndependentValueBinding="{Binding Path=Key}"/> </ctk:Chart.Series> </ctk:Chart> </Grid> </UserControl>
C# Code
using System.Windows.Controls; using System.Windows.Controls.DataVisualization.Charting; using System.Collections.ObjectModel; using System.Collections.Generic; using System; namespace SilverlightMiniApp { public partial class MainPage : UserControl { ObservableCollection<KeyValuePair<int, int>> myData = new ObservableCollection<KeyValuePair<int, int>>(); System.Windows.Threading.DispatcherTimer aTimer = new System.Windows.Threading.DispatcherTimer(); public MainPage() { InitializeComponent(); for (int i = 0; i < 24; i++) myData.Add(new KeyValuePair<int, int>(i, 0)); ((ColumnSeries)MainChart.Series[0]).ItemsSource = myData; aTimer.Interval = TimeSpan.FromMilliseconds(4000); aTimer.Tick += aTimer_Tick; aTimer.Start(); } void aTimer_Tick(object sender, EventArgs e) { Random aRandom = new Random(); for (int i = 0; i < 24; i++) myData[i]=new KeyValuePair<int, int>(i, aRandom.Next(0, 30)); } } }
Samstag, 6. Februar 2010 17:31
Antworten
-
Hier jetzt die Lösung (Work-Around) mit MVVM:
XAML:
<navigation:Page xmlns:ctk="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit" x:Class="SilverlightApplication1.Page3" 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" mc:Ignorable="d" xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation" d:DesignWidth="640" d:DesignHeight="480" Title="Page3 Page" xmlns:my="clr-namespace:SilverlightApplication1" > <navigation:Page.Resources> <my:Page3ViewModel x:Key="VM" /> </navigation:Page.Resources> <Grid x:Name="LayoutRoot"> <ctk:Chart Name="MainChart" Height="500"> <ctk:Chart.Series> <ctk:ColumnSeries ItemsSource="{Binding Source={StaticResource VM}, Path=Data}" DependentValueBinding="{Binding Value}" IndependentValueBinding="{Binding Key}" > <ctk:ColumnSeries.DependentRangeAxis> <ctk:LinearAxis Orientation="Y" Minimum="0" Maximum="100" /> </ctk:ColumnSeries.DependentRangeAxis> </ctk:ColumnSeries> </ctk:Chart.Series> </ctk:Chart> </Grid> </navigation:Page>
Dazu das ViewModel und die Datenklasse:
Public Class Page3ViewModel Implements INotifyPropertyChanged Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged Private WithEvents aTimer As New DispatcherTimer Public Sub New() Me._data = New List(Of DataClass) For i = 1 To 24 Me._data.Add(New DataClass With {.Key = 2 * i, .Value = i}) Next With aTimer .Interval = TimeSpan.FromMilliseconds(4000) .Start() End With End Sub Private Sub aTimer_Tick(ByVal sender As Object, ByVal e As EventArgs) _ Handles aTimer.Tick Dim aRandom As New Random() For i = 0 To 23 Me._data(i).Value = aRandom.Next(0, 30) Next RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Data")) End Sub Private _data As List(Of DataClass) Public ReadOnly Property Data() As List(Of DataClass) Get Return New List(Of DataClass)(Me._data) End Get End Property End Class Public Class DataClass Private _key As Integer Public Property Key() As Integer Get Return _key End Get Set(ByVal value As Integer) _key = value End Set End Property Private _value As Integer Public Property Value() As Integer Get Return _value End Get Set(ByVal value As Integer) _value = value End Set End Property End Class
--
Peter
- Als Antwort vorgeschlagen Peter Fleischer Samstag, 20. März 2010 08:20
- Als Antwort markiert ixmac Dienstag, 30. März 2010 11:00
Samstag, 20. März 2010 08:20
Alle Antworten
-
Nimm anstelle der KeyValuePair-Objekte eigene Objekt, die INotifyPropertyChanged implemetieren, dann werden Änderungen auch sofort angezeigt.
--
Peter- Als Antwort markiert Robert Breitenhofer Donnerstag, 4. März 2010 09:21
- Tag als Antwort aufgehoben Robert Breitenhofer Dienstag, 16. März 2010 08:49
Mittwoch, 24. Februar 2010 06:00 -
Hallo,leider ist das nicht die Lösung des Problems.Die Balken werden ja aktualisiert.Nur ab einem Zeitpunkt werden die Balken nicht mehr ab der Null-Linie gezeichnet.Ich habe das auf mehreren Rechnern reproduzieren können.Das Programm hab ich trotzdem umgebaut auf eine "ObservableKeyValuePair" :)Der Rest ist wie oben.
public class ObservableKeyValuePair<TKey, TValue> : INotifyPropertyChanged { public ObservableKeyValuePair(TKey k, TValue v) { Key = k; Value = v; } private TKey _key; public TKey Key { get{ return(_key); } set { _key = value; if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Key")); } } private TValue _value; public TValue Value { get{return (_value);} set { _value = value; if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Value")); } } public event PropertyChangedEventHandler PropertyChanged; }
Das Setzen der Daten im Timer hab ich nochmal vereinfacht:void aTimer_Tick(object sender, EventArgs e) { Random aRandom = new Random(); for (int i = 0; i < 24; i++) myData[i].Value = aRandom.Next(0, 30); }
Die Aktualisierung geht. Das Problem der "fliegenden Balken" bleibt.Beste GrüßeMarcusMontag, 15. März 2010 18:52 -
Hier jetzt die Lösung (Work-Around) mit MVVM:
XAML:
<navigation:Page xmlns:ctk="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit" x:Class="SilverlightApplication1.Page3" 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" mc:Ignorable="d" xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation" d:DesignWidth="640" d:DesignHeight="480" Title="Page3 Page" xmlns:my="clr-namespace:SilverlightApplication1" > <navigation:Page.Resources> <my:Page3ViewModel x:Key="VM" /> </navigation:Page.Resources> <Grid x:Name="LayoutRoot"> <ctk:Chart Name="MainChart" Height="500"> <ctk:Chart.Series> <ctk:ColumnSeries ItemsSource="{Binding Source={StaticResource VM}, Path=Data}" DependentValueBinding="{Binding Value}" IndependentValueBinding="{Binding Key}" > <ctk:ColumnSeries.DependentRangeAxis> <ctk:LinearAxis Orientation="Y" Minimum="0" Maximum="100" /> </ctk:ColumnSeries.DependentRangeAxis> </ctk:ColumnSeries> </ctk:Chart.Series> </ctk:Chart> </Grid> </navigation:Page>
Dazu das ViewModel und die Datenklasse:
Public Class Page3ViewModel Implements INotifyPropertyChanged Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged Private WithEvents aTimer As New DispatcherTimer Public Sub New() Me._data = New List(Of DataClass) For i = 1 To 24 Me._data.Add(New DataClass With {.Key = 2 * i, .Value = i}) Next With aTimer .Interval = TimeSpan.FromMilliseconds(4000) .Start() End With End Sub Private Sub aTimer_Tick(ByVal sender As Object, ByVal e As EventArgs) _ Handles aTimer.Tick Dim aRandom As New Random() For i = 0 To 23 Me._data(i).Value = aRandom.Next(0, 30) Next RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Data")) End Sub Private _data As List(Of DataClass) Public ReadOnly Property Data() As List(Of DataClass) Get Return New List(Of DataClass)(Me._data) End Get End Property End Class Public Class DataClass Private _key As Integer Public Property Key() As Integer Get Return _key End Get Set(ByVal value As Integer) _key = value End Set End Property Private _value As Integer Public Property Value() As Integer Get Return _value End Get Set(ByVal value As Integer) _value = value End Set End Property End Class
--
Peter
- Als Antwort vorgeschlagen Peter Fleischer Samstag, 20. März 2010 08:20
- Als Antwort markiert ixmac Dienstag, 30. März 2010 11:00
Samstag, 20. März 2010 08:20