Forum: PC-Programmierung C# WPF: einfache Pixel (für Messkurven) malen?


von Bronco (Gast)


Lesenswert?

Hallo zusammen,

ich möchte in einem C# WPF-Programm Messkurven malen, indem ich einer 
Zeichenfläche zyklisch Messpunkte als Pixel hinzufüge.

Im Augenblick mach ich das über ein Canvas mit einer Polyline, wobei ich 
der Polyline für jeden Messpunkt einen Point hinzufüge. Funktioniert 
gut, allerdings wird das Programm mit der Zeit immer langsamer, was ich 
darauf zurückführe, dass die Verwaltung der vielen Point-Objekte immer 
aufwendiger wird. Denn wenn ich die Points der Polyline lösche, ist die 
Geschwindigkeit sofort wieder da.
Wenn ich hingegen einfach "unverwaltete" Pixel malen könnte, hätte ich 
das Problem nicht.

Beim Googlen hab ich leider keine Alternative gefunden. Was könnte man 
da machen?

von Babbage (Gast)


Lesenswert?

Wie wärs damit:
Generating Graphs with WPF
https://msdn.microsoft.com/en-us/magazine/ff714591.aspx

Ist schon ein paar Jahre alt aber immer noch top.

von Odrr! (Gast)


Lesenswert?

Evtl. auch mal das hier anschauen:
https://writeablebitmapex.codeplex.com/

von mitleser (Gast)


Lesenswert?

Hi,

ich nehme immer

"zedgraph"

Gruß

von Günter R. (muntablues)


Lesenswert?

Zeig mal wie du die Punkte hinzu fügst. Ich denke da kann man noch sehr 
viel optimieren.

Vor allem würde ich immer nur die letzten, sagen wir mal 100, Punkte an 
die View übergeben, dann hast du ganz bestimmt kein Problem. Einfach im 
Viewmodel die Polyline Punkte beschneiden und dann haut das sicher hin.

So denn,

von Bronco (Gast)


Lesenswert?

Günter R. schrieb:
> Zeig mal wie du die Punkte hinzu fügst. Ich denke da kann man noch
> sehr viel optimieren.
1
amplitudeLine     = new Polyline;
2
...
3
amplitudeLine.Points.Add(new Point(x, y));
Was willst Du da groß optimieren?


> Vor allem würde ich immer nur die letzten, sagen wir mal 100, Punkte an
> die View übergeben,
Aber dann werden alle älteren gelöscht/verdrängt, oder? Ich brauche die 
aber noch.

von Draco (Gast)


Lesenswert?

Speichere den Rest doch einfach in nem normalen Array ab und bei Bedarf 
rufst du sie daraus auf?!?

von Günter R. (muntablues)


Lesenswert?

Bronco schrieb:
> Aber dann werden alle älteren gelöscht/verdrängt, oder? Ich brauche die
> aber noch.

Du kannst ja im Viewmodel die Daten für die Polyline filtern und nur die 
letzten anzeigen. Je nach Größe des Controls auf dem die Polyline 
gezeichnet wird, würde ich das anpassen.

Alles zusammen würde ich das ca. so machen:
1
    class ViewModel : INotifyPropertyChanged
2
    {
3
        public event PropertyChangedEventHandler PropertyChanged;
4
5
        private const int NumberOfDrawingPoints = 100;
6
        private readonly List<double> amplitudes;
7
8
        private PointCollection polylinePoints;
9
10
11
        public ViewModel()
12
        {
13
            amplitudes = new List<double>(); 
14
            PolylinePoints = new PointCollection();
15
        }
16
17
        public PointCollection PolylinePoints
18
        {
19
            get { return polylinePoints; }
20
            set
21
            {
22
                polylinePoints = value;
23
                NotifyOfPropertyChange();
24
            }
25
        }
26
27
        public void AddMeasurement(double value)
28
        {
29
            amplitudes.Add(value);
30
            CalculatePoints();
31
        }
32
33
        private void CalculatePoints()
34
        {
35
            // take only last 100 points of amplitudes
36
            var drawingPoints = amplitudes.Skip(Math.Max(0, amplitudes.Count() - NumberOfDrawingPoints)).ToArray();
37
            var points = new PointCollection();
38
            for (int i = 0; i < drawingPoints.Count(); i++)
39
            {
40
                // TODO: X scale 
41
                points.Add(new Point(i, drawingPoints[i]));
42
            }
43
            PolylinePoints = points;
44
        }
45
46
        protected virtual void NotifyOfPropertyChange([CallerMemberName] string propertyName = null)
47
        {
48
            var handler = PropertyChanged;
49
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
50
        }
51
    }

von BSJ (Gast)


Lesenswert?

Denkbar wäre auch eine eigene Queue die INotifyPropertyChanged 
implementiert.
Damit hast du zwar nur die letzten x Samples zu Anzeige verfügbar, musst 
dich jedoch nicht um irgendwelche ArrayGrenzen usw kümmern.
Damit wird das Zeichnen zu reinem und lesbaren XAML Code.

von Bronco (Gast)


Lesenswert?

Danke für die Tips, aber die Beschränkung der Anzahl von Punkten geht an 
meinem Ziel vorbei. Ich will Meßkurven über einen längeren Zeitraum 
aufzeichnen können.
Natürlich gäbe es da Möglichkeiten, z.B. nur größere Änderungen 
anzuzeigen und die kleineren unter den Tisch fallen zulassen, aber im 
Grunde möchte ich einfach "malen können".

von Günter R. (muntablues)


Lesenswert?

Das kann man auch, wenn man es richtig macht...

Wieviel Messwerte hast pro Stunde und wie groß ist die "Zeichenfläche"? 
Ab wieviel Punkten fängt es an merklich zu bremsen?

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.