Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Auf Übergeordnete Eigenschaften zugreifen
fritziiiii
myCSharp.de - Member



Dabei seit:
Beiträge: 8

Themenstarter:

Auf Übergeordnete Eigenschaften zugreifen

beantworten | zitieren | melden

Hi,
bitte verzeiht meinen blöden Betreff, aber ich weiß nicht wie ich mein Problem besser bezeichnen könnte:

Ausgangslage:
- ich habe eine Klasse "EinzelnesElement"

- ich habe eine Klasse "Basisklasse"
In dieser Basisklasse erzeuge ich eine ObservableCollection<EinzelnesElemente> ListeElemente
In der Basisklasse ist zudem die Eigenschaft "Status" deklariert.

Nun zum Problem:
Ich würde in der Klasse "EinzelnesElement" zu gern den Wert der Eigenschaft "Status" abfragen!
Wie krieg ich das hin?


namespace WpfApp1
{
    public class EinzelnesElemente : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if (PropertyChanged != null) PropertyChanged(this, e);
        }

        public string Name { get; set; }

        public void StatusAbfragen()
        {
            // hier würd ich gern den Status der Basisklasse abfragen
        }
    }


    public class Basisklasse : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if (PropertyChanged != null) PropertyChanged(this, e);
        }

        public ObservableCollection<EinzelnesElemente> ListeElemente = new ObservableCollection<EinzelnesElemente>();

        public int Status = 5;

    }

        /// <summary>
        /// Interaktionslogik für MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
    {
        public MainWindow()
        {

            Basisklasse basis = new Basisklasse();
            basis.ListeElemente.Add(new EinzelnesElemente());
            InitializeComponent();
        }
    }
}

private Nachricht | Beiträge des Benutzers
Deaktiviertes Profil
myCSharp.de - Member



Dabei seit:
Beiträge: 996

beantworten | zitieren | melden

Da wirst du irgendwie an EinzelnesElemente eine Referenz zu der Basisklasse übergeben müssen, sonst geht das nicht.

Wenn du nicht weißt in welchem Haus du wohnst, wie sollst du wissen wie es aussieht?
private Nachricht | Beiträge des Benutzers
OlafSt
myCSharp.de - Member



Dabei seit:
Beiträge: 76
Herkunft: HH

beantworten | zitieren | melden

Oder indem man schlicht und ergreifend

EinzelnesElement
von

BasisKlasse
ableitet...
private Nachricht | Beiträge des Benutzers
pinki
myCSharp.de - Member

Avatar #avatar-4072.jpg


Dabei seit:
Beiträge: 706
Herkunft: OWL

beantworten | zitieren | melden

Sir Rufos Antwort erscheint mir schlüssiger.

Schau dir mal folgenden Fall an:
Es gibt ein Basisklassenobjekt und 5 EinzelnesElemente-Objekte, die sich in ListeElemente der Basisklasse befinden.
Man will jetzt auf den Status zugreifen.

Bei einer Ableitung hat jedes Objekt seinen eigenen Status und weiß immer noch nichts über den Status des Objekts, in dessen ListeElemente man sich befindet.
private Nachricht | Beiträge des Benutzers
fritziiiii
myCSharp.de - Member



Dabei seit:
Beiträge: 8

Themenstarter:

beantworten | zitieren | melden

Schonmal danke für eure Antworten.
Habe nun meinen Code angepaßt, aber der Groschen ist noch nicht ganz gefallen

die Basisklasse habe ich um die Methode "ElementHinzufuegen ergänzt. In dieser Methode gebe ich eine Referenz auf die Variable "Status"

public void ElementHinzufuegen(ref int status)
        {
            ListeElemente.Add(new EinzelnesElemente(ref status));
        }

In der Klasse "EinzelnesElement" habe ich einen Konstruktor eingefügt, der die Referenz entgegennimmt

 public EinzelnesElemente(ref int status)
        {
            Status = status; 
        }
