Autor Beitrag
C#
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: Fr 10.10.14 08:36 
Morgähn,

gibt es eine Möglichkeit, den setter einer Eigenschaft auszulösen, wenn eine Eigenschaft dieser Eigenschaft geändert wird? :gruebel:
Z.B. habe ich eine Klasse Rect. In dieser Klasse befindet sich ein  Point Position. Kann ich in der Rect-Klasse prüfen ob die X oder Y Koordinate von Position geändert wurde?

_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
freak4fun
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 604
Erhaltene Danke: 4

Win 7 Pro
VS 2013 Express, Delphi, C#, PHP, Java
BeitragVerfasst: Fr 10.10.14 09:21 
Ja. Vor dem setzen den neuen mit dem alten wert vergleichen. :think:

_________________
"Ich werde auf GAR KEINEN Fall…!" - "Keks?" - "Okay, ich tu's."
i++; // zaehler i um 1 erhoehen
C# Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: Fr 10.10.14 09:27 
Ja clever :D
Der setter wird aber nicht aufgerufen! Genau das ist ja mein Problem. Meine Klasse bekommt nicht mit, wenn der Wert geändert wird.

_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: Fr 10.10.14 09:31 
Setze doch einfach den gleichen Wert nochmal?
Dann wird der Setter aufgerufen, wobei das meiner Meinung nach aber irgendwie falsch klingt.

Warum genau soll der Setter denn aufgerufen werden?
Zeig mal ein Code-Beispiel, das verstehe ich glaube ich besser :D
freak4fun
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 604
Erhaltene Danke: 4

Win 7 Pro
VS 2013 Express, Delphi, C#, PHP, Java
BeitragVerfasst: Fr 10.10.14 09:31 
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
public class MyClass
  {
    private Point _Position;
    public Point Position
    {
      set { 
        if(this._Position.X != value.X)
        {
          MessageBox.Show("X hat sich verändert!");
        }
        if(this._Position.Y != value.Y)
        {
          MessageBox.Show("Y hat sich verändert!");
        }
        this._Position = value;
      }
      get { return this._Position; }
    }
  }


ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
  public partial class Form1 : Form
  {

    MyClass mc;

    public Form1()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
    
      Point p = new Point( int.Parse(textBox1.Text), int.Parse(textBox2.Text));
      this.mc.Position = p;
    }

    private void Form1_Load(object sender, EventArgs e)
    {
      mc = new MyClass();
    }
  }

_________________
"Ich werde auf GAR KEINEN Fall…!" - "Keks?" - "Okay, ich tu's."
i++; // zaehler i um 1 erhoehen
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4701
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Fr 10.10.14 09:49 
Das wird nicht funktionieren. Schon deshalb weil Point ein struct ist.
Der Zugriff auf den getter wird dir eine Kopie des Point liefern. Diese Kopie hat keinerlei Bezug zu ihrer Quelle.
Bei structs solltest du am besten immer davon ausgehen das die unveränderlich sind. Heißt wenn du die Position ändern willst ist es ein neuer Point struct.
Das Problem kannst du zum Beispiel ausprobieren wenn du versuchst in Winforms ein Control zu verschieben. Control.Location.X = neuer Wert wird zu keiner Veränderung führen da der Zugriff auf Control.Location dir bereits eine Kopie liefert. Und das ändern der Kopie natürlich keinerlei Auswirkung hat.


Dein Eigenschaften von Eigenschaften Überwachen Problem kannst du eigentlich nur mit einer eigene Klasse (kein struct) lösen das passende Events wirft die von der ~Owner~ Klasse gefangen werden und dann entsprechend ausgewertet wird.

Für diesen Beitrag haben gedankt: C#
C# Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: Fr 10.10.14 10:02 
Das dachte ich mir schon... Aber mit events möchte ich nicht arbeiten. Dann mache ich aus meiner klasse eine Struktur das geht in Ordnung. Grund des ganzen ist, dass ich eine neue Klasse für rectangle erstelle. Die Positionen sind als Vektoren angegeben (auch eigene klasse).

_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4701
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Fr 10.10.14 11:26 
Zitat:
Das dachte ich mir schon... Aber mit events möchte ich nicht arbeiten.


Das ist vermutlich auch besser so ;)
Das verdrahten von Events bzw. das nicht benutzen von structs (aka keine Kopien) hätte dann andere Probleme wenn man das Objekt versuchst an anderer Stelle wiederzuverwenden und man eben keine Kopie hat.

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
var one = new MyClass();
one.Position = new Point(5,5);
var two = new MyClass()
two.Position = one.Position;

two.Position.X = 10;


Je nachdem wie ~intelligent~ man das geregelt hat würde sich nun one and two verschieben oder nur one. Beides wäre offensichtlich falsch. Das Point Kopiersemantik benutzt ist gut so ;)
freak4fun
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 604
Erhaltene Danke: 4

