[c#] odwołanie się do dynamicznych kontrolek

0

Znalazłem taki kod:


           Control[] ctrl = new Control[2];
            for (int i = 0; i < 2; i++)
            {
                GroupBox gb = new GroupBox();
                gb.Size = new Size(200, 50);
                gb.Location = new Point(5, i * 90 + 15);
                gb.Text = "Slot" + i.ToString();
                gb.AutoSize = true;
                gb.Name = "gb" + i.ToString();
            
                for (int j = 0; j < 2; j++)
                {
                    TextBox tb = new TextBox();
                    tb.Size = new Size(130, 20);
                    tb.Location = new Point(10 + (j * 140), 40);
                    tb.Name = "tb" + i.ToString();
                    gb.Controls.Add(tb);

                    Label l = new Label();
                    l.Text = "ttttttt";
                    l.Size = new Size(130, 30);
                    l.Location = new Point(10 + (j * 140), 15);
                    l.Name = "l" + i.ToString();
                    gb.Controls.Add(l);

                    ctrl[i] = gb;
                    
                }
            }
            this.Controls.AddRange(ctrl);

Tworzy on dynamicznie na formie, 2 grouboxy z labelami i textboxami.
Nie potrafię odwołać się do utworzonych obiektów. Np z textboxa odczytać wartość,
sprawdzić jaki klawisz został wciśnięty.

0

Żeby sprawdzić jaki klawisz był wciśnięty musisz podpiąć do każdego z nich delegat obsługujący odpowiednie zdarzenie. najlepiej wyklikaj przykład w GUI designera i potem zrób tak samo na kolejnych obiektach z twojego przykładu.

Jeśli chodzi o sprawdzanie wartości to musisz dokładnie wiedzieć który z elementów tabeli ctrl chcesz czytać.
np ctrl[1].Text lub inna właściwość.

Czasami trzeba zrobić jawną konwersję

((TextBox)ctrl[1]) .Text

0

Z delegatami już sobie poradziłem. A jak sprawdzić indeks groupboxa z tablicy ctrl, w którym naciśnięto klawisz w textboxie?

0

Mam na formie groupboxa, na nim textboxy, przyciski itp
W jaki sposób dynamicznie stworzyć kopię tego textboxa (<- edit:chodzi o gruopboxa) wraz z kontrolkami.
Próbuję tak, ale przenosi mi tylko starego textboxa:

Control[] ctrl = new Control[2]; 
GroupBox gb = new GroupBox();
gb = groupBox1;
ctrl[1] = gb;
ctrl[1].Location = new Point(10, 10);
this.Controls.AddRange(ctrl);
0

textboxa z jakimi kontrolkami, textbox nie jest kontenrem dla innych kontrolek
a w jaki sposob? napisac sobie caly mechanizm kopiujacy
bez obrazy, ale ten kawalek kodu jest kompletnie bez sensu, jesli mialby robic to co napisales

kod w piwerszym poscie tworzyl 2 groupboxy w kazdym 2 textboxy i 2 labele
wiec czy chcialbyc skopiowac czy przeniesc jakiegos textboxa i label w inna lokalizacje, czy caly groupbox
co chcialbys skopiowac? text czy takze wszystkie wlasciwosci odpowiedzialne za wyglad kontrolki

0

Strzelam, że autorowi dużo pomogłoby, gdyby umieścił takiego GroupBoxa w jakiejś swojej UserControl, wystawił z niej jakieś property oraz zdarzenia i operował na niej.

0

massther, abstrahując od kodu z pierwszego posta, pytałem o możliwość
dynamicznego utworzenia groupboxa z całą zawartością, bazując na groupboxie utworzonym
w czasie projektowania aplikacji.

0

To ja chyba o czymś takim właśnie napisałem.
Czemu moje rozwiązanie Ci nie pasuje?

0

Takie rozwiązanie mi pasuje, ale mam pewien problem.
Znalazłem na forum przykład użycia usercontrola. Nie działa u mnie
zdarzenie OnAcceptButtonClick. Klikam w buttona ale zdarzenie nie jest wywoływane.
Na formie nie mam dostępu do zdarzenia OnAcceptButtonClick z usercontrola.
Utworzyłem tablicę na dwa usercontrole:

TextBoxAndButtonsControl[] aaa = newTextBoxAndButtonsControl[2];
aaa[0] = new TextBoxAndButtonsControl();
aaa[1] = new TextBoxAndButtonsControl();

A to przykład który znalazłem:

somekind napisał(a)

Załóżmy, że na kontrolce jest txtValue i btnAccept:

using System;
using System.Windows.Forms;

namespace UserControlEventTest
{
    public partial class TextBoxAndButtonsControl : UserControl
    {
        public event EventHandler OnAcceptButtonClick;

        public string UserText
        {
            get { return this.txtValue.Text; }
        }

        public TextBoxAndButtonsControl()
        {
            InitializeComponent();
        }

        private void btnAccept_Click(object sender, EventArgs e)
        {
            if (this.OnAcceptButtonClick != null)
                OnAcceptButtonClick(this, EventArgs.Empty);  <<<<<<<<<<<<< tutaj ustawiam breakpoint!!!!!!!!!!
        }

       
    }
}

A na formatce jest taka kontrolka i label1:

using System;
using System.Windows.Forms;

namespace UserControlEventTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void textBoxAndButtonsControl1_OnAcceptButtonClick(object sender, EventArgs e)
        {
            this.label1.Text = this.aaa[0].UserText;   
        }
    }
}

