Autor Wątek: Rozpoznawanie nadesłanego Event'a  (Przeczytany 2294 razy)

Offline Adam B

  • Użytkownik

# Lipiec 26, 2009, 21:09:01
Witam,
Mam problem z rozpoznaniem obiektu, który wywołał metodę. Piszę program, w którym mogę dodawać dynamicznie elementy do panelu za pomocą Buttona "DODAJ". Po dodaniu takiego dynamicznego obiektu chciałem przypisać mu funkcję mam jednak 2 problemy:
 1. Jak rozpoznać, który obiekt, ze stworzonych, wywołał daną funkcję.
 2. Drugi polega na tym, że do kilku obiektów przypisuje tą samą funkcję - jednak rozwiązanie pierwszego problemu powinno rozwiązać też drugi.

oto kod:

  void addQuest()
        {
            // TWORZENIE ELEMENTÓW
            Panel Quest = new Panel();
            Label Name = new Label();
            TextBox Question = new TextBox();
            TextBox Answer1 = new TextBox();
            TextBox Answer2 = new TextBox();
            TextBox Answer3 = new TextBox();
            TextBox Answer4 = new TextBox();

            // TWORZENIE NAPISÓW
            Name.Text = "ZADANIE:"+panelZadania.Controls.Count.ToString();
            Question.Text = "Question";
            Answer1.Text = "odp1";
            Answer2.Text = "odp2";
            Answer3.Text = "odp3";
            Answer4.Text = "odp4";

            //KOLOR TŁA
            Question.BackColor = System.Drawing.Color.Silver;
            Answer1.BackColor = System.Drawing.Color.IndianRed;
            Answer2.BackColor = System.Drawing.Color.IndianRed;
            Answer3.BackColor = System.Drawing.Color.IndianRed;
            Answer4.BackColor = System.Drawing.Color.IndianRed;

            // PARAMETRY ELEMENTÓW
            Question.Multiline = true;
            Question.Height = 80;
            Question.Width = 150;
            Answer1.Width = 200;
            Answer2.Width = 200;
            Answer3.Width = 200;
            Answer4.Width = 200;

            //ROZMIESZCZENIE ELEMENTÓW NA PANELU
            Name.Location = new System.Drawing.Point(10, 5);
            Question.Location = new System.Drawing.Point(5, 20);
            Answer1.Location = new System.Drawing.Point(160, 20);
            Answer2.Location = new System.Drawing.Point(160, 40);
            Answer3.Location = new System.Drawing.Point(160, 60);
            Answer4.Location = new System.Drawing.Point(160, 80);

            //USTAWIENIE QUEST NA PANELU panelZadania
            Quest.Dock = DockStyle.Top;

///////////////////////////////////////////////////////////////////////////////////////////////////////
            //AKCJE NA KLIKNIęCIA
            Answer1.Click += new System.EventHandler(this.Answer_Click);
            Answer2.Click += new System.EventHandler(this.Answer_Click);
            Answer3.Click += new System.EventHandler(this.Answer_Click);
            Answer4.Click += new System.EventHandler(this.Answer_Click);
///////////////////////////////////////////////////////////////////////////////////////////////////////

            // DODAWANIE ELEMENTÓW DO PANELU QUEST
            panelZadania.Controls.Add(Quest);
            Quest.Controls.Add(Question);
            Quest.Controls.Add(Answer4);
            Quest.Controls.Add(Answer3);
            Quest.Controls.Add(Answer2);
            Quest.Controls.Add(Answer1);
            Quest.Controls.Add(Name);
        }

A teraz metoda wywoływana przy kliknięciu TextBoxów AnswerX:
        private void Answer_Click(object sender, EventArgs e)
        {
            // ehh więc właśnie :P
        }

Pracuje z Microsoft Visual C# Expres Edition 2008

Pozdrawiam Adam B :)

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Esidar

  • Użytkownik

# Lipiec 26, 2009, 21:25:33
pierwszy:
            //AKCJE NA KLIKNIęCIA
            Answer1.Click += new System.EventHandler(this.Answer_Click1);
            Answer2.Click += new System.EventHandler(this.Answer_Click2);
            Answer3.Click += new System.EventHandler(this.Answer_Click3);
            Answer4.Click += new System.EventHandler(this.Answer_Click4);

drugi:

private void Answer_Click(object sender, EventArgs e)
{
     if( sender == Answer3 )
}
// sender - jak nazwa wskazuje, wynosi....
« Ostatnia zmiana: Lipiec 26, 2009, 21:28:48 wysłana przez Esidar »

Offline Zielony

  • Użytkownik
    • Ghurund Engine

# Lipiec 26, 2009, 21:27:36
Pierwszym parametrem metody wywoływanej na zdarzenie jest nadawca ('sender')