Win 7 Pro
VS 2013 Express, Delphi, C#, PHP, Java
BeitragVerfasst: Fr 10.10.14 11:48 
user profile iconRalf Jansen hat folgendes geschrieben Zum zitierten Posting springen:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
var one = new MyClass();
one.Position = new Point(5,5);
var two = new MyClass()
two.Position = one.Position;

two.Position.X = 10;


Je nachdem wie ~intelligent~ man das geregelt hat würde sich nun one and two verschieben oder nur one. Beides wäre offensichtlich falsch. Das Point Kopiersemantik benutzt ist gut so ;)


Wie kommst du darauf?

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
var one = new MyClass();
one.Position = new Point(5,5);
var two = new MyClass();
two.Position = one.Position;

two.Position = new Point(105);

MessageBox.Show("two.Position.X: " + two.Position.X.ToString());
MessageBox.Show("one.Position.X: " + one.Position.X.ToString());

Zitat:
"two.Position.X: 10"
"one.Position.X: 5"



Wo ist das Problem?

_________________
"Ich werde auf GAR KEINEN Fall…!" - "Keks?" - "Okay, ich tu's."
i++; // zaehler i um 1 erhoehen
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4701
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Fr 10.10.14 12:02 
Zitat:
two.Position = one.Position;

two.Position = new Point(10, 5);


a.) Da ist die erste Zuweisung natürlich unnötig.
und
b.) impliziert die Anforderung von C# das Point nicht kopiert wird bei Zuweisung was es im Moment tut da es ein struct ist. Wenn es nicht kopiert wird würde aber one und two auf die gleiche Point Instanz schauen. Sie hätten also gar keine unabhängige Position. Nachvollziehen kannst du das natürlich nicht mit der jetzigen Point struct sondern nur indem du Point nachschreibst als Klasse. Dann wäre C# Wunsch nähernungsweise erfüllbar. Es würden sich aber dafür andere Merkwürdigkeiten/Probleme einschleichen wie zum Beispiel die von mir gezeigte.
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: Fr 10.10.14 13:25 
Ralf, warum funktioniert das oben genannte Beispiel von C# nicht?
Natürlich wird im Speicher eine neue Point-"Instanz" erzeugt, wenn eine der Properties geändert wird, allerdings soll doch nur verglichen werden.

So wie ich das sehe, möchte er, dass eine Meldung ausgegeben wird, dass sich bei der Zuweisung des neuen Wertes tatsächlich etwas geändert hat.
Das kenne ich, wenn ich INotifyPropertyChanged implementiere. Ich prüfe erst, ob der ursprüngliche Wert ungleich dem neuen Wert ist. Wenn dem so ist, wird geändert und PropertyChanged geworfen, andernfalls nicht.
In diesem Fall soll das genauso ablaufen (nur mit einer MessageBox), allerdings soll nicht nur angezeigt werden, dass sich etwas ändert, sondern was im Inhalt sich konkret geändert hat.

Oder sehe ich da etwas falsch?
freak4fun
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 604
Erhaltene Danke: 4

Win 7 Pro
VS 2013 Express, Delphi, C#, PHP, Java
BeitragVerfasst: Fr 10.10.14 13:34 
Ich hab es so verstanden, das er eine Variable vom Typ Point hat und nun einfach informiert werden will wenn sich daran was ändert. Der Rest ist Beiwerk. :roll:
Wenn er einen Point in seiner Klasse hat ist das immer nur eine Kopie des Original-Point. Da bekommt er auch keine Meldung wenn sich der Original-Point ändert.

Entweder er kapselt den Zugriff auf den Original-Point oder überdenkt sein Konzept.

_________________
"Ich werde auf GAR KEINEN Fall…!" - "Keks?" - "Okay, ich tu's."
i++; // zaehler i um 1 erhoehen
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4701
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Fr 10.10.14 14:25 
Zitat:
Ralf, warum funktioniert das oben genannte Beispiel von C# nicht?

Das Beispiel das er zeigt hat auch kein Problem. Es zeigt ja nicht was er mit Position machen will ;)

Ich kann nur zwischen den Zeilen lesen das er sowas wollte wie MyClass.Position.X = 5; und dann im Position Setter irgendwie auf die Änderung von x zu reagieren.
Die Möglichkeit der Zuweisung eines neuen Points ist davon unberührt da kann man natürlich irgendwelche Test in den Setter einbauen ob sich der neue Point vom alten unterscheidet. Aber das war ja der Ausgangspunkt der Frage das sein Setter nicht aufgerufen wurde was nur Sinn macht wenn er auf erstgenannten aus war ohne Zuweisung eines neuen Point.
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: Fr 10.10.14 15:07 
Das würde nur via INotifyPropertyChanged gehen, man kann Interfaces doch auch in ein Struct implementieren?
Allerdings würde das dann eine neue Point-Struktur fordern.