0

A metoda textBoxAndButtonsControl1_OnAcceptButtonClick jest podpięta do aaa[0].OnAcceptButtonClick?

0

Chyba nie dam z tym rady. Zamiast wędki, poprosiłbym rybę.
Kiedy klikam w przycisk z usercontrola i ustawiam sobie breakpoint na
OnAcceptButtonClick(this, EventArgs.Empty); (zaznaczam miejsce na poprzednim poście)
warunek nie jest spełniony i nie zachodzi zdarzenie. NIe mogę dojść dlaczego.
Jestem bardzo początkujący.

0
shifttab napisał(a)

Kiedy klikam w przycisk z usercontrola i ustawiam sobie breakpoint na
OnAcceptButtonClick(this, EventArgs.Empty); (zaznaczam miejsce na poprzednim poście)
warunek nie jest spełniony i nie zachodzi zdarzenie.

to znaczy ze nic nie jest podpiete do tego zdarzenia

0

Zmodyfikuj ten swój kod tak:

using System;
using System.Windows.Forms;

namespace UserControlEventTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            this.aaa[0].OnAcceptButtonClick += this.textBoxAndButtonsControl1_OnAcceptButtonClick;
        }

        private void textBoxAndButtonsControl1_OnAcceptButtonClick(object sender, EventArgs e)
        {
            this.label1.Text = this.aaa[0].UserText;   
        }
    }
}
0

Dzięki, somekind, teraz wszystko działa jak powinno.
Jeszcze jedno pytanie odnośnie słowa this.
Czy odwołując się do kontrolek znajdujących się na formie
można to słowo pominąć czy nie?

0

this to referencja do obiektu w kontekscie ktorego wykonywana jest operacja
czyli odpowiedz na twoje pytanie brzmi tak, mozesz pominac, jesli do tych kontrolek odwolujesz sie z metodach ktore sa w klasie formularza

0

Użycie this po prostu zwiększa czytelność kodu.

0

Tworze dynamicznie dwa usercontrole:

aaa[0] = new TextBoxAndButtonsControl();
aaa[1] = new TextBoxAndButtonsControl();

Zdarzenie OnAcceptButtonClick dział już jak powino.
Do pobieranie danych z textboxow na usercontrol utworzylem własciwosci:
public string user_txt_1{ get { return this.txt_1.Text; } set { this.txt_1.Text = value; } }
itd...

W jaki sposób uzyskać indeks obiektu aaa, w którym został naciśnięty przycisk?
Kombinuję i nic nie wychodzi.

0

sender w zdarzeniu to twoj text box, teraz musisz forem przeleciec po tablicy aaa i ustalic obiekt spod ktorego indexu == sender (lub uzyc do tego Linq)

0

Z formy nie potrafię ustalić jaki to indeks, bo nie wiem jak wywołać
aaa[0].textbox ??? nie mam dostępu do żadnych kontrolek w usercontrol
z poziomu formy. Poproszę o przykładowy kod.

A gdyby dodać do nazwy obiektu indeks:
aaa[0].name=aaa[0].name + ind.tostring()
Jak pobrać nazwę usercontrol na którym wciśnięto przycisk.
Jak sprawdzić czy przycisk należy do usercontrol.
Parent zwraca mi nazwę formy.

0

