Diskuze: Ako fokusnúť položku ListBoxu po reloade cez binding
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.

Člen

Zobrazeno 7 zpráv z 7.
//= Settings::TRACKING_CODE_B ?> //= Settings::TRACKING_CODE ?>
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.
Taková funkcionalita patří do samostatné třídy, které se říká
attached behavior, kterou pak attachneš na daný control.
Jako příklad tady mám behavior, který při změně itemssource u comboboxu
vybere vždy první item, od toho bys měl být schopný se odpíchnout.
public class ComboBoxSelectBehavior
{
/// <summary>
/// Dependency properta, který mi říká, že chci při změně zdroje
/// </summary>
public static DependencyProperty SelectFirstOnNewSourceProperty = DependencyProperty.RegisterAttached("SelectFirstOnNewSource", typeof(bool), typeof(ComboBoxSelectBehavior), new UIPropertyMetadata(false, SelectFirstOnNewSourceChanged));
/// <summary>
/// Getter
/// </summary>
public static bool GetSelectFirstOnNewSource(DependencyObject obj)
{
return (bool)obj.GetValue(SelectFirstOnNewSourceProperty);
}
/// <summary>
/// Setter
/// </summary>
public static void SetSelectFirstOnNewSource(DependencyObject obj, bool value)
{
obj.SetValue(SelectFirstOnNewSourceProperty, value);
}
/// <summary>
/// Změna ddependency property, registrace
/// </summary>
public static void SelectFirstOnNewSourceChanged(
DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var comboBox = d as ComboBox;
if (comboBox == null) return;
bool oldValue = (bool)e.OldValue, newValue = (bool)e.NewValue;
if (newValue == oldValue) return;
if (newValue)
{
var itemsSourcePropertyDescriptor = TypeDescriptor.GetProperties(comboBox)["ItemsSource"];
itemsSourcePropertyDescriptor.AddValueChanged(comboBox, ComboBox_ItemsSourceChanged);
}
else
{
var itemsSourcePropertyDescriptor = TypeDescriptor.GetProperties(comboBox)["ItemsSource"];
itemsSourcePropertyDescriptor.RemoveValueChanged(comboBox, ComboBox_ItemsSourceChanged);
}
}
/// <summary>
/// Eventa o změně zdroje
/// </summary>
private static void ComboBox_ItemsSourceChanged(object sender, EventArgs e)
{
var comboBox = (ComboBox)sender;
if (comboBox.Items.Count > 0)
comboBox.SelectedIndex = 0;
else
comboBox.SelectedIndex = -1;
}
}
použití je pak v xamlu
<ComboBox behav:ComboBoxSelectBehavior.SelectFirstOnNewSource="True" />
výhodou je, že tato funkcionalita je izolovaná a znovupoužitelná a
prostě SOLID
Ďakujem. Ak tomu správne rozumiem, tak vlastne rozširuješ triedu ComboBox
o novú metódu SelectFirstOnNewSource, ktorá by sa mala vykonať, keď sa
zmení zdroj. Alebo mi niečo uniklo? Trochu ma mätie, že v xamli
priraďuješ
<ComboBox behav:ComboBoxSelectBehavior.SelectFirstOnNewSource="True"
/>
hoci samotnú vlastnosť SelectFirstOnNewSource v triede
ComboBoxSelectBehavior vôbec nemáš. A ešte načo je tam vlastne tá
dependencyproperta? Nestačilo by jednoducho ošetrovať udalosť
ItemSourceChanged? Sorry za možno blbé otázky, ale chcem veciam porozumieť,
nie iba mechanicky opisovať kódy. Vďaka .
Ne, není to rozšíření třídy ComboBox, ale je to vytvoření tzv. attached property
Ta se na daný control pouze "připojuje", ale control ji nezná. Je to to samé
jako např.
<Grid>
//definice řádků a sloupců...
<Combobox Grid.Row="1" />
<Grid />
ComboBox taky neví nic o Grid.Row, ale je možné na něj tuto property připojit.
hoci samotnú vlastnosť SelectFirstOnNewSource v triede
ComboBoxSelectBehavior vôbec nemáš
mám, je to dependency property definovaná jako
public static DependencyProperty SelectFirstOnNewSourceProperty = DependencyProperty.RegisterAttached("SelectFirstOnNewSource", typeof(bool), typeof(ComboBoxSelectBehavior), new UIPropertyMetadata(false, SelectFirstOnNewSourceChanged));
Nestačilo by jednoducho ošetrovať udalosť ItemSourceChanged
Asi by to stačilo, ale tohle je obecnější a zapouzdřenější
řešení.
Doufám, že jsem to podal trochu srozumitelně. Doporučuju si alespoň krátce nastudovat, co je Dependency property a Attached property, protože ve WPF je to celkem základní věc.
Ahoj, tak po čase som sa k problému znovu vrátil a keďže som stále nebol schopný dobrať sa k úspešnému koncu, urobil som si projekt s jedným comboboxom a jedným tlačidlom "obráť poradie". Vytvoril som si triedu Kontext a do nej dal list stringov, ktorý sa v konštruktore naplní zopár položkami. Combobox som v xamli nabindoval na tento list a potom som si skopíroval presne tú triedu, čo si sem dal. No a výsledok je taký, že po spustení programu sa vytvorí okno, vytvorí sa kontext a list s položkami. Vtedy sa generuje aj metóda ComboBox_ItemsSourceChanged a vyberie sa prvá položka. Ale ak kliknem na tlačidlo "Obráť poradie", čo urobí iba List.Reverse() tak položky v comboboxe sa obrátia ale udalosť sa už nevyvolá a nevyberie sa prvá položka. Takže vlastne ani presným skopírovaním Tvojho kódu som nedosiahol to, aby sa výber prvej položky urobil po akejkolvek zmene obsahu comboboxu resp zdrojového listu. Kde môže byť chyba resp. ako na to?
Pokud neměníš zdroj dat, tak se logicky ta událost vyvolat nemůže. Můžeš si zkusit tu událost vyvolat ručně hned po List.Reverse(), nebo si můžeš ten kód napsat do extra funkce a vyvolávat to tam...
No pôvodne som sa o to pokúšal. Hneď po zavolaní reverse som ručne vyvolával aj onú udalosť aj priamo metódu, ktorá by vybrala a fokusla položku v listboxe. Lenže vtedy program často padal s hláškou, že sa pokúšam vyberať a fokusovať neexistujúci objekt. Evidentne teda ešte update listboxu neprebehol a práve preto som chcel aby sám listbox po načítaní nových dát vyvolal udalosť že už mám všetky dáta update prebehlo v poriadku som pripravený. Kedysi som v Delphi toto riešil cez udalosť onchanged ktorú tam mal listbox a ktorá sa vyvolala po akejkoľvek zmene obsahu komponenty, teda po pridaní položky, vymazaní, preskupení, načítaní nových dát. Toto mi tu presne chýba aby som jednoducho ošetril udalosť, ktorá je vyvolaná po zmene obsahu listboxu. Akosi sa mi nechce veriť že pri tak komplexnom systéme takú banálnu vec nejde odchytiť. Skúšal som aj udalosť Loaded, ale aj tá je generovaná len po prvom načítaní dát a potom už nie, čo je tiež podla mňa škoda, pretože dáta sa loadujú stále. Ak by teda mal niekto nejaký nápad, bude to vítané, inak pokračujem v pátraní a v úplne najhoršom sa vykašlem na binding a urobím si vlastnú metódu UpdateListbox, ktorá v cykle cez add nahádže do listboxu položky zo zdroja dát a nakoniec vyberie a fokusne požadovaný záznam. Trocha amatérske ale zaručene funkčné.
Zobrazeno 7 zpráv z 7.