Oder das ganze wird mit einer Klasse umgangen, die ICloneable implementiert und bei dem Setzen einer Instanz in eine Property wird nicht die tatsächliche Eigenschaft gesetzt, sondern eine Kopie davon.
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4701
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Fr 10.10.14 16:44 
Klar wär das möglich aber du läufst dann eben in andere Probleme die ich mit dem Beispiel, 2 Klassen teilen sich plötzlich eine Position, zeigen wollte.
Du kannst dann die Klasse nicht einfach unbedacht woanders verwenden weil da eben noch eine Eventverdrahtung lebt und dann unerwartete Dinge passieren.
Das Problem kann diese potentielle neue Point Klasse auch nicht aus sich selber heraus lösen. Alle beteiligten Klassen müßten dann so clever sein beim zuweisen je nach Notwendigkeit mal doch eine Kopie anzufertigen oder Events zu verdrahten bzw. abzuhängen. Ist denke das ist zu fehleranfällig.

Die Ursünde war Point überhaupt Setter für X und Y zu geben. Ohne die wäre klar das ändern nur über den Konstruktor geht und auch nur das sinnvoll ist. Aber nachher ist man immer schlauer ;)
C# Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: Fr 10.10.14 17:09 
Alsooooo um hier mal aufzuräumen:
Ich habe eine Klasse (mittlerweile ist es eine Struktur):
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
struct Vector2
{
    public float X {get; set;}

    publif float Y {get; set;}
    
    ...
}

und
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
class Rect
{
public Vector2 Position
        {
            get { return position; }
            set
            {
                if (position == value) return;

                position = value;
                center = value + Size / 2;
                topRight = new Vector2(value.X + Size.X, value.Y);
                bottomLeft = new Vector2(value.X, value.Y + Size.Y);
                bottomRight = value + Size;
            }
        }

        public Vector2 Center
        {
            get { return center; }
            set
            {
                if (center == value) return;

                center = value;
                position = value - Size / 2;
                topRight = new Vector2(value.X + Width / 2, value.Y - Height / 2);
                bottomLeft = new Vector2(value.X - Width / 2, value.Y + Height / 2);
                bottomRight = value + Size / 2;
            }
        }
}

...


Und was ich gerne gehabt hätte ist, dass wenn die Position geändert wird (via Position.X bzw. Position.Y) der Setter der Position-Eigenschaft aufgerufen wird, damit ich die anderen Variablen updaten kann.

_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Fr 10.10.14 17:20 
user profile iconPalladin007 hat folgendes geschrieben Zum zitierten Posting springen:
Das würde nur via INotifyPropertyChanged gehen, man kann Interfaces doch auch in ein Struct implementieren?

Interfaces für Strukturen sind eine schlechte Idee, s. z.B. C#: structs and Interface
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4701
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Fr 10.10.14 17:27 
Pragmatische Lösung a.) Setter von X und Y in Vector2 (dann Vector 2 als struct) entfernen somit nur noch Ändern über Konstruktor möglich und damit implizit Rect.Position nur änderbar durch neu zuweisen.

Pragmatische Lösung b.) Vector2 wie du es zeigst (als Klasse) aber dann sollte Vector2 wie Paladin vorschlägt INotifyPropertyChanged implementieren und Rect entsprechend die Events fangen und darauf reagieren lassen. Dann darf Rect aber auf keinen Fall noch einen Setter für Position haben sondern Rect sollte nur eine intern selbst erzeugte Vector2 Instanz per Getter veröffentlichen(deine jetzigen Prüfungen im setter gehören dann in den PropertyChanged EventHandler) . Die Probleme die durch das Verschieben einer Vector2 Instanz zwischen rect Klassen enststehen würden sind kaum zu beherschen und solltest du so verhindern.
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: Fr 10.10.14 18:55 
Nutzt du das für eine Oberfläche?
Für DataBinding (was ja INotifyPropertyChanged nutzt), würde ich dann vermutlich eine Klasse schreiben, die im Grunde genau das tut, wie Point und gleichzeitig eine Konvertierung in den eigentlichen Point-Wert anbietet. Dafür können ja Casting-Operatoren definiert werden.
Dann kannst du die Klasse ganz normal nutzen, wie jede Andere auch.
Die eigentliche Programm-Logik arbeitet mit dem Point-Wert (struct in .NET), während die GUI die Point-Referenz (eigene KLasse) bekommt.


Ich glaube, besser geht es nicht.
C# Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: Fr 10.10.14 20:12 
Ich bleibe jetzt bei struct. Ich möchte auf keinen Fall events hier einbauen, weil diese Typen Grundbausteine meiner Bibliothek sind. Das sollen ganz einfache Datentypen bleiben, die nur für Berechnungen sind. Wie halt auch Point und Rectangle. Die sollten auch etwas performant sein und nicht bei jedem Aufruf 100 verkettete Methoden kreuz und quer aufrufen.

_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler