Forum: PC-Programmierung Linie in WPF zeichnen (Code behind)


von Joe (Gast)


Lesenswert?

Hallo Leute,

versuche mit Visual C# 2010 eine Linie zu zeichnen (wpf-Projekt).
Mein Code (MainWindow.xaml.cs) sieht folgendermaßen aus;
1
using System;
2
using System.Collections.Generic;
3
using System.Linq;
4
using System.Text;
5
using System.Windows;
6
using System.Windows.Controls;
7
using System.Windows.Data;
8
using System.Windows.Documents;
9
using System.Windows.Input;
10
using System.Windows.Media;
11
using System.Windows.Media.Imaging;
12
using System.Windows.Navigation;
13
using System.Windows.Shapes;
14
15
namespace DrawSomeLines
16
{
17
    /// <summary>
18
    /// Interaktionslogik für MainWindow.xaml
19
    /// </summary>
20
    public partial class MainWindow : Window
21
    {
22
        public MainWindow()
23
        {
24
            InitializeComponent();
25
26
27
            Line myLine = new Line();
28
            Grid myGrid = null;
29
            myLine.Stroke = System.Windows.Media.Brushes.LightSteelBlue;
30
            myLine.X1 = 1;
31
            myLine.X2 = 50;
32
            myLine.Y1 = 1;
33
            myLine.Y2 = 50;
34
            myLine.HorizontalAlignment = HorizontalAlignment.Left;
35
            myLine.VerticalAlignment = VerticalAlignment.Center;
36
            myLine.StrokeThickness = 2;
37
            myGrid.Children.Add(myLine);
38
39
40
41
        }
42
    }
43
}


Mit F5 starte ich das Debugging und erhalte folgende Fehlermeldung:

"TargetInvocationException wurde nicht behandelt"


Was mache ich falsch?

GRÜSSE, JOE

von Borislav B. (boris_b)


Lesenswert?

Um's kurz zu machen: myGrid ist null

von jmp (Gast)


Lesenswert?

Grid myGrid = null;
und
myGrid.Children.Add(myLine);

==> myGrid ist nicht instantiiert

--jmp

von Joe (Gast)


Lesenswert?

OK, folgender Code kompiliert jetzt. Sehe aber keine Linie.
1
public MainWindow()
2
        {
3
            InitializeComponent();
4
5
6
            Line myLine = new Line();
7
            Grid myGrid = new Grid();
8
            myLine.Stroke = System.Windows.Media.Brushes.Black;
9
            myLine.X1 = 150;
10
            myLine.X2 = 50;
11
            myLine.Y1 = 150;
12
            myLine.Y2 = 50;
13
            myLine.HorizontalAlignment = HorizontalAlignment.Left;
14
            myLine.VerticalAlignment = VerticalAlignment.Center;
15
            myLine.StrokeThickness = 4;
16
            myGrid.Children.Add(myLine);
17
        }

von jmp (Gast)


Lesenswert?

1. Normalerweise werden Zeichenfunktionen in einem OnDraw-Event 
ausgeführt.
2. Deine Linie scheint mir ein Punkt zu sein (gleiche x- und 
y-Koordinaten)

--jmp

von Borislav B. (boris_b)


Lesenswert?

Joe schrieb:
> Sehe aber keine Linie.

Mit deinem Grid machst du ja auch nichts. Das wird gleich wieder vom 
Garbage Collector gefressen wenn die Funktion verlassen wird. Klar dass 
da nichts gezeichnet wird...

: Bearbeitet durch User
von Joe (Gast)


Lesenswert?

Ich dachte, dass in folgender Zeile "myGrid" verwendet wird:

myGrid.Children.Add(myLine);

von Karl H. (kbuchegg)


Lesenswert?

Joe schrieb:
> Ich dachte, dass in folgender Zeile "myGrid" verwendet wird:
>
> myGrid.Children.Add(myLine);

Da steht:
füge die Linie zum Grid dazu.

Gut.

Aber was ist mit dem Grid selber?
Woher soll das Window wissen, dass du diesen einen Grid angezeigt haben 
willst? Du kannst tausende Gridsd haben, jeder mit anderen Linien. Aber 
welche davon sollen denn jetzt gemalt werden und welche nicht?

von Jonas B. (jibi)


Lesenswert?

Dir fehlen ganz klar die Grundlagen in C# und WPF.
Die solltest du dir erstmal aneignen.

Gruß Jonas

von Joe (Gast)


Lesenswert?