Aber jetzt komm ich nicht weiter. Was muß ich machen, damit ich in der Klasse mit der Referenz weiterarbeiten kann und NICHT als neue Variable ablege?

namespace WpfApp1
{
    public class EinzelnesElemente : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if (PropertyChanged != null) PropertyChanged(this, e);
        }

        int Status;

        // Konstruktor
        public EinzelnesElemente(ref int status)
        {
            Status = status;  //Baustelle
        }
        

        public string Name { get; set; }

        public string StatusAbfragen()
        {
            return Convert.ToString(Status);
        }



    }


    public class Basisklasse : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if (PropertyChanged != null) PropertyChanged(this, e);
        }

        public ObservableCollection<EinzelnesElemente> ListeElemente = new ObservableCollection<EinzelnesElemente>();

        public int Status = 5;
        

        public void ElementHinzufuegen(ref int status)
        {
            ListeElemente.Add(new EinzelnesElemente(ref status));
        }

    }

    public partial class MainWindow : Window
    {
        Basisklasse basis = new Basisklasse();
        public MainWindow()
        {
            basis.ElementHinzufuegen(ref basis.Status);

            InitializeComponent();
           
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            basis.Status = 7;
        }

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
          
            Label_Ausgabe.Content = basis.ListeElemente[0].StatusAbfragen();
        }
    }
}
private Nachricht | Beiträge des Benutzers
inflames2k
myCSharp.de - Experte

Avatar #AARsmmPEUMee0tQa2JoB.png


Dabei seit:
Beiträge: 2361

beantworten | zitieren | melden

Was Sir Rufo meinte war eher der Ansatz, dass deine Elemente eine Referenz auf den Parent haben.

In deinem Fall:


public class EinzelnesElement
{
      private BasisKlasse _parent;
    
      public EinzelnesElement(Basisklasse parent)
      {
          this._parent = parent;
      }

      public void StatusAbfragen()
      {
           // wie auch immer deine Statusabfrage aussieht
           this._parent.Status ??? 
      }
}
Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager | Spielkartenbibliothek
private Nachricht | Beiträge des Benutzers
fritziiiii
myCSharp.de - Member



Dabei seit:
Beiträge: 8

Themenstarter:

beantworten | zitieren | melden

Danke!

Das war die Lösung!
private Nachricht | Beiträge des Benutzers
ThomasE.
myCSharp.de - Member



Dabei seit:
Beiträge: 453

beantworten | zitieren | melden

Also ich hätte in der Klasse EinzelnesElemente ein Event eingebaut, welches den aktuellen Status besorgt.

Somit müßte die Basisklasse das Event eines jeden Eintrags registrieren.
Dadurch fällt die Abhängigkeit des Klassenverweises von Basisklasse aus EinzelnesElemente weg.

Ist dann die andere Lösung, im Gegensatz zu @Sir Rufo's Vorschlag.
Ich habe den Titel mal angepasst, so dass Suchende auch etwas damit anfangen können. EDIT: Ich sollte beim Wort "Shift" im Titel das "f" nicht vergessen...
private Nachricht | Beiträge des Benutzers
inflames2k
myCSharp.de - Experte

Avatar #AARsmmPEUMee0tQa2JoB.png


Dabei seit:
Beiträge: 2361

beantworten | zitieren | melden

Hallo ThomasE,

deine Lösung ist natürlich die sauberere. Für den aktuellen Anwendungsfall, nehme ich aber an dass diese EinzelElemente nur Bestandteil von "BasisKlasse" sind und damit eine feste Kopplung möglich ist.

Spätestens wenn fritziiiii die Elemente noch an anderer Stelle initialisiert die nichts mit "BasisKlasse" zu tun hat sollte er natürlich die saubere Umsetzung in Betracht ziehen und über Events den Status anfragen.
Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager | Spielkartenbibliothek
private Nachricht | Beiträge des Benutzers
p!lle
myCSharp.de - Member