Offline Adam B

  • Użytkownik

# Lipiec 26, 2009, 23:19:38
Niestety tak nie działa, ponieważ nie rozpoznaje Answer1 itp.
The name 'Answer4' does not exist in the current context

Problem polega raczej z odwołaniem się do dynamicznie stworzonego obiektu. Droga powinna się zaczynać chyba od panelZadania - ponieważ jest to element inicjalizowany wraz z uruchomieniem programu. ??

// na msdn nie widziałem jak mogę sprawdzać elementy (i ich własności), które są powiązane z danym panelem. Coś w stylu:
panelZadania->Quest(panel dynamiczny na którym rozmieszczam dalsze "podelementy")->Answer1(element docelowy, którego szukam)
« Ostatnia zmiana: Lipiec 26, 2009, 23:22:57 wysłana przez Adam B »

Offline Fiołek

  • Użytkownik
    • Blog

# Lipiec 26, 2009, 23:44:28
Żeby porównać 'sender' z obiektem utworzonym "dynamicznie" musisz ten obiekt jakoś przechowywać(pole klasy np.). Innym rozwiązaniem jest porównywanie ID/Nazwy obiektu 'sender'.

// na msdn nie widziałem jak mogę sprawdzać elementy (i ich własności), które są powiązane z danym panelem. Coś w stylu:
panelZadania->Quest(panel dynamiczny na którym rozmieszczam dalsze "podelementy")->Answer1(element docelowy, którego szukam)

ControlCollection.Find:
Kod: (csharp) [Zaznacz]
var quest = panelZadania.Controls.Find("Quest", false)[0];
var answer = quest.Controls.Find("Answer", false)[0];
« Ostatnia zmiana: Lipiec 26, 2009, 23:46:06 wysłana przez Fiołek »

Offline Adam B

  • Użytkownik

# Lipiec 27, 2009, 00:23:36
ControlCollection.Find:
Kod: (csharp) [Zaznacz]
var quest = panelZadania.Controls.Find("Quest", false)[0];
var answer = quest.Controls.Find("Answer", false)[0];

Niestety takie rozwiązanie też nie działa problem pojawia się już w momencie:
var quest = panelZadania.Controls.Find("Quest", false)[0];

Błąd polega na tym, że został przekroczony index tablicy:
Cytuj
Index was outside the bounds of the array.

Offline Fiołek

  • Użytkownik
    • Blog

# Lipiec 27, 2009, 00:27:01
A może byś tak zajrzał do dokumentacji? ControlCollection.Find szuka po nazwie(właściwość Name) kontrolki. Jeśli nie znajduje żadnej, to się nie dziw, że masz Index out of range ;) Ustaw odpowiednio właściwość(przy tworzeniu) a wszystko będzie dobrze.

Offline Adam B

  • Użytkownik

# Lipiec 27, 2009, 00:37:51
Okej ale po stworzeniu takiej tablicy w jaki sposób będę mógł sprawdzić, który z indeksów tablicy wybrać, aby odwołać się do konkretnego panelu, a potem na tym panelu do odpowiedniego przycisku ?

// Chyba musi być jakaś prostsza droga dostępu do klikniętego elementu.
« Ostatnia zmiana: Lipiec 27, 2009, 00:59:32 wysłana przez Adam B »

Offline Fiołek

  • Użytkownik
    • Blog

# Lipiec 27, 2009, 12:16:03
Co ty chcesz zrobić? Pokazałem jak dostać się do nazwanego elementu kolekcji kontrolek, Esidar pokazał jak rozpoznać która kontrolka wysyła zdarzenie. Gdzie tu tablice?

// Chyba musi być jakaś prostsza droga dostępu do klikniętego elementu.
Jest - rozwiązanie podał Esidar.

Offline Adam B

  • Użytkownik

# Lipiec 27, 2009, 13:08:35
Załóżmy, że to wygląda tak:


Klikam w answerX na jakimś panelu Quest. Ewentualnie mogę każdy z paneli nazywać inaczej: Quest1, Quest2, Quest3 ale wtedy nie wiem jak odebrać w "EventHandlerze" nazwę Panelu, z którego została wysłana akcja.
Więc to mi nie pomoże, bo tu muszę znać nazwę:
var quest = panelZadania.Controls.Find("Quest", false)[0]; 
// Tu by mogło być Quest1, Quest2 itp.

Generalnie chodzi mi o coś takiego:
Cytuj
Klikam w przycisk Answer1 to zmienia mi się kolor TextBoxa, który jest na Penelu Quest na czerwony
Klikam w przycisk Answer2 to zmienia mi się kolor TextBoxa, który jest na Penelu Quest na zielony itp