Ok, habe verstanden.
1
public partial class MainWindow : Window
2
    {
3
        public MainWindow()
4
        {
5
            InitializeComponent();            
6
        }
7
8
        private void Window_Loaded(object sender, RoutedEventArgs e)
9
        {
10
            Line myLine = new Line();
11
            Grid myGrid = new Grid();
12
            myGrid.Width = 400;
13
            myGrid.Height = 400;
14
15
16
            myLine.Stroke = System.Windows.Media.Brushes.Black;
17
            myLine.Fill = System.Windows.Media.Brushes.Black;
18
            myLine.X1 = 100;
19
            myLine.X2 = 150;
20
            myLine.Y1 = 100;
21
            myLine.Y2 = 150;
22
            //myLine.HorizontalAlignment = HorizontalAlignment.Left;
23
            //myLine.VerticalAlignment = VerticalAlignment.Center;
24
            myLine.StrokeThickness = 4;
25
            myGrid.Children.Add(myLine);
26
27
            myGrid.ShowGridLines = true;
28
29
            this.Content = myGrid;
30
            this.Show();
31
        }
32
33
        
34
    }




Ist die verwendete Lösung sinnvoll oder wie (bzw. in welcher 
Ereignis-Funktion) integriere ich meinen Code?


GRÜSSE, JOe

von Borislav B. (boris_b)


Lesenswert?

Joe schrieb:
> Ist die verwendete Lösung sinnvoll

Nein. Das Konzept von WPF ist es Code und GUI zu TRENNEN. D.h. deine GUI 
gehört in die XAMLs, der Code in die CSs. Das manuelle Zeichnen per Code 
ist nicht sinnvoll.

von Jonas B. (jibi)


Lesenswert?

Also wenn die Linie da immer gezeichnet werden soll, also quasi Teil der 
Gui wird - dann gehört die in ein XAML Document, wird also nur 
beschrieben. Wie
die dann gezeichnet wird, darum kümmert sich die Grafikengine, die dir 
WPF freundlicherweise spendiert.

Gruß Jonas

: Bearbeitet durch User
von Joe (Gast)


Lesenswert?

Ok, sehe ich ein. Ich versuche die Linie zu bewegen, daher das Zeichnen 
im C#-Code

1
public partial class MainWindow : Window
2
    {       
3
4
        private Line myLine = new Line();
5
        private Grid myGrid = new Grid();              
6
7
8
        public MainWindow()
9
        {
10
            InitializeComponent();            
11
        }
12
13
        private void Window_Loaded(object sender, RoutedEventArgs e)
14
        {
15
            Timer myTimer = new Timer(3000);
16
17
            myTimer.Elapsed += new ElapsedEventHandler(TimerElapsed);
18
            myTimer.Enabled = true;
19
20
            myLine.Stroke = System.Windows.Media.Brushes.Black;
21
            myLine.Fill = System.Windows.Media.Brushes.Black;
22
            myLine.StrokeThickness = 4;
23
            myGrid.Children.Add(myLine);
24
            myGrid.ShowGridLines = true;
25
26
            this.Content = myGrid;
27
            this.Show();           
28
            
29
        }
30
31
32
        static void TimerElapsed(object sender, ElapsedEventArgs e)
33
        {
34
            DrawLine();
35
        }
36
37
38
        private void DrawLine()
39
        {
40
            if (this.myLine.X1 < 1900)
41
                this.myLine.X1 = this.myLine.X1 + 100;
42
            else
43
                this.myLine.X1 = 0;
44
        }
45
        
46
    }



Ich erhalte die Fehlermeldung:

Fehler  1  Für das nicht statische Feld, die Methode oder die 
Eigenschaft "DrawSomeLines.MainWindow.DrawLine()" ist ein Objektverweis 
erforderlich.  C:\Users\tt.GD\Documents\Visual Studio 
2010\Projects\DrawSomeLines\DrawSomeLines\MainWindow.xaml.cs  54  13 
DrawSomeLines


Anscheinend kann ich aus einer statischen Methode keine nicht-statische 
Methode aufrufen?

GRÜSSE; Joe

von Jonas B. (jibi)


Lesenswert?

>Anscheinend kann ich aus einer statischen Methode keine nicht-statische
>Methode aufrufen?

>>Dir fehlen ganz klar die Grundlagen in C# und WPF.
>>Die solltest du dir erstmal aneignen.

Gruß Jonas

von Jonas B. (jibi)


Lesenswert?

>Timer myTimer = new Timer(3000);

Und wieder hast du den Timer in einem Event definiert, sobald das Event 
abgearbeitet wurde frisst der GC deinen Timer...

Gruß Jonas

von Joe (Gast)


Lesenswert?

Mit diesem Beispiel versuche ich meine Grundlagen zu schaffen.


So falsch kann der Zähler nicht sein. Wenn ich statt des 
DrawLine-Aufrufes
mir eine MessageBox anzeigen lasse, so klappt das auch im 3sec-Abstand.