sorry, w twoim przypadku sender w zdarzeniu to bedzie twoj user control TextBoxAndButtonsControl, a tabela aaa to lista wlasnie tych elementow, wiec wszystko ok, forem znajdz index sendera w tablicy aaa

a swoja droga, czemu sam nie zauwazyles czym jest sender? ty wywolujesz zdarzenie, wiec wiesz co podajesz jako sender
uzywaj debugera i podgladaj co jest w jakis obiektach
i nie bierz wszystkiego bezkrytycznie co piszemy, pomysl czy piszemy prawde, czesto nikt kto ci odpowiada nie klepie zaraz kodu, tylko odpisuje na szybko z glowy, pomylki sie zdarzja

0
massther napisał(a)

forem znajdz index sendera w tablicy aaa

możesz napisać jak? jaką właściwość, metodę użyć?

0

oO
wracamy do pracy od podstaw

masz klase TextBoxAndButtonsControl
masz w klasie formy tablice/liste obiektow tej klasy
w swojej kontrolce wyrzucasz event OnAcceptButtonClick(this, EventArgs.Empty);
wiec senderem jest instancja klasy TextBoxAndButtonsControl

wiesz jak sie iteruje tablice/liste za pomoca petli for?

w obsludze zdarzenia wystarczy zrzutowac sender'a na TextBoxAndButtonsControl i znalezc ktory to obiekt w tablicy
w for uzyles jakiegos iteratora, ktory teraz (kiedy znalazles ktory to sender w tablicy) jest indexem w tablicy

0
massther napisał(a)

masz klase TextBoxAndButtonsControl
masz w klasie formy tablice/liste obiektow tej klasy
w swojej kontrolce wyrzucasz event OnAcceptButtonClick(this, EventArgs.Empty);
wiec senderem jest instancja klasy TextBoxAndButtonsControl

Sender wskazuje na przycisk, z którego został wywołany, więc
rzutowanie (sender as TextBoxAndButtonsControl) daje błąd.

Poradziłem sobie inaczej. Po naciśnięciu przycisku odpalają się dwa zdarzenia:

            if (this.OnButtonClick != null)
            {
                OnButtonClick(this, EventArgs.Empty);
                OnButtonClick(sender, EventArgs.Empty);
            }

Teraz mam dostęp (poprzez this) do nazwy Usercontrola, w którym ostatni znak to mój indeks.
I mam dostęp na nazwy przycisku (poprzez sender), który jest mi też potrzebny.
Inaczej nie umiem.
Massther, napisz jak wg Ciebie powinno wyglądać rzutowani o którym piszesz?

0
shifttab napisał(a)

Sender wskazuje na przycisk, z którego został wywołany, więc
rzutowanie (sender as TextBoxAndButtonsControl) daje błąd.

Dlaczego kłamiesz?

W kodzie kontrolki jest taki kod:

private void btnAccept_Click(object sender, EventArgs e)
{
    if (this.OnAcceptButtonClick != null)
    {
        OnAcceptButtonClick(this, EventArgs.Empty);
    }
}

Rzucany jest this, więc słuchacz zdarzenia dostaje jako sender obiekt kontrolki, a nie przycisk.

Ale jeśli jest Ci potrzebny i przycisk i kontorolka, to zamiast this podaj sender, a w kodzie metody obsługującej zdarzenie przerzutujesz go na Button, a do kontrolki dobierzesz się przez właściwość Parent.

0

jezeli wyrzucasz zdarzenie tak OnAcceptButtonClick(this, EventArgs.Empty);
to w metodzie odslugujacej to zdarzenie
mojaKontrolka_OnAcceptButtonClick(object sender, EventArgs e)
{}
sender jest tym co wskazywalo this w miejscu gdzie rzucales zdarzenie, czyli ((MojaKontrolka)sender).JakasWlasciwosc

0

Miałem w kodzie zdarzenia OnButtonClick przekazywanego sendera, a nie this,
więc stąd to nieporozumienie. Teraz wszystko działa już jak powinno.

0

Ale... natknąłem się na kolejny problem.

Zanim usercontrol otrzyma nazwę Slot0 - gdzie ostatni znak to mój indeks,
odpalane jest zdarzenie OnTextChanged (wskazujące zmiany w Textboxach na usercontrolu),
które przekazuje sendera. Parent tego sendera nie posiada w tym momencie nazwy Slot0.
Z buttonami nie ma tego problemu.