Avatar #avatar-3556.jpg


Dabei seit:
Beiträge: 1053

beantworten | zitieren | melden

Wie genau soll die (sauberere) Lösung mit dem Event im EinzelnesElement aussehen?
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von p!lle am .
private Nachricht | Beiträge des Benutzers
FZelle
myCSharp.de - Experte



Dabei seit:
Beiträge: 10084

beantworten | zitieren | melden

Das Event kommt an die klasse die das Ereignis auslöst.

Aber Ich denke eher das fritziiiii nicht mal verstanden hat was INotifyPropertyChanged bedeutet bzw. wie man es tatsächlich anwendet, denn einfach nur das Interface grob implementieren bringt überhaupt nix, wenn man keine Properties implementiert .

Ansonsten müsste man ja nur INPC von der Basisklasse abonieren und entsprechend reagieren.
private Nachricht | Beiträge des Benutzers
MrSparkle
myCSharp.de - Team

Avatar #avatar-2159.gif


Dabei seit:
Beiträge: 5992
Herkunft: Leipzig

beantworten | zitieren | melden

Wie man die INotifyPropertyChanged-Schnittstelle richtig implementiert und verwendet, ist in [Artikel] MVVM und DataBinding beschrieben. Der Rest sind dann eher Grundlagen der Objektorientierten Programmierung.
Weeks of programming can save you hours of planning
private Nachricht | Beiträge des Benutzers
fritziiiii
myCSharp.de - Member



Dabei seit:
Beiträge: 8

Themenstarter:

beantworten | zitieren | melden

Hallo FZelle,

keine Frage, ich bin bestimmt nicht die hellste Kerze auf der Torte, was Programmierung angeht.
Zu meiner Verteidigung muß ich jedoch anfügen, daß ich aus meinem bestehenden Projekt Code-Bruckstücke herausgenommen habe, und daraus ein Grundgerüst für meine Fragestellung hier aufgebaut habe. Das INotifyPropertyChanged hab ich einfach nur vergessen herauszunehmen. Mein Hauptaugenmerk war darauf gerichtet, einen kurzen, auf das Kernproblem zielenden Code zu liefern.

Da du dich ja scheinbar mit Events auskennst, würde es mich freuen, wenn du mein Code-Beispiel so abänderst, daß es mit Events funktioniert. P!lle scheint das ja durchaus auch zu interessieren.

Gruß
Fritziiiii
private Nachricht | Beiträge des Benutzers
MrSparkle
myCSharp.de - Team

Avatar #avatar-2159.gif


Dabei seit:
Beiträge: 5992
Herkunft: Leipzig

beantworten | zitieren | melden

Hi fritziiiii,

wir helfen ja gerne weiter, aber das Forum ist nicht dazu da, dir deinen Code zu schreiben. Davon würdest du ja auch nichts lernen.

Wenn du dich nicht mit Events auskennst, dann kannst du dir die Beispiele in der Doku anschauen, oder die entsprechenden Kapitel im OpenBook vom Rheinwerk-Verlag:

Niemand wird mit Programmierkenntnissen geboren, aber wenn du dir die Basics nicht anliest, dann wirst du es auch nicht lernen.

Hier gibt es auch noch ein paar interessante Links für den Einstieg: [FAQ] Wie finde ich den Einstieg in C#?

Bitte beachte auch [Hinweis] Wie poste ich richtig?, besonders Punkt 1.1 und 4.
Weeks of programming can save you hours of planning
private Nachricht | Beiträge des Benutzers
FZelle
myCSharp.de - Experte



Dabei seit:
Beiträge: 10084

beantworten | zitieren | melden

@fritziiiii:
Deine Herangehensweise ist vollkommen falsch.

Du nimmst irgendwelche brocken und versuchst die zusammenzustockeln ohne zu verstehen was die machen.

