PictureBoxen zur Laufzeit erstellen



  • for (int i = 0; i == myfileinfos.Count; i++) 
                { 
    
                    flowLayoutPanel1.Controls.Add(new PictureBox()); //Picturebox erstellen 
    
                }
    

    da werden sie ja erstellt (einfach ohne Namen jeweils das kannte ich bisher noch nicht) und

    foreach(Control c in flowLayoutPanel1.Controls)
    

    da sind sie dann jeweils zugreifbar (zuerstdachte ich an etwas wie PictureBox pb+.ToString() = new... aber das geht ja nicht einen Variablennamen als Namen anzugeben..dann kam ich auf diese Idee.
    Jedenfalls, muss ich sie in der zweiten Schleife (foreach) [i]nochmals
    mit Add hinzufügen?



  • Was ist denn eigentlich so schwer daran mal in den Initialize Quellcode zu schauen ?

    for(int i = 0; i < 10;i++)
                {
                    PictureBox box = new PictureBox();
                    box.Image = Bitmap.FromFile(@"c:\bg\0001.jpg");
                    flowLayoutPanel1.Controls.Add(box);
                }
    


  • direkt zuweisen bei der erstellung ist besser - sonst durchlaeufst du die schleife 2x und das ist quatsch

    unabhaengig davon ist die foreach dein problem
    foreach gibt nicht zwingend eine referenz - es kann auch eine kopie sein - du erstellst das bild auf eine kopie welches dann einfach verworfen wird, entweder du nimmst eine for schleife, oder du machst es gleich richtig und weist das bild direkt beim erstellen zu

    MSDN schrieb:

    The foreach statement repeats a group of embedded statements for each element in an array or an object collection. The foreach statement is used to iterate through the collection to get the desired information, but should not be used to change the contents of the collection to avoid unpredictable side effects.



  • Zum einen wird die Controls Collection nicht geändert wenn der Eigenschaft der Picturebox etwas zugewiesen wird und zum anderen kannst Du Kopien von der Referenz so viele Kopien anliegen so viel du willst, die Operation wird am Objekt ausgeführt auf das die Referenz zeigt. Selbst wenn der Enumerator Kopien erzeugt wären es nur Kopien der Referenz.



  • Es läuft nun - mit dem Code (fast) wie ich gehabt habe. Das Problem war ein ganz anderes; und zwar

    for(int i = 0; i < 10;i++)
    

    anstatt

    for(int i = 0; i ==10;i++)
    

    sowie

    FileInfo f=myfileinfos[index].ToString();
    PictureBox.LoadAsync(f.FullName
    

    anstatt

    PictureBox.LoadAsync(myfileinfos[index].ToString()); (oder Image.FromFile)
    

    da der Pfad nicht übergeben wurde.
    Nun aber habe ich ein anderes Problem: DIe Pictureboxen werden in der Mitte des Fensters angeordnet, d.h. wenn man nicht hinunterscrollt sieht man nichts. WIe /was muss ich da dem FlowLayoutPanel zuweisen damit es das nicht tut? FlowDirection=TopDown geht auch nicht, das beginnt zwar oben aber nicht am linken Rand sondern hier wiederum in der Mitte (muss man also nach rechts scrollen).

    Vielen Dank 🙂



  • Ein wenig MSDN ist auch für Dich übrig...

    Geht Dein Panel überhaupt über die gesamte Fläche oder klebt die einfach nur mittendrinn ?



  • Knuddlbaer schrieb:

    ... zum anderen kannst Du Kopien von der Referenz so viele Kopien anliegen so viel du willst, die Operation wird am Objekt ausgeführt auf das die Referenz zeigt. Selbst wenn der Enumerator Kopien erzeugt wären es nur Kopien der Referenz.

    das nahm ich zuerst auch an, nur als ich foreach mal intensiever in mein code eingebaut hatte - hatte es mal nicht funktiert, die zuweisung ging floeten - seit dem vermeide ich ein foreach wenn ich die elemente irgendwie veraendern muss - da es meiner erfahrung nach auch zu blanken kopien kommen kann statt einer kopie einer referenz

    ich schau mal ob ich es noch find, aber denk nicht da ich es gleich als for umgebaut hatte als es nicht funktionierte

    //Dazuedit, grad probiert, nichtmal der compiler laessts durch:

    List<int> numbers = new List<int>();
    numbers.Add(1);
    numbers.Add(2);
    numbers.Add(3);
    numbers.Add(4);
    numbers.Add(5);
    
    foreach (int number in numbers)
        number += 10;
    
    foreach (int number in numbers)
        Console.WriteLine(number);
    

    VS08 schrieb:

    Cannot assign to 'number' because it is a 'foreach iteration Variable'

    mit diesem das selbe:

    struct Number
    {
        public int Value;
    }
    
    static void Main(string[] args)
    {
        List<Number> numbers = new List<Number>();
        numbers.Add(new Number());
        numbers.Add(new Number());
        numbers.Add(new Number());
        numbers.Add(new Number());
        numbers.Add(new Number());
    
        foreach (Number number in numbers)
            number.Value += 10;
    
        foreach (Number number in numbers)
            Console.WriteLine(number.Value);
    

    fuer mich ist das ein inkosistentes verhalten, daher vermeide ich es objekte zu veraendern welche aus einer foreach kommen

    ich hatte wie gesagt schon den fall das ic variablen veraendert hatten, und im laufenden programm dann die zuweisung nicht beachtet wurde, bis ich es als for umgebaut hab



  • int ist ja auch ein struct. Damit geht das natürlich nicht.
    Mit Klassen funktioniert das aber.



  • was heisst "natuerlich" - wo ist die logik dahinter das es mit class geht aber struct nicht ???

    http://msdn.microsoft.com/de-de/library/cc433531(VS.71).aspx

    MSDN schrieb:

    ...muss einen der folgenden Typen darstellen: interface, class oder struct....

    laut MSDN solls auch mit struct gehen



  • Weil structs Wertetypen sind und in der foreach-Schleife einer Variablen dann halt
    ein Wert und keine Referenz zugewiesen wird.



  • genau - darum sagte ich ja

    da es meiner erfahrung nach auch zu blanken kopien kommen kann statt einer kopie einer referenz
    

    ich verlass mich da nicht drauf das ich in foreach werte direkt aendern kann welche auch wirklich zugewiesen werden

    btw. falls sich wer wundert, ich bastel derzeit an mein greasemonkey script rum und deswegen ist er derzeit nicht aktiv



  • Mmh, okay, wobei man das Problem aber nicht nur bei foreach hat.
    Das geht doch eher um Structs und Klassen und das man die zugegeben schlecht unterscheiden kann.



  • stimmt auch wieder - bei funktionsaufrufen ist es das selbe - da werden nur klassen als referenzen uebergeben
    structs nicht /=

    "string" wird auch nicht als referenz uebergeben sondern als kopie, sofern es nicht bestandteil einer klasse ist

    class NumberClass
    {
    	public NumberClass(int number)
    	{
    		Value = number;
    	}
    	public int Value { get; set; }
    }
    
    struct NumberStruct
    {
    	public int Value;
    }
    
    class TextClass
    {
    	public TextClass(string text)
    	{
    		Value = text;
    	}
    	public string Value { get; set; }
    }
    
    //-------------------------------------------------------
    static void Increaser(NumberClass p)
    {
    	p.Value += 10;
    }
    static void Increaser(NumberStruct p)
    {
    	p.Value += 10;
    }
    static void Increaser(int p)
    {
    	p += 10;
    }
    static void Changer(string p)
    {
    	p = "11";
    }
    static void Changer(TextClass p)
    {
    	p.Value = "11";
    }
    //-------------------------------------------------------
    
    static void Main(string[] args)
    {
    	NumberClass numberClass = new NumberClass(1);
    	NumberStruct numberStruct = new NumberStruct();
    	numberStruct.Value = 1;
    	int number = 1;
    	string numberText = "1";
    	TextClass textClass = new TextClass("1");
    	Console.WriteLine("Before numberclass: " + numberClass.Value);
    	Console.WriteLine("Before struct: " + numberStruct.Value);
    	Console.WriteLine("Before int: " + number);
    	Console.WriteLine("Before string: " + numberText);
    	Console.WriteLine("Before textclass: " + textClass.Value);
    
    	Increaser(numberClass);
    	Increaser(numberStruct);
    	Increaser(number);
    	Changer(numberText);
    	Changer(textClass);
    
    	Console.WriteLine("After numberclass: " + numberClass.Value);
    	Console.WriteLine("After struct: " + numberStruct.Value);
    	Console.WriteLine("After int: " + number);
    	Console.WriteLine("After string: " + numberText);
    	Console.WriteLine("After textclass: " + textClass.Value);
    }
    

    Console schrieb:

    Before numberclass: 1
    Before struct: 1
    Before int: 1
    Before string: 1
    Before textclass: 1
    After numberclass: 11
    After struct: 1
    After int: 1
    After string: 1
    After textclass: 11

    und das obwohl string, int usw auch klassen sind
    ich find das verwirrend



  • Den foreach loop kannst Du Dir grob so vorstellen:

    foreach(T x in y) { ...}
    
    for(int counter = 0; counter < y.Length; counter++)
    {
       readonly T tmp = y[counter];
       ....
    }
    

    Bei Enumeratoren schauts ein wenig anders aus. Vllt. hilft das ein wenig als Brücke zu den foreach Konstrukten.

    Ansonsten lies mal die Sätze die drüber stehen.

    Um eine Auflistung durchlaufen zu können, muss [...] Der Auflistungstyp einen der folgenden Typen darstellen: interface, class oder struct [...]

    "string" wird auch nicht als referenz uebergeben sondern als kopie, sofern es nicht bestandteil einer klasse ist

    Wie kommst Du nun drauf ?

    ublic sealed class String
    

    spricht doch sehr dafür das auch ein String als Referenz übergeben wird.



  • Knuddlbaer schrieb:

    "string" wird auch nicht als referenz uebergeben sondern als kopie, sofern es nicht bestandteil einer klasse ist

    Wie kommst Du nun drauf ?

    ublic sealed class String
    

    spricht doch sehr dafür das auch ein String als Referenz übergeben wird.

    weil ich es getestet hab, schau mal den code oben an, und das ergebnis, ich kuerz es mal der uebersicht zuliebe zusammen:

    class TextClass
    {
        public TextClass(string text)
        {
            Value = text;
        }
        public string Value { get; set; }
    }
    
    //-------------------------------------------------------
    static void Changer(string p)
    {
        p = "11";
    }
    static void Changer(TextClass p)
    {
        p.Value = "11";
    }
    //-------------------------------------------------------
    
    static void Main(string[] args)
    {
        string numberText = "1";
        TextClass textClass = new TextClass("1");
        Console.WriteLine("Before string: " + numberText);
        Console.WriteLine("Before textclass: " + textClass.Value);
    
        Changer(numberText);
        Changer(textClass);
    
        Console.WriteLine("After string: " + numberText);
        Console.WriteLine("After textclass: " + textClass.Value);
    }
    

    Console schrieb:

    Before string: 1
    Before textclass: 1
    After string: 1
    After textclass: 11

    wie man sieht ist der string nur veraendert wurden wenn er in einer klasse gekapselt ist
    und wenn man sich das gesamte beispiel in mein vorherigen posting an schaut, sieht man das es nur als referenz uebergeben wird wenn es eine eigene klasse ist
    int, long, string usw werden als kopie uebergeben - obwohl es auch nur klassen sind /=



  • Tu Dir doch einfach mal selbst den gefallen und schau Dir die String Klasse mal in der Dokumentation an. Man kann mit etwas Intuition schon gut raten und eine Richtung für die Dokumentation haben um weitere Informationen zu suchen.

    Die von Dir genannten Beispiele und diese Diskussion wären für mich der Anlass noch mal in die Dokumentation zu schauen. Aber selbst ohne dem Wissen, das System.String nicht änderbar ist und jede Änderung eine neue Instanz von System.String erzeugt ist die Erkenntnis die Du aus Deinem Beispielcode zeigst noch ausbaufähig.

    namespace ConsoleApplication2
    {
    
        class Beispielklasse
        {
            public override string ToString()
            {
                return name;
            }
    
            string name;
            /// <summary>
            /// Initializes a new instance of the Beispielklasse class.
            /// </summary>
            /// <param name="name"></param>
            public Beispielklasse(string name)
            {
                this.name = name;
            }
    
            public static void Changer(Beispielklasse var)
            {
                var = new Beispielklasse("Changer(Beispielklasse var)");
            }
            public static void Changer(ref Beispielklasse var) 
            {
                var = new Beispielklasse("Changer(ref Beispielklasse var)");
            }
    
        }
        class Program
        {
            static void Main(string[] args)
            {
                Beispielklasse bsp = new Beispielklasse("Main");
                Console.WriteLine(bsp);
                Beispielklasse.Changer(bsp);
                Console.WriteLine(bsp);
                Beispielklasse.Changer(ref bsp);
                Console.WriteLine(bsp);
            }
        }
    }
    
    Beispielklasse.Changer(bsp);
    

    Hier wird eine Kopie der Referenz erzeugt. Die Kopie der Referenz wird auf einen neuen Wert gesetzt.

    class Program
        {
            public static void Changer(string var)
            {
                var = "changer(string)";
            }
            public static void Changer(ref string var)
            {
                var = "changer(ref string)";
            }
    
            static void Main(string[] args)
            {
                string test = "Main";
                Console.WriteLine(test);
                Program.Changer(test);
                Console.WriteLine(test);
                Program.Changer(ref test);
                Console.WriteLine(test);
            }
        }
    

    Ist das gleiche - nur in grün (bzw. string);



  • int und long sind structs, also ist die nicht-Änderung okay.
    Bei string s ist das wie in Java. s="bla" erzeugt ein neues Objekt, da man einen string nach dem Erstellen nicht mehr ändern kann (StringBuilder hingegen würde wie erwartet ändern).



  • void Foo(object x) //x ist eine _Kopie der Referenz_ auf den übergebenen Parameter 
    {
       x = new object();
    }
    
    ...
    object myObj, otherObj;
    myObj = otherObj = new object();
    
    Foo(myObj);
    
    System.Diagnostics.Debug.Assert(myObj == otherObj);
    

    Ansonsten kann man schreiben

    void Foo(ref object x)
    //oder
    void Foo(out object x)
    


  • Knuddlbaer schrieb:

    ...
    Hier wird eine Kopie der Referenz erzeugt. Die Kopie der Referenz wird auf einen neuen Wert gesetzt.
    ...

    👍
    Ich war zu langsam. Aber wer hätte gedacht, dass vor acht Uhr noch andere Leute posten.



  • im fall von string wird die referenz kopiert - der kopie dann ein neuen wert zugewiesen
    dieser verfaellt nach ende der sichtbarkeit
    soweit kann ich das unterschreiben - die tests haben das auch ergeben
    nur

    _wonach_ kann cih gehen ? Int32, String sind alles genauso klassen wie eigene
    warum werden diese kopiert uebergeben aber eigene klassen nicht??
    das ist gerade das problem - beim entwickeln weiss man nicht unbedingt wie der wert an kommt - und da muss man manchmal echt aufpassen
    ich hab bisher kein gemeinsamen tonus erkennen koennen

    // nicht geaendert

    static void Change(string value)
    {
    	value = "neu";
    	Console.WriteLine(value);
    }
    
    static void Main(string[] args)
    {
    	string value = "begin";
    	Console.WriteLine(value);
    	Change(value);
    	Console.WriteLine(value);
    }
    

    // geaendert

    class Value
    {
    	public string Text;
    	public Value(string value)
    	{
    		Text = value;
    	}
    }
    static void Change(Value value)
    {
    	value.Text = "neu";
    	Console.WriteLine(value.Text);
    }
    static void Main(string[] args)
    {
    	Value value = new Value("begin");
    	Console.WriteLine(value.Text);
    	Change(value);
    	Console.WriteLine(value.Text);
    }
    

    ersteres wird also kopierte referenz uebergeben welches verfaellt - zweiteres wird als "echte" referenz uebergeben
    woran kann man den unterschied festhalten ? sind beides klassen!

    @Any Mod, koennte man diese diskusion in einen eigenen thread splitten?


Anmelden zum Antworten