NOVINKA! E-learningové kurzy umělé inteligence. Nyní AI za nejlepší ceny. Zjisti více:
NOVINKA – Víkendový online kurz Software tester, který tě posune dál. Zjisti, jak na to!

Diskuze: c# form - dynamicky přidávané položky do kontextového menu

V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.

Aktivity
Avatar
Michaal.K
Člen
Avatar
Michaal.K:17.8.2016 12:46

Ahoj,

vytvořil jsem si kontextové menu a jeho položky přidávám v kódu. Problém je v tom, že počet položek v kontextovém menu se uživatelsky mění za běhu programu a já potřebuju zjistit na kterou položku uživatel kliknul a podle toho zavolat dannou funkci. Viz. obrázek. Díky za rady...

 
Odpovědět
17.8.2016 12:46
Avatar
Odpovídá na Michaal.K
Michal Žůrek - misaz:17.8.2016 12:49

položka na kterou uživatel kliknul se ti vrátí v parametru sender obsluhy události. Takže na všechny dynamicky vytvořené položky přidej nějakou obsluhu události, které bude mít standardní parametry sender a e a pak v ni si můžeš zjistit z parametru sender o kteroru položku jde.

Editováno 17.8.2016 12:51
 
Nahoru Odpovědět
17.8.2016 12:49
Avatar
Michaal.K
Člen
Avatar
Odpovídá na Michal Žůrek - misaz
Michaal.K:17.8.2016 14:03

Tak jsem si vytvořil událost:

this.treeMenuStripItem.DropDownItemClicked += new ToolStripItemClickedEventHandler(this.TreeMenuStripItemDropDownItemClicked);

Ta opravdu funguje, že když kliknu v kontextovém menu na položky: test, aaa, bbb tak skočím do obsluhy této události. To jsem si odkrokoval.
Ale když chci přes sender zjistit na jakou položku bylo kliknuto tak sender nabízí možnosti jen: sender.Equals, sender.GetHashCode, sender.GetType, sender.ToString...

 
Nahoru Odpovědět
17.8.2016 14:03
Avatar
hj.masek
Člen
Avatar
hj.masek:17.8.2016 14:40
var clickedItem = sender as ToolStripItem;
//ostatni operace uz s polozkou
 
Nahoru Odpovědět
17.8.2016 14:40
Avatar
Michaal.K
Člen
Avatar
Odpovídá na hj.masek
Michaal.K:17.8.2016 14:58

Díky za odpověď. Teď už mohu pracovat jako s položkou ale problém je v tom, že v senderu mám uloženou položku: Test a já jsem klikl na: aaa. Viz. obrázek v prvním příspěvku....

 
Nahoru Odpovědět
17.8.2016 14:58
Avatar
Odpovídá na Michaal.K
Michal Žůrek - misaz:17.8.2016 18:00

protože jsi tu událost nastavil na

this.treeMenuStripItem

cž je předpokládám položka Test, tu událost musíš nastavit na položku aaa, pak bbb, zkrátka na všechny na kterých to chceš odchytit.

 
Nahoru Odpovědět
17.8.2016 18:00
Avatar
VitekST
Člen
Avatar
Odpovídá na Michaal.K
VitekST:17.8.2016 21:01

No... Já jsem to dělával za pomocí přiřazování anonymní metody na handler při vytváření, a jako identifikátor jsem použil lokální proměnnou (třeba z foreache).

Nějak takto: (kód jsem vymyslel na rychlo, nemusí to dávat smysl)

void Populate(){
        string[] names = new string[] { "A", "B", "C", "D" }; //Pole s položkama, reprezentuje třeba seznam klíčů položek

        foreach(string name in names){ //Cyklus, který projde všechny položky
                ToolStripItem item = new ToolStripItem(); //Nová položka
                item.Text = name; //Text položky

                item.Clicked = (o, e) => { //Lambda výraz, vytváříme a předáváme novou anonymní metodu
                        Clicked(name); //Zavoláme metodu, která se postará o kód po kliknutí, předáváme proměnnou z foreach cyklu
                };
        }
}

void Clicked(string text){
        MessageBox.Show(text); //Zde si dělej co chceš
}

Dělával, ale nedělám.
Jednak třeba proto, že to je neefektivní, pro každou položku vytváříš novou metodu.
Pro pár položek to nevadí, ale teď si představ, že těch položek máš stovky. Možná nereálné, ale přece chceme, aby naše appka byla škálovatelná, ne?

Dnes bych na to šel přes sender.
Jakmile připíchneš na událost metodu odpovídající handleru (tj. s parametry : )

object sender, EventArgs e

...dostaneš objekt sender. Jedná se o přetypovaný objekt ovládacího prvku, který vyvolal událost.
Tzn. jestli se kliklo na položku v menu, sender bude přetypovaný ToolStripItem, který lze přetypovat zpět.

Toho můžeš krásně využít, protože ToolStripItem má vlastnost Key (klíč), kterou můžeš nastavit na cokoli, a pak se podle toho rozhodovat.

Nějak takto:

void Populate(){
        string[] names = new string[] { "A", "B", "C", "D" }; //Pole s položkama, reprezentuje třeba seznam klíčů položek

        foreach(string name in names){ //Cyklus, který projde všechny položky
                ToolStripItem item = new ToolStripItem(); //Nová položka
                item.Text = name; //Text položky
                item.key = name; //Klíč položky (důležitý!)

                item.Clicked += Clicked; //Zde připíchneme metodu na událost
        }
}

void Clicked(object sender, EventArgs e){ //Jakmile se událost vyvolá...
        ToolStripItem clickedItem = (ToolStripItem)o; //...můžeme si sender přetypovat na ToolStripItem.

        MessageBox.Show(clickedItem.Key); //No a vypíšeme ten klíč, který jsme dříve uložili
}
 