// panelZadania.Controls.Find(sender.Parent.Name, false)[0]; :P ale coś takiego nie ma prawa bytu 
« Ostatnia zmiana: Lipiec 27, 2009, 13:11:02 wysłana przez Adam B »

Offline Fiołek

  • Użytkownik
    • Blog

# Lipiec 27, 2009, 13:20:19
Czyli rozwiązanie Esidara jest całkowicie wystarczające.
Kod: (csharp) [Zaznacz]
private void Answer_Click(object sender, EventArgs e)
{
    Control ctrl = sender as Control; //sender to jeden z czterech odpowiedzi.
    Color tbColor = Color.Black;
    if(ctrl.Name == "answer1")
        tbColor = Color.Red;
    //Tutaj sprawdzamy resztę kolorów.
    var tb = ctrl.Parent.Controls //Kontrolki panelu-rodzica
    .OfType<TextBox>() //Wybieramy wszystkie TB
    [0]; //I, z tych wszystkich, wybieramy pierwszy TB.
    //Zmieniamy kolor tego TB.
}

Offline Adam B

  • Użytkownik

# Lipiec 27, 2009, 13:36:02
Czyli rozwiązanie Esidara jest całkowicie wystarczające.
Kod: (csharp) [Zaznacz]
private void Answer_Click(object sender, EventArgs e)
{
    Control ctrl = sender as Control; //sender to jeden z czterech odpowiedzi.
    Color tbColor = Color.Black;
    if(ctrl.Name == "answer1")
        tbColor = Color.Red;
    //Tutaj sprawdzamy resztę kolorów.
    var tb = ctrl.Parent.Controls //Kontrolki panelu-rodzica
    .OfType<TextBox>() //Wybieramy wszystkie TB
    [0]; //I, z tych wszystkich, wybieramy pierwszy TB.
    //Zmieniamy kolor tego TB.
}

Oke oki dzięki - nie znałem tego patentu "Control ctrl = sender as Control;"
Teraz kod wygląda tak:
            Control ctrl = sender as Control; //sender to jeden z czterech odpowiedzi.
            var answer1 = ctrl.Parent.Controls.Find("Answer1", false)[0];
            answer1.BackColor = System.Drawing.Color.Green;

I to w zupełności wystarczy ! :) Dzięki wielkie ++ :P

// WKLEJE CAŁOŚć:

        // ODPOWIEDZI NA KLIKNIęCIA CHECKBOXÓW
        private void zaznaczOdpowiedz_Click(object sender, EventArgs e)
        {
            Control ctrl = sender as Control; //sender to jeden z czterech odpowiedzi.
            String Name = "Answer3";

            if (ctrl.Name == "GoodAnswer1")
                Name = "Answer1";
            if (ctrl.Name == "GoodAnswer2")
                Name = "Answer2";
            if (ctrl.Name == "GoodAnswer3")
                Name = "Answer3";
            if (ctrl.Name == "GoodAnswer4")
                Name = "Answer4";

            var answer1 = ctrl.Parent.Controls.Find(Name, false)[0];
            answer1.BackColor = System.Drawing.Color.Green;
        }
« Ostatnia zmiana: Lipiec 27, 2009, 13:39:37 wysłana przez Adam B »

Offline muggy

  • Użytkownik

# Lipiec 27, 2009, 13:44:45
Jeśli dodasz w metodzie tworzącej nazwy swoim objektom Answear:

// TWORZENIE ELEMENTÓW
Panel Quest = new Panel();
Label Name = new Label();
TextBox Question = new TextBox();
TextBox Answer1 = new TextBox();
TextBox Answer2 = new TextBox();
TextBox Answer3 = new TextBox();
TextBox Answer4 = new TextBox();

Answer1.Name = "answear1";
Answer2.Name = "answear2";
Answer3.Name = "answear3";
Answer4.Name = "answear4";


to możesz rozpoznawać kliknięty TextBox w ten sposób:
private void Answer_Click(object sender, EventArgs e)
{
// zadziała tylko, gdy zdarzenie wywołane przez objekt klasy TextBox (jedna z odpowiedzi)
if (sender is TextBox)
{
TextBox answear = sender as TextBox;
// rozstrzygnięcie wybranej odpowiedzi na bazie właściwości Name
switch (answear.Name)
{
case "answear1":
answear.BackColor = Color.Red;
break;
case "answear2":
answear.BackColor = Color.Blue;
break;
case "answear3":
answear.BackColor = Color.Green;
break;
case "answear4":
answear.BackColor = Color.Yellow;
break;
}
}
}

Mam nadzieję, że pomogłem, pozdrawiam
« Ostatnia zmiana: Lipiec 27, 2009, 13:50:44 wysłana przez muggy »

Offline Adam B

  • Użytkownik

# Lipiec 27, 2009, 14:18:35
Dzięki.. ale problem już rozwiązałem post wyżej :)