Kann mir jemand erklären, was bei dem Aufruf von DrawLine() falsch ist?

GRÜSSE, Joe

von Joe (Gast)


Lesenswert?

Jonas, wie würdest Du es richtig machen?

• Wo würdest Du den Timer definieren?
• Wo würdest Du nach Ablauf des Timers die neue X-Koordinate zeichnen?

von Borislav B. (boris_b)


Lesenswert?

Wenn du Animationen machen willst, geht das auch ohne so einen seltsamen 
Workaround. Das bietet WPF quasi schon von Haus aus:

http://msdn.microsoft.com/de-de/library/ms752312%28v=vs.110%29.aspx

von Joe (Gast)


Lesenswert?

Danke für den Link. Bevor ich mir den genauer anschaue, würde ich gerne 
mein Beispiel hinbekommen, mit den gezeigten Teilen.


GRÜSSE, JOE

von Karl H. (kbuchegg)


Lesenswert?

Joe schrieb:
> Mit diesem Beispiel versuche ich meine Grundlagen zu schaffen.
>

Dann empfehle ich dir dringend den Ankauf von Literatur.
Du wirst hier im Forum niemanden finden, der dir einen 300 Seiten C# 
Schmöker anlassbezogen vorbetet.


> So falsch kann der Zähler nicht sein. Wenn ich statt des
> DrawLine-Aufrufes
> mir eine MessageBox anzeigen lasse, so klappt das auch im 3sec-Abstand.

Das hängt ganz davon ab, wann der Garbage Collector dann irgendwann mal 
das Timer-Objekt entsorgt.

> Kann mir jemand erklären, was bei dem Aufruf von DrawLine() falsch ist?

die Funktion ist static, gehört also zu keinem spezifischen Objekt, 
sondern hängt nur allgemein so in der Klasse rum, damit sie im 
Namensraum der Klasse existiert. Aber wenn sie aufgerufen wird, dann 
wird sie nicht für irgend ein spezifisches Objekt aufgerufen. Ergo 
kannst du auch nicht auf nicht-statische Dinge in deiner Klasse 
zugreifen, denn die sind ja an ein einziges, bestimmtes Objekt gebunden 
(jedes jemals derartige Objekt hat seine eigenen Satz an 
nicht-statischen Variablen).


> • Wo würdest Du den Timer definieren?

Den Timer muss es geben, so lange es das Window gibt.
Genauso wie den Grid oder (bei dir momentan) die Linie.
Also: Wo und wie hast du den Grid und die Linie definiert bzw. erzeugt 
und warum hast du das mit dem Timer nicht genauso gemacht?

: Bearbeitet durch User
von Joe (Gast)


Lesenswert?

OK, danke für Eure Vorschläge und Erläuterungen.


Folgender modifizierter Code lässt sich starten, hat dann aber einen 
Laufzeitfehler:
1
namespace DrawSomeLines
2
{
3
    /// <summary>
4
    /// Interaktionslogik für MainWindow.xaml
5
    /// </summary>
6
    public partial class MainWindow : Window
7
    {       
8
9
        private Line myLine = new Line();
10
        private Grid myGrid = new Grid();              
11
12
13
        public MainWindow()
14
        {
15
            InitializeComponent();            
16
        }
17
18
        private void Window_Loaded(object sender, RoutedEventArgs e)
19
        {
20
            Timer myTimer = new Timer(3000);
21
22
            myTimer.Elapsed += new ElapsedEventHandler(TimerElapsed);
23
            myTimer.Enabled = true;
24
25
            myLine.Stroke = System.Windows.Media.Brushes.Black;
26
            myLine.Fill = System.Windows.Media.Brushes.Black;
27
            myLine.StrokeThickness = 4;
28
            myLine.X1 = 100;
29
            myLine.Y1 = 200;
30
            myGrid.Children.Add(myLine);
31
            myGrid.ShowGridLines = true;
32
33
            this.Content = myGrid;
34
            this.Show();           
35
            
36
        }
37
38
39
        private void TimerElapsed(object sender, ElapsedEventArgs e)
40
        {
41
            DrawLine();            
42
            
43
        }
44
45
46
        private void DrawLine()
47
        {
48
            if (this.myLine.X1 < 1900)   //(*)
49
                this.myLine.X1 = this.myLine.X1 + 100;
50
            else
51
                this.myLine.X1 = 0;
52
        }
53
        
54
    }
55
}




Fehlermeldung: (*)
Der aufrufende Thread kann nicht auf dieses Objekt zugreifen, da sich 
das Objekt im Besitz eines anderen Threads befindet.



GRÜSSE, JOE

von Borislav B. (boris_b)


Lesenswert?