Stell dir vor du baust ein Fahrrad, dazu nimmst du 2 Räder, einen rahmen, Lenker usw.
Dann schaust du wie die irgendwie zusammengehören und machst dann den lenker an die Pedale, die Räder an den Sattel und fragst dich warum das nicht fährt.

Genauso ist das hier auch.
Du musst dir erst die Grundlagen aneignen, danach kannst du erst mit dem Probieren anfangen.

Schon die Aussage das INPC hier versehentlich noch dran ist, und dann auch noch falsch implementiert, aber in Wirklichkeit die Lösung zu deinem Problem wäre, zeigt das du wegen fehlender Grundlagen den Wald vor lauter Bäumen nicht siehst.

Erstmal eine echte Basisklasse die mal INPC "richtiger" implementiert


public class BaseViewModel : INotifyPropertyChanged, IDisposable
{
	public event PropertyChangedEventHandler PropertyChanged;
	protected virtual void OnPropertyChanged(string propertyName)
	{
		var handler = PropertyChanged;
		if (handler != null) 
			handler(this, new PropertyChangedEventArgs(propertyName));
	}
	protected bool SetProperty<T>(ref T oldValue, T newValue, [CallerMemberName]string propertyName = null)
	{
		if (oldValue == null && newValue == null)
		{
			return false;
		}

		if ((oldValue == null && newValue != null) || !oldValue.Equals(newValue))
		{
			oldValue = newValue;
			OnPropertyChanged(propertyName);
			return true;
		}

		return false;
	}
	protected virtual void Dispose(bool disposing)
	{
	}
	public void Dispose()
	{
		Dispose( true );
	}
	
}

Und nun die beiden klassen


public class EinzelnesElemente : BaseViewModel
{
	private int m_BasisStatus;
	// Konstruktor
	public EinzelnesElemente(Basisklasse basisKlasse)
	{
		basisKlasse?.PropertyChanged += BasisPropertyChanged;
	}
	protected override void Dispose(bool disposing)
	{
		basisKlasse?.PropertyChanged -= BasisPropertyChanged;
	}

	protected void BasisPropertyChanged(object sender, PropertyChangedEventArgs e)
	{
		if( e.PropertyName == "Status")
		{
			m_BasisStatus = (sender as Basisklasse).Status;
		}
	}

	public string Name 
	{ 
		get { return m_Name;}
		set { SetProperty<string>(m_Name,value); }
	} string m_Name;

	public string StatusAbfragen()
	{
		return Convert.ToString(m_BasisStatus);
	}
}
public class Basisklasse : BaseViewModel
{
	public ObservableCollection<EinzelnesElemente> ListeElemente = new ObservableCollection<EinzelnesElemente>();

	public int Status
	{
		get { return m_Status;}
		set { SetProperty<int>(ref m_Status, value);}
	} int m_Status;

	public void ElementHinzufuegen(ref int status)
	{
		ListeElemente.Add(new EinzelnesElemente(this));
	}
}
private Nachricht | Beiträge des Benutzers
fritziiiii
myCSharp.de - Member



Dabei seit:
Beiträge: 8

Themenstarter:

beantworten | zitieren | melden

Hi FZelle,

danke für deine Antwort. Werde vermutlich jetzt erstmal eine gewisse Zeit brauchen, um das Aufzuarbeiten, was du mir präsentierst.

Aber zwei Sachen würd ich noch gerne loswerden:
Thema INotifyPropertyChanged: Die verwendete Version hab ich aus meinen C#-Buch (= Identisch mit dem Rheinwerk Openbook Kapitel 21.2, einfache Datenbindung) Das kann doch nicht sooo falsch sein, oder?

