Ta ukázka není vyloženě situace, kde by vlákna hrála nějakou roli, ale tím druhým vláknem jsem si pouze pomohl vyřešit ten konflikt přístupů, který nastal kvůli tomu, že události CheckBoxu a CheckedListBoxu byli tak úzce provázané. Vlákna jsou (zvenku) relativně jednoduchá a zajímavá, ale zatím pro Vás nejsou nutností, pokud uvážím, na jakém projektu pracujete. Řádek, který jste označil, souvisí se scénářem, kdy je pod jedním CheckBoxem více položek v CheckedListBoxu. Vy jste tuto situaci vyloučil (ačkoliv pak mi uniká smysl použití CheckedListBoxu). Nicméně znamená následující (obecně):
Dim položky = New Integer() {1,2,3,4,5,6,7}
Dim položkySudé = položky.Except(new Integer() {1,3,5,7})
' položkySudé nyní obsahuje pole integerů s hodnotami 2,4,6
Except je extension metoda, která vrací všechno ze vstupní množiny, kromě množiny dané parametrem.Je definovaná pro rozhraní IEnumerable. IEnumerable je rozhraní, které se používá na všechny datové objekty, kterými lze iterovat. Cokoliv, u čeho můžete použít For Each (pole, List<T>, TreeNodeCollection etc.) implementuje rozhraní IEnumerable a tím pádem na to lze použít extension metoda Except.
Dim položky1 = New Integer() {1,2,3,4,5,6,7}
Dim položky2 = New Integer() {1,2,3}
Dim položky1podminka = položky1.Any(Function(p) p > 5) ' True
Dim položky2podminka = položky2.Any(Function(p) p > 5) ' False
Any je opět extension metoda. Je definovaná též pro IEnumerable (respektive IEnumerable<T> pro podporu generiky). Vrací vždy pravdivostní hodnotu, tedy True nebo False (Boolean) a vrací True, pokud alespoň jeden prvek vstupní množiny vyhoví podmínce. Podmínku jsem výše definoval lambda funkcí (Function(p) p > 5), ale může odkazovat i na existující funkci v kódu (jako parametr by se dosadilo AddressOf JménoFunkce). Ještě malá poznámka ke generice. Jak vidíte, Except a Any budou fungovat na všem, co má enumerátor (tedy implementuje IEnumerable či Enumerable<T>. Jsou to totiž generické metody. Generické znamená, že mají typový parametr (T), stejně jako třeba seznam List(OF T) a když je potřeba, vytvoří se podle této šablony metoda (nebo třída) na míru danému typu. Napíšeme-li tedy v kódu něco jako Dim seznam = New List(Of String), při běhu programu se vytvoří nová třída, která nebude typu List(Of String), ale něco jako List`1blablabla, prostě unikátní identifikátor CLR. Tato třída stejně jako List(Of T) bude implementovat IEnumerable, takže se bude dát dosadit tam, kam List(Of String). Stejně tak generické funkce Except, Any (a všechny ostatní http://msdn.microsoft.com/en-us/library/... ) jsou definované jednou s daným typovým parametrem, ale budou fungovat pro jakýkoliv typ, který existuje v .NET frameworku, nebo pro Váš vlastní datový typ. Díky tomu můžeme použít Except a Any na pole integerů výše. Zpět k vašemu problému - pokud tedy pro jeden CheckBox může být pouze jedna položka v CheckedListBoxu, nemá smysl CheckedListBox používat. Stejně tak, generování té položky by nemělo být při prvním zaškrtnutí CheckBoxu, ale například při načtení formuláře. Jestli Vám dobře rozumím, požadujete aby CheckBox měl závislý jiný CheckBox a: 1.) Zaškrtnu master = zaškrtnu slave 2.) Odškrtnu master = odškrtnu slave 3.) Zaškrtnu slave = nedělám nic pro master (?) 4.) Odškrtnu slave = odškrtnu master Každopádně ať je to jak chce, toto je jednoduché pro prvky nakreslené v designeru. Předpokládám, že Vy prvky generujete dynamicky a proto jste sáhl po CheckedListBoxu, jelikož se do něj položky umisťují snadněji, než na formulář. Tomu rozumím, ale přesto si nemyslím, že je CheckedListBox ideální. Stejně tak můžete dynamicky vygenerovat CheckBox (slave) a provázat jeho události s master.
' Toto probíhá v Load formuláře
' Na formuláři už máme checkbox CheckBox1
Dim slaveCheckBoxForMaster1 = new CheckBox() With {.Text = "Lupenaté", Left = 12, Top = 24}
Controls.Add(slaveCheckBoxForMaster1)
AddHandler slaveCheckBoxForMaster1.CheckedChanged,
Sub(sender2 As Object, e2 As EventArgs)
If Not DirectCast(sender2, CheckBox).Checked Then CheckBox1.Checked = False
End Sub
AddHandler CheckBox1.CheckedChanged,
Sub()
slaveCheckBoxForMaster1.Checked = CheckBox1.Checked
End Sub
Píši to z hlavy, pravděpodobně tam budou nějaké nedostatky, ale myšlenka by měla být jasná. Máte hlavní CheckBox (CheckBox1), který si při design time přetáhnete na formulář. Máte vygenerovaný CheckBox (slaveCheckBoxForMaster1), který se při runtimu vytvoří v události Load formuláře a navěsíte jak jeho událost (na jejímž základě budete modifikovat hlavní CheckBox), tak navěsíte handler pro již existující hlavní CheckBox, aby ten mohl také ovlivňovat svůj podřízený CheckBoxu. Nejspíš bude třeba zavést příznak programováZměna podobně, jako jsem ho já uvedl ve své ukázce. Jde o to, že pokud CheckBox zaškrtnete, vyvolá se jeho událost a ta vyvolá zaškrtnutí podřízeného CheckBoxu, což vyvolá jeho událost a zaškrtne hlavní CheckBox, což vyvolá jeho událost a zaškrtne podřízený Checkbox, což... A tak dále. Pokud v programu budete zaškrtávat CheckBox, předtím dejte programováZměna = True a potom programováZměna = False, a do všech handlerů zaškrtnutí dejte jejich obsah do podmínky If Not programováZměna. Tím si zajistíte pouze reakci na akci uživatele, nikoliv programu. U všech kromě prvního příspěvku ve vláknu by měl být odkaz "Označit jako odpověď" nebo podobný. U příspěvků, které na položený dotaz odpovídají tento odkaz následujte a tím by se mělo vlákno označit za vyřešené.
|