Joe schrieb:
> Der aufrufende Thread kann nicht auf dieses Objekt zugreifen, da sich
> das Objekt im Besitz eines anderen Threads befindet.

Dann weißt du ja wo das Problem liegt und kannst es beheben.

Willst jetzt hier wirklich mit JEDEM Problem aufschlagen anstatt einfach 
mal ein Tutoarial/Buch durchzuarbeiten?

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Tja.
da wird dann eben wahrscheinlich ein Invoke fehlen.

Vielleicht verstehst du jetz schön langsam, warum die Methode 'Ich 
probier einfach so lange rum bis xyz (zutreffendes einsetzen)' nicht 
funktioniert. Es gibt hunderte (wenn nicht sogar tausende) Dinge, die du 
wissen und beherrschen musst. Und nur wenn du alle beherrscht, dann 
landest du auch bei einem sauberen Programm. Nur: woher sollst du denn 
das alles wissen, was es zu beachten gilt? Eben. Du kannst es nicht 
wissen. Aber dein Buch weiß es.

: Bearbeitet durch User
von Joe (Gast)


Lesenswert?

Hmmm, ok. Ich habe ein Buch: "Einstieg in Visual C# 2010"

Dort finde ich leider nicht viel zu WPF und auch nicht wie
ich Multi-Threading mache. Die Frage ist doch, wie kann ich obiges 
Beispiel
sauber und simpel lösen. Wenn ich Schritte zur Lösung erfahre, dann 
lerne ich
doch am besten oder nicht? Weil ich dann nämlich weiß, wie man es 
richtig macht.

>Es gibt hunderte (wenn nicht sogar tausende) Dinge, die du
>wissen und beherrschen musst.

JA, das gebe ich Dir Recht. Man muss aber am lebenden Beispiel erfahren 
und lernen, was man alles falsch machen kann. Die Beispiele im Buch sind 
immer
sehr simpel und funktionieren natürlich immer.

Grüsse, JOE

von Karl H. (kbuchegg)


Lesenswert?

Joe schrieb:
> Hmmm, ok. Ich habe ein Buch: "Einstieg in Visual C# 2010"
>
> Dort finde ich leider nicht viel zu WPF und auch nicht wie
> ich Multi-Threading mache.

Ich kann mir nicht vorstellen, dass Invoke da drinnen nicht beschrieben 
ist. Denn das, und das Zusammenspiel mit Delegates, braucht man 
eigentlich alle Nase lang, wenn man C# mit .Net einsetzt.

Insofern hat das nichts mit WPF zu tun. WPF ist ja nur ein Framework, 
welches dir eine bestimmte Organisation vorgibt. Die Basismechanismen, 
wie die Dinge in C# funktionieren sind ja nach wie vor dieselben.

> JA, das gebe ich Dir Recht. Man muss aber am lebenden Beispiel erfahren
> und lernen, was man alles falsch machen kann. Die Beispiele im Buch sind
> immer
> sehr simpel und funktionieren natürlich immer.

Die Beispiele schweben aber nicht im freien Raum, sondern sind in 
Kapitel eingebettet in denen Erläuterungen stehen. Das wichtige sind ja 
nicht die Beispiele, sondern dass man versteht, worum es im jeweiligen 
Kapitel geht.
D.h. man muss so ein Buch auch durcharbeiten! Kapitel für Kapitel lesen, 
darüber nachdenken was man gelesen hat, die Beispiele als Illustration 
des gelesenen nehmen und im Idealfall dann auch ein wenig abwandeln bzw. 
zur Selbstkontrolle selbst ein paar Beispiele dazu erfinden, wenn am 
Kapitelende keine Übungsbeispiele angegeben sind.

Dann wird das auch was.

von Joe (Gast)


Lesenswert?

>Ich kann mir nicht vorstellen, dass Invoke da drinnen nicht beschrieben
>ist. Denn das, und das Zusammenspiel mit Delegates, braucht man
>eigentlich alle Nase lang, wenn man C# mit .Net einsetzt.

Zumindest im Stichwortverzeichnis finde ich "Invoke" und "Delegates" 
nicht.

von Eugler (Gast)


Lesenswert?

Joe schrieb:
>>Ich kann mir nicht vorstellen, dass Invoke da drinnen nicht
> beschrieben
>>ist. Denn das, und das Zusammenspiel mit Delegates, braucht man
>>eigentlich alle Nase lang, wenn man C# mit .Net einsetzt.
>
> Zumindest im Stichwortverzeichnis finde ich "Invoke" und "Delegates"
> nicht.

http://technet.microsoft.com/de-de/

Manchmal verstehe ich es nicht ... .

von Joe (Gast)


Lesenswert?

Manchmal verstehe ich die Arroganz einiger Forums-"Teilnehmer" auch 
nicht ;-)

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.