Thema 2:
Bitte ettwas Geduld mit den "Amateuren". Ich bin durchaus bemühlt, mein Wissen in C# zu vertiefen, glaube auch, mit meinem Projekt durchaus einiges gelernt zu haben, aber man stößt als Laie eben immer wieder an Probleme wo man selbst nicht weiterkommt und man Hilfe braucht, weil man gar nicht weis in welche Richtung man suchen muß
private Nachricht | Beiträge des Benutzers
ThomasE.
myCSharp.de - Member



Dabei seit:
Beiträge: 453

beantworten | zitieren | melden

Zur Ergänzung hier nun mein Lösungsvorschlag: (Angelehnt an @FZelle's BaseViewModel )


public class EinzelnesElemente : BaseViewModel
{
    // Konstruktor
    public EinzelnesElemente()
    {
    }

    // Gebundene Eigenschaft(en)
    public string Name
    {
        get { return m_Name;}
        set { SetProperty<string>(m_Name,value); }
    } string m_Name;

    
    public string StatusAbfragen()
    {
        if(this.HoleAktuellenStatusEvent == null) return null;

        HoleAktuellenStatusEventArgs args = new HoleAktuellenStatusEventArgs();
        this.HoleAktuellenStatusEvent(this, args);  

        return args.AktuellerStatus.ToString();
    }

    public event EventHandler<HoleAktuellenStatusEventArgs> HoleAktuellenStatusEvent;
}

public class Basisklasse : BaseViewModel
{
    public ObservableCollection<EinzelnesElemente> ListeElemente = new ObservableCollection<EinzelnesElemente>();

    public int Status
    {
        get { return m_Status;}
        set { SetProperty<int>(ref m_Status, value);}
    } int m_Status;

    public void ElementHinzufuegen(ref int status)
    {
        EinzelnesElemente einElement = new EinzelnesElemente();
        einElement.HoleAktuellenStatusEvent += this.EinzelnesElemente_HoleAktuellenStatusEvent;
        this.ListeElemente.Add(einElement);
    }

    // Event(s)
    private void EinzelnesElemente_HoleAktuellenStatusEvent(object sender, HoleAktuellenStatusEventArgs args)
    {
        args.AktuellerStatus = this.Status;
    }
}

public class HoleAktuellenStatusEventArgs : EventArgs
{
    public HoleAktuellenStatusEvent()
    {
        this.AktuellerStatus = -1;
    }

    public int AktuellerStatus {get; set;}
}

Der Sinn dahinter ist der, daß die Klasse EinzelnesElemente unabhängig von Basisklasse ist und wieder woanders verwendet werden könnte.
Ich habe den Titel mal angepasst, so dass Suchende auch etwas damit anfangen können. EDIT: Ich sollte beim Wort "Shift" im Titel das "f" nicht vergessen...
private Nachricht | Beiträge des Benutzers
p!lle
myCSharp.de - Member

Avatar #avatar-3556.jpg


Dabei seit:
Beiträge: 1053

beantworten | zitieren | melden

Also ich habe in meiner 12-jährigen Entwicklerkarriere noch nie ein Event gesehen, dass etwas abfragt und dessen EventArgs nach dem Auslösen des Events geändert werden.
Davon ab, jeder, der die Instanz des EinzelnesElemente kennt, kann sich auf das Event hängen und dann den Status ändern.

Sowas setzt doch hoffentlich niemand um?! 8o

Wir kennen zwar nicht den genauen Anwendungsfall von fritziiiii, in den meisten Fällen ist jedoch eine Abhängigkeit des Child vom Parent nicht weiter tragisch.
private Nachricht | Beiträge des Benutzers
pinki
myCSharp.de - Member

Avatar #avatar-4072.jpg


Dabei seit:
Beiträge: 706
Herkunft: OWL

beantworten | zitieren | melden

EventArgs, die geändert werden, hast du bestimmt schon bei RoutedEvents oder dem Closing-Ereignis eines Fensters gesehen.
private Nachricht | Beiträge des Benutzers
p!lle
myCSharp.de - Member

Avatar #avatar-3556.jpg


Dabei seit:
Beiträge: 1053

beantworten | zitieren | melden

Stimmt.

Sauber ist das Ganze mMn trotzdem nicht. :tongue:
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von p!lle am .
private Nachricht | Beiträge des Benutzers
Taipi88
myCSharp.de - Member

Avatar #avatar-3220.jpg


Dabei seit:
Beiträge: 1044
Herkunft: Mainz

beantworten | zitieren | melden

Hi,

naja - passt wirklich nicht so toll auf den Anwendungsfall - aber gerade in Bezug auf EventArgs kenne ich einige, die z.B. so funktioneren, dass man EventArgs.Handled = true; setzt, damit sonst keiner mehr was macht. So unüblich ist das nicht - wenn ich mich recht entsinne war das z.B. bei System.Windows.Forms irgendwo so...

LG
private Nachricht | Beiträge des Benutzers
ThomasE.
myCSharp.de - Member



Dabei seit:
Beiträge: 453

beantworten | zitieren | melden

Zitat von p!lle
Sauber ist das Ganze mMn trotzdem nicht. :tongue:
Finde ich in Ordnung.

Nur wie sonst schafft man eine saubere Trennung?

Zitat von p!lle
Davon ab, jeder, der die Instanz des EinzelnesElemente kennt, kann sich auf das Event hängen und dann den Status ändern.
Das ist ja auch Sinn und Zweck des Ganzen, hatte ich ja extra beschrieben.
Ich habe den Titel mal angepasst, so dass Suchende auch etwas damit anfangen können. EDIT: Ich sollte beim Wort "Shift" im Titel das "f" nicht vergessen...
private Nachricht | Beiträge des Benutzers
MarsStein
myCSharp.de - Experte

Avatar #avatar-3191.gif


Dabei seit:
Beiträge: 3430
Herkunft: Trier -> München

beantworten | zitieren | melden

Hallo,
Zitat
Nur wie sonst schafft man eine saubere Trennung?
Könnte man z.B. auch über ein Interface lösen:

interface IStatusHolder
{
    int Status { get; }
}

class Basisklasse: IStatusHolder
{
...
}

class EinzelnesElemente
{
    private IStatusHolder StatusHolder { get; set; }
    EinzelnesElemente(IStatusholder statusHolder)
    {
        StatusHolder = statusHolder;
    }

    public string StatusAbfragen()
    {
        return Convert.ToString(StatusHolder.Status);
    }
}

Dann ist es vollkommen egal, ob der Status von Basisklasse osder sonst irgendwoher kommt. Eine feste Kopplung gibt es nur noch zum Interface.
Und dann kann man sich überlegen, ob IStatusHolder bereits auch ein INotifyPropertyChanged ist, um sich - wie von FZelle vorgeschlagen - über Änderungen benachrichtigen zu lassen.

Gruß, MarsStein
Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca
private Nachricht | Beiträge des Benutzers
ThomasE.
myCSharp.de - Member



Dabei seit:
Beiträge: 453

beantworten | zitieren | melden

Klar, Interface, hätt ich gleich selbst drauf kommen können. Danke!
Zitat
Und dann kann man sich überlegen, ob IStatusHolder bereits auch ein INotifyPropertyChanged ist, um sich - wie von FZelle vorgeschlagen - über Änderungen benachrichtigen zu lassen.

Das mit dem INotifyPropertyChanged wäre mir wieder zu spezifisch, da ist das mit einem eigenen Interface meiner Meinung nach günstiger... Außer das eigene Interface implemetiert INotifyPropertyChanged aber das würde zu weit führen, ohne einem Konzept wäre das nur ein durcheinander...
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von ThomasE. am .
Ich habe den Titel mal angepasst, so dass Suchende auch etwas damit anfangen können. EDIT: Ich sollte beim Wort "Shift" im Titel das "f" nicht vergessen...
private Nachricht | Beiträge des Benutzers