0

pomijajac kwestie ze poleganie na kawalku nazwy jako na indexkie w tablicy jest troche kontrowersyjne, to pewnie zbyt pozno ustawiasz name i zbyt wczesnie przypinasz sie do zdarzen
za malo kodu zeby cos wiecej sensownego powiedziec (albo nie chce mi sie wyslilac mozgownicy :])

wlasciwie po co interesuje cie index kontrolki w tablicy? jesli to ma czemus sensownegu gdzies pozluzyc (jako jakies id gdzies), to raczej proponuje aby twoja konktrolka miala wlasciwosc public string MyID {get;set;}
mozesz tez rzucac zdarzenia, ktorych metody obslugi sa bardziej skomplikowane niz void Nazwa(object,EventArgs)
mozesz uzyc EventHandler<JakisTypEventArgs> lub zadelkarowac jakis delegat i uzyc go jako schamt/wzorzec funkcji obslugujacej event

przyklad jak wg mnie powinien wygladac twoj kod:

class MyForm : Form
{
  MyCtrl[] myCtrlArray;
  public MyForm()
  {
    InitialComponents();
    myCtrlArray = new MyCtrl[2];

    myCtrlArray[0] = new MyCtrl();
    myCtrlArray[0].Name = "Ctrl1";
    ... oraz inne wlasciwosci
    myCtrlArray[0].AcceptButtonClick += AcceptButtonClickOnMyControl;

    myCtrlArray[1] = new MyCtrl();
    myCtrlArray[1].Name = "Ctrl2";
    ... oraz inne wlasciwosci
    myCtrlArray[1].AcceptButtonClick += AcceptButtonClickOnMyControl;

     // pewnie trzeba jeszcze te kontrolki gdzies osadzic :)
  }
  void AcceptButtonClickOnMyControl(object sender, EventArgs e)
  {
    var myCtrl = sender as MyCtrl;
    if (myCtrl != null)
    {
       MessageBox.Show("Akceptacja na kontrolce: " + myCtrl.Name + ", uzytkownik podal: " + myCtrl.Txt1);
  // jesli juz bardzo potrzebujesz index w swojej tablicy
       int ind = Array.IndexOf(myCtrlArray, myCtrl);
       if (ind > -1){/*znalazl kontrolke w tablicy */}
    }
  }
}
class MyCtrl : UserControl
{
    public event EventHandler AcceptButtonClick;

    // zakladam ze masz m.in. Button btnAccept;
    void tbnAccept_Click(object sender, EventArgs e)
    {
        // cos zrob
       if (AcceptButtonClick != null) AcceptButtonClick(this,EventArgs.Empty);
    }

    public string Txt1 {get{return tb1.Text;} set{tb1.Text=value}}
}
0
massther napisał(a)

wlasciwie po co interesuje cie index kontrolki w tablicy?

Mam user control na którym jest groupbox z buttonami i polami tekstowymi.
Od użytkownika zależy ile takich usercontroli załaduje. Jest więc tablica usercontroli.
Każdy usercontrol obsługuje jeden plik tekstowy, a że idea jest taka, by móc
edytować kilka plików tekstowych równocześnie, więc muszę znać indeks.
Na wszystkich plikach dozwolone są takie same operacje, więc tworzę tablicę obiektów
na podstawie klasy, która mi to wszystko obsługuje.
Dzięki za kod.

0
massther napisał(a)

pomijajac kwestie ze poleganie na kawalku nazwy jako na indexkie w tablicy jest troche kontrowersyjne,
to pewnie zbyt pozno ustawiasz name i zbyt wczesnie przypinasz sie do zdarzen
za malo kodu zeby cos wiecej sensownego powiedziec (albo nie chce mi sie wyslilac mozgownicy :])

Ponieważ sender musi wskazywać na przycisk, nie mogę użyć this. (albo mogę ale nie potrafię)
Przycisk jest na grouboxie, a groupbox na usercontrol.
Czyli do nazwy usercontrol tak się odwołuję i jest ok:
(sender as TextBox).Parent.Parent.Name
wcześniej miałem
(sender as TextBox).Parent.Name
czyli odwoływałem się do nazwy groupbox, która najwidoczniej
zmieniana była później, niż wywoływane zdarzenie w textboxie.

Przesiadłem się z vb i myślenie obiektowe jest mi obce.
Samo myślenie nie jest mi obce :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1