Nahoru Odpovědět
17.8.2016 21:01
Avatar
Michaal.K
Člen
Avatar
Odpovídá na Michal Žůrek - misaz
Michaal.K:18.8.2016 7:41

Díky za odpověď.
Ale je tam:

this.treeMenuStripItem.DropDownItemClicked

a když jsem to krokoval a klikl jsem na položku "Test" tak to do té události neskočilo až když jsem klikl na "test" nebo "aaa" nebo "bbb". Tak ztoho jsem usoudil, že obsluhuji tyto položky.
Ale položky test, aaa, bbb jsou uživatelsky měnitelné za běhu programu. Takže nevím kolik jich bude a vytvářet třeba 20 událostí pro každou položku to mi nepřijde moc efektivní...
Myslel jsem, že existuje nějaká událost click pro ten list s položkami (test, aaa, bbb), kdy bych pak zjistil na kterou položku se kliklo.

 
Nahoru Odpovědět
18.8.2016 7:41
Avatar
Michaal.K
Člen
Avatar
Odpovídá na VitekST
Michaal.K:18.8.2016 7:46

Díky za odpověď...
Tak tohle už je na mě dost složitý, ale nejefektivnější :-) O vlastnosti key jsem vůbec nevěděl. Zkusím to nějak střebat a dát do svého programu. Díky

 
Nahoru Odpovědět
18.8.2016 7:46
Avatar
Michaal.K
Člen
Avatar
Odpovídá na VitekST
Michaal.K:18.8.2016 8:38

Tak u

ToolStripItem item = new ToolStripItem(); //Nová položka

se objevila chybová hláška

Nelze vytvořit instanci abstraktní třídy nebo rozhraní System.Windows.Forms.ToolStripItem. (CS0144)

a ještě u

item.key = name; //Klíč položky (důležitý!)

toto

System.Windows.Forms.ToolStripItem neobsahuje definici key a nebyla nalezena žádná metoda rozšíření key, která by přijímala první argument typu System.Windows.Forms.ToolStripItem (nechybí direktiva using nebo odkaz na sestavení?) (CS1061)
 
Nahoru Odpovědět
18.8.2016 8:38
Avatar
VitekST
Člen
Avatar
Odpovídá na Michaal.K
VitekST:18.8.2016 8:46

Promiň, to má člověk tak, když už pomalu usíná u klávesnice. :D

Nahraď ToolStripItem za ToolStripMenuItem, a vlastnost Key za Tag.
Takže takto:

ToolStripMenuItem item = new ToolStripMenuItem(); //Nová položka

...

item.Tag = name; //Klíč položky (důležitý!)

...

MessageBox.Show(clickedItem.Tag); //No a vypíšeme ten klíč, který jsme dříve uložili

A slovo "klíč" by bylo vhodnější nahradit za "značku", v tomto případě.

Editováno 18.8.2016 8:48
 
Nahoru Odpovědět
18.8.2016 8:46
Avatar
Michaal.K
Člen
Avatar
Odpovídá na VitekST
Michaal.K:18.8.2016 9:01

V poho ;-)
Ještě mám jeden dotaz. Upravil jsem

item.Clicked += Clicked; //Zde připíchneme metodu na událost

na

item.Click += Clicked;

ale teď se při kliknutí na "test" nebo "aaa" nebo "bbb" v kontextovém menu nedostanu do udalosti

void Clicked(object sender, EventArgs e)
 
Nahoru Odpovědět
18.8.2016 9:01
Avatar
VitekST
Člen
Avatar
Odpovídá na Michaal.K
VitekST:18.8.2016 9:12

Aha.
Zdá se, že událost Click neplatí na položky které jsou podřazené, budeme muset tedy metodu připíchnout na nadřazené menu, a tedy to bude událost DropDownItemClic­ked.

Stejně tak musíme změnit metodu samotnou.
Nyní není senderem položka, ale nadřazené menu, změnil se typ argumentů, kde následně ten objekt obsahuje položku, na kterou se kliklo.

void Populate(){
        string[] names = new string[] { "A", "B", "C", "D" }; //Pole s položkama, reprezentuje třeba seznam klíčů položek

        foreach(string name in names){ //Cyklus, který projde všechny položky
                ToolStripMenuItem item = new ToolStripMenuItem(); //Nová položka
                item.Text = name; //Text položky
                item.Tag = name; //Značka položky (důležitá!)

                menu.Items.Add(item); //Přidáme položku do menu
        }

        menu.DropDownItemClicked += Clicked; //Připíchneme metodu na událost
}

void Clicked(object sender, ToolStripItemClickedEventArgs e){ //Jakmile se událost vyvolá...
        ToolStripItem clickedItem = e.ClickedItem; //...můžeme si získat položku, na kterou se kliklo.

        MessageBox.Show(clickedItem.Tag); //No a vypíšeme tu značku, kterou jsme dříve uložili
}
Akceptované řešení
+20 Zkušeností
Řešení problému
 
Nahoru Odpovědět
18.8.2016 9:12
Avatar
Michaal.K
Člen
Avatar
Odpovídá na VitekST
Michaal.K:18.8.2016 11:18

Díky moc :-) Teď už vše funguje správně....

 
Nahoru Odpovědět
18.8.2016 11:18
Avatar
VitekST
Člen
Avatar
Odpovídá na Michaal.K
VitekST:18.8.2016 11:22

No problem m8. 8-)

 
Nahoru Odpovědět
18.8.2016 11:22
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 15 zpráv z 15.