none
WPF: Variable vom aufrufenden Fenster holen

    Frage

  • Hallo Forum,

    Ich rufe aus einem Fenster ein anderes Fenster auf und möchte dort auf eine Variable des aufrufenden Fenster zugreifen. Im dortigen Behind-Code schaffe ich es nicht auf die Variable zuzugreifen,

    lg heinz

     '<Window x:Class="BilderPuzzleMain.MainWindow"       
    Private Sub starteSpiel()
                Dim SpielWindow As New Window()
                SpielWindow.Owner = Me
                SpielWindow.Show()
            End Sub
    '
    '<Window x:Class="BilderPuzzleSpiel.SpielWindow"
            Private Sub SpielLoaded(ByVal sender As Object, ByVal e As EventArgs)
                m_Bild = BilderPuzzleMain.MainWindow.m_BildAktuell 'HIER kennt er die Quelle nicht
            End Sub
    

    Sonntag, 17. März 2013 17:12

Antworten

  • Hallo,

    ich würde an deiner Stelle im Konstruktor des 2. Fensters nach einer Instanz des 1. fensters oder der Variable verlangen. Ein Beipeil mit übergabe des Fensters:

    Class Windows1
    	Inherits Windows
    	Private Sub DoSome()
    		Dim wnd As New Window2(Me)
    		wnd.Owner = Me
    		wnd.Show()
    	End Sub
    	Public ABC As String = ""
    End Class
    
    Class Windows2
    	Inherits Windows
    	Private wnd As Window1 = Nothing
    	Private Sub New(wnd As Window1)
    		Me.wnd = wnd
    	End Sub
    	Private Sub DoSome()
    		MessageBox.Show(wnd.ABC)
    	End Sub
    End Class
    Wenn du nur die Variable übergibst, dann brauchst du Sie nicht public machen.


    <Code:13/> - Koopakiller [kuːpakɪllɐ]
    Webseite | Code Beispiele | Facebook | Snippets


    Sonntag, 17. März 2013 18:15
  • Hi,
    um Daten in einem Programm zwischen verschiedenen Objekten auszutauschen, kann man den Verweis auf den Container mit den Variablen übergeben. So kann man beispielsweise eine Variable in einer Form einer andern Form im Konstruktor übergeben, indem man den Verweis auf sich selbst, d.h. auf die aktuelle Form, mitreicht. Diese Arbeitsweise hat jedoch den Nachteil, dass sich alle Klassen kennen müssen und bei komplexeren Projekten der Überblick verloren gehen kann, insbesondere bei Tests.

    Eine alternative Lösung ist die Ablage der Variablenwerte in einem separaten Datenobjekt, welches alle anderen Objekte (Klassen) kennen. Da erübrigt sich die Notwendigkeit, dass unterschiedliche Klassen sich gegenseitig kennen müssen. Für die Ablage der Variablenwerte ist eine Klasse zu nutzen, die nur einmalig instanziiert wird, d.h. es gibt im Projekt nur ein Objekt vom Typ dieser Klasse. Das kann man erreichen, indem man einen statischen Verweis auf dieses Datenobjekt hat. Statische Zugriffe lassen sich in VB am einfachsten in Moduln verwaltet.

    Nachfolgend ist ein Beispiel zur Demonstration dargestellt:

    Class1 - Klasse für das Datenobjekt:

    
    

    Imports System.ComponentModel


    ''' <summary> ''' Klasse zur Erzeugung von Datenobjekten, ''' in denen Werte gespeichert und wieder bereitgestellt werden können ''' </summary> ''' <remarks></remarks> Public Class Class1 Implements INotifyPropertyChanged ' Interface für das Melden von Änderungen ''' <summary> ''' interne Variable zum Puffern eines Wertes ''' </summary> ''' <remarks></remarks> Private _daten As String ''' <summary> ''' In der Assembly sichtbare Eigenschaft für das Puffern eines Wertes ''' </summary> ''' <value></value> ''' <returns></returns> ''' <remarks></remarks> Friend Property Daten As String Get Return Me._daten ' gepufferten Wert bereitstellen End Get Set(value As String) ' Abfrage, ob veränderter Wert zu puffern ist If Me._daten <> value Then Me._daten = value ' Melden, dass in der Eigenschaft gepufferter Wert verändert wurde OnPropertyChanged("Daten") End If End Set End Property ''' <summary> ''' Ereignis für das Melden von Veränderungen des gepufferten Wertes ''' </summary> ''' <param name="sender"></param> ''' <param name="e"></param> ''' <remarks></remarks> Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged ''' <summary> ''' interne Methode zum Auslösen des Meldevorganges ''' </summary> ''' <param name="propName"></param> ''' <remarks></remarks> Private Sub OnPropertyChanged(propName As String) RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propName)) End Sub End Class


    Modul1 - statische Klasse

    ''' <summary>
    ''' statische Klasse, auf deren Innereien ohne Objektinstanziierung zugegriffen werden kann
    ''' </summary>
    ''' <remarks></remarks>
    Module Module1
      ''' <summary>
      ''' interner Puffer für die Ablage des Verweises auf eine Instanz des Datenobjektes
      ''' </summary>
      ''' <remarks></remarks>
      Private _datenobjekt As Class1 = Nothing
      ''' <summary>
      ''' statische Eigenschaft, die den Verweis auf das Datenobjekt bereitstellt
      ''' </summary>
      ''' <value></value>
      ''' <returns></returns>
      ''' <remarks></remarks>
      Friend ReadOnly Property Datenobjekt As Class1
        Get
          ' Prüfen, obe es bereits ein Datenobjekt gibt
          If _datenobjekt Is Nothing Then _datenobjekt = New Class1
          ' Bereitstellung des Verweises auf das Datenobjekt
          Return _datenobjekt
        End Get
      End Property
    End Module

    Form1:

    ''' <summary>

    ''' 1. Form ''' </summary> ''' <remarks></remarks> Public Class Form1 ''' <summary> ''' TextBox in der Form ''' </summary> ''' <remarks></remarks> Private tb As New TextBox With {.Dock = DockStyle.Top} ''' <summary> ''' Befehlsschaltfläche in der Form ''' </summary> ''' <remarks></remarks> Private WithEvents btn As New Button With {.Dock = DockStyle.Top, .Text = "Speichern"} ''' <summary> ''' Beim Laden der Form-Instanz Anfangszustände setzen ''' </summary> ''' <param name="sender"></param> ''' <param name="e"></param> ''' <remarks></remarks> Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load ' Alle Steuerelemente platzieren (anstelle der Arbeit mit dem Designer) Me.Controls.AddRange(New Control() {btn, tb}) ' weitere Form zur Anzeige bringen Call (New Form2).Show() End Sub ''' <summary> ''' Klick-Ereignis der Befehlsschaltfläche behandeln ''' </summary> ''' <param name="sender"></param> ''' <param name="e"></param> ''' <remarks></remarks> Private Sub btn_Click(sender As Object, e As EventArgs) Handles btn.Click ' Inhalt der text-Eigenschaft der TextBox im Datenobjekt ablegen Module1.Datenobjekt.Daten = tb.Text End Sub End Class



    Form 2:

    Imports System.ComponentModel ''' <summary> ''' Weitere Form, die Daten von "außen" anzeigt ''' </summary> ''' <remarks></remarks> Public Class Form2 ''' <summary> ''' TextBox in der Form ''' </summary> ''' <remarks></remarks> Private tb As New TextBox With {.Dock = DockStyle.Top} ''' <summary> ''' Beim Laden der Form-Instanz Anfangszustände setzen ''' </summary> ''' <param name="sender"></param> ''' <param name="e"></param> ''' <remarks></remarks> Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load ' Alle Steuerelemente platzieren (anstelle der Arbeit mit dem Designer) Me.Controls.AddRange(New Control() {tb}) ' Ereignis der Datenänderungen im Datenobjekt fangen und verarbeiten AddHandler Module1.Datenobjekt.PropertyChanged, Sub(da As Object, pc As PropertyChangedEventArgs) ' Methode, die beim Eintreten des Ereignisses abgearbeitet wird ' Abfrage, ob sich der Inhalt der Eigenschaft "Daten" geändert hat If pc.PropertyName = "Daten" Then ' geänderten Wert in die TextBox schreiben tb.Text = Module1.Datenobjekt.Daten End If End Sub End Sub End Class


    --
    Viele Gruesse
    Peter




    Montag, 18. März 2013 08:02

Alle Antworten

  • Hallo,

    ich würde an deiner Stelle im Konstruktor des 2. Fensters nach einer Instanz des 1. fensters oder der Variable verlangen. Ein Beipeil mit übergabe des Fensters:

    Class Windows1
    	Inherits Windows
    	Private Sub DoSome()
    		Dim wnd As New Window2(Me)
    		wnd.Owner = Me
    		wnd.Show()
    	End Sub
    	Public ABC As String = ""
    End Class
    
    Class Windows2
    	Inherits Windows
    	Private wnd As Window1 = Nothing
    	Private Sub New(wnd As Window1)
    		Me.wnd = wnd
    	End Sub
    	Private Sub DoSome()
    		MessageBox.Show(wnd.ABC)
    	End Sub
    End Class
    Wenn du nur die Variable übergibst, dann brauchst du Sie nicht public machen.


    <Code:13/> - Koopakiller [kuːpakɪllɐ]
    Webseite | Code Beispiele | Facebook | Snippets


    Sonntag, 17. März 2013 18:15
  • Hi,
    ich würde die zu übergebenden Variableninhalte in Objekte auslagern, auf die über statische Variablen oder Eigenschaften zugegriffen werden kann. Damit entfällt die Notwendigkeit der gegenseitigen Kenntnis der Window-Klassen.
     
    --
    Peter Fleischer
    Sonntag, 17. März 2013 18:20
  • Hallo, Peter,

    hört sich gut an, aber wie mache ich das? Bzw. wo kann ich das nachlesen?,

    lg heinz

    Sonntag, 17. März 2013 19:29
  • Hallo Koopakiller,

    danke, das funktioniert, obwohl mir nicht ganz klar warum,

    lg heinz

    Sonntag, 17. März 2013 19:31
  • Das funktioniert weil die Instanz der Form nur ein Verweis auf einen bereich im Arbeitsspeicher ist. Wenn du nun die Instanz übergibst, dann übergibst du nur den Verweis auf den Arbeitsspeicher. Das heißt, das Window2 direkt auf Window1 zugreifen kann.

    Zu den Statischen Eigenschaften: http://openbook.galileocomputing.de/einstieg_vb_2008/visual_basic_kap_05_006.htm
    Wichtig ist, das der Wert Anwendungsweit gleich ist udn man somit Daten austausche  kann.


    <Code:13/> - Koopakiller [kuːpakɪllɐ]
    Webseite | Code Beispiele | Facebook | Snippets


    Sonntag, 17. März 2013 20:29
  • Hi,
    um Daten in einem Programm zwischen verschiedenen Objekten auszutauschen, kann man den Verweis auf den Container mit den Variablen übergeben. So kann man beispielsweise eine Variable in einer Form einer andern Form im Konstruktor übergeben, indem man den Verweis auf sich selbst, d.h. auf die aktuelle Form, mitreicht. Diese Arbeitsweise hat jedoch den Nachteil, dass sich alle Klassen kennen müssen und bei komplexeren Projekten der Überblick verloren gehen kann, insbesondere bei Tests.

    Eine alternative Lösung ist die Ablage der Variablenwerte in einem separaten Datenobjekt, welches alle anderen Objekte (Klassen) kennen. Da erübrigt sich die Notwendigkeit, dass unterschiedliche Klassen sich gegenseitig kennen müssen. Für die Ablage der Variablenwerte ist eine Klasse zu nutzen, die nur einmalig instanziiert wird, d.h. es gibt im Projekt nur ein Objekt vom Typ dieser Klasse. Das kann man erreichen, indem man einen statischen Verweis auf dieses Datenobjekt hat. Statische Zugriffe lassen sich in VB am einfachsten in Moduln verwaltet.

    Nachfolgend ist ein Beispiel zur Demonstration dargestellt:

    Class1 - Klasse für das Datenobjekt:

    
    

    Imports System.ComponentModel


    ''' <summary> ''' Klasse zur Erzeugung von Datenobjekten, ''' in denen Werte gespeichert und wieder bereitgestellt werden können ''' </summary> ''' <remarks></remarks> Public Class Class1 Implements INotifyPropertyChanged ' Interface für das Melden von Änderungen ''' <summary> ''' interne Variable zum Puffern eines Wertes ''' </summary> ''' <remarks></remarks> Private _daten As String ''' <summary> ''' In der Assembly sichtbare Eigenschaft für das Puffern eines Wertes ''' </summary> ''' <value></value> ''' <returns></returns> ''' <remarks></remarks> Friend Property Daten As String Get Return Me._daten ' gepufferten Wert bereitstellen End Get Set(value As String) ' Abfrage, ob veränderter Wert zu puffern ist If Me._daten <> value Then Me._daten = value ' Melden, dass in der Eigenschaft gepufferter Wert verändert wurde OnPropertyChanged("Daten") End If End Set End Property ''' <summary> ''' Ereignis für das Melden von Veränderungen des gepufferten Wertes ''' </summary> ''' <param name="sender"></param> ''' <param name="e"></param> ''' <remarks></remarks> Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged ''' <summary> ''' interne Methode zum Auslösen des Meldevorganges ''' </summary> ''' <param name="propName"></param> ''' <remarks></remarks> Private Sub OnPropertyChanged(propName As String) RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propName)) End Sub End Class


    Modul1 - statische Klasse

    ''' <summary>
    ''' statische Klasse, auf deren Innereien ohne Objektinstanziierung zugegriffen werden kann
    ''' </summary>
    ''' <remarks></remarks>
    Module Module1
      ''' <summary>
      ''' interner Puffer für die Ablage des Verweises auf eine Instanz des Datenobjektes
      ''' </summary>
      ''' <remarks></remarks>
      Private _datenobjekt As Class1 = Nothing
      ''' <summary>
      ''' statische Eigenschaft, die den Verweis auf das Datenobjekt bereitstellt
      ''' </summary>
      ''' <value></value>
      ''' <returns></returns>
      ''' <remarks></remarks>
      Friend ReadOnly Property Datenobjekt As Class1
        Get
          ' Prüfen, obe es bereits ein Datenobjekt gibt
          If _datenobjekt Is Nothing Then _datenobjekt = New Class1
          ' Bereitstellung des Verweises auf das Datenobjekt
          Return _datenobjekt
        End Get
      End Property
    End Module

    Form1:

    ''' <summary>

    ''' 1. Form ''' </summary> ''' <remarks></remarks> Public Class Form1 ''' <summary> ''' TextBox in der Form ''' </summary> ''' <remarks></remarks> Private tb As New TextBox With {.Dock = DockStyle.Top} ''' <summary> ''' Befehlsschaltfläche in der Form ''' </summary> ''' <remarks></remarks> Private WithEvents btn As New Button With {.Dock = DockStyle.Top, .Text = "Speichern"} ''' <summary> ''' Beim Laden der Form-Instanz Anfangszustände setzen ''' </summary> ''' <param name="sender"></param> ''' <param name="e"></param> ''' <remarks></remarks> Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load ' Alle Steuerelemente platzieren (anstelle der Arbeit mit dem Designer) Me.Controls.AddRange(New Control() {btn, tb}) ' weitere Form zur Anzeige bringen Call (New Form2).Show() End Sub ''' <summary> ''' Klick-Ereignis der Befehlsschaltfläche behandeln ''' </summary> ''' <param name="sender"></param> ''' <param name="e"></param> ''' <remarks></remarks> Private Sub btn_Click(sender As Object, e As EventArgs) Handles btn.Click ' Inhalt der text-Eigenschaft der TextBox im Datenobjekt ablegen Module1.Datenobjekt.Daten = tb.Text End Sub End Class



    Form 2:

    Imports System.ComponentModel ''' <summary> ''' Weitere Form, die Daten von "außen" anzeigt ''' </summary> ''' <remarks></remarks> Public Class Form2 ''' <summary> ''' TextBox in der Form ''' </summary> ''' <remarks></remarks> Private tb As New TextBox With {.Dock = DockStyle.Top} ''' <summary> ''' Beim Laden der Form-Instanz Anfangszustände setzen ''' </summary> ''' <param name="sender"></param> ''' <param name="e"></param> ''' <remarks></remarks> Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load ' Alle Steuerelemente platzieren (anstelle der Arbeit mit dem Designer) Me.Controls.AddRange(New Control() {tb}) ' Ereignis der Datenänderungen im Datenobjekt fangen und verarbeiten AddHandler Module1.Datenobjekt.PropertyChanged, Sub(da As Object, pc As PropertyChangedEventArgs) ' Methode, die beim Eintreten des Ereignisses abgearbeitet wird ' Abfrage, ob sich der Inhalt der Eigenschaft "Daten" geändert hat If pc.PropertyName = "Daten" Then ' geänderten Wert in die TextBox schreiben tb.Text = Module1.Datenobjekt.Daten End If End Sub End Sub End Class


    --
    Viele Gruesse
    Peter




    Montag, 18. März 2013 08:02
  • Hallo Peter,

    das Beispiel ist sehr gut,

    lg heinz

    Montag, 18. März 2013 11:33
  • Hi,
    ich hatte da gleich noch NotifyPropertyChanged eingebaut, da diese Frage bestimmt als nächste Frage gekommen wäre.
     
    --
    Peter Fleischer
    Montag, 18. März 2013 13:22
  • Hallo Peter,

    ja die Methode ist ausgesprochen hilfreich,

    lg heinz

    Mittwoch, 20. März 2013 09:50