WPF - dodatkowy element w Combobox

0

Cześć!

Mógłby ktoś doświadczony napisać, w jaki sposób rozwiązać, w sposób elegancki, poniższy problem? To co piszę, to rzecz jasna swego rodzaju pseudokod, ale każdy powinien zrozumieć co mam namyśli.

Załóżmy, że korzystam z zewnętrznego API, które zwraca mi pewną listę obiektów "FakeObject".

We ViewModelu uzupełniam listę, którą następnie chcę wyświetlić w ComboBoxie. VM oczywiście implementuje wszystkie potrzebne interfejsy i umie powiadamiać widok o ewentualnych zmianach.

List<FakeObject> FakeObjects = externalAPI.GetListOfFakeObjects();

Dodatkowo potrzebuję mieć informację, który obiekt jest aktualnie wybrany. W tym celu tworzę kolejne property:

SelectedFakeObject i binduje do niego SelectedItem z widoku.

Do tej pory wszystko jest super. Jednak dochodzi mi dodatkowe (pewnie dość częste) wymaganie. Jako pierwszy item w combo potrzebuję wyświetlić dodatkowe pole z wartością "XYZ". Mogę to rozwiązać za pomocą XAML-a.

<ComboBox.Resources>
  <ResourceDictionary>
    <CollectionViewSource x:Key="ViewSource" Source="{Binding FakeObjects}" />
  </ResourceDictionary>
</ComboBox.Resources>
  <ComboBox.ItemsSource>
    <CompositeCollection>
      <ComboBoxItem>XYZ</ComboBoxItem>
      <CollectionContainer Collection="{Binding Source={StaticResource ViewSource}}" />
    </CompositeCollection>
(...)

We VM zmieniam SelectedFakeObject na tym Object i wszystko prawie działa. Mam fajne rozróżnienie, czy wybrany element jest to FakeObject (operator is), czy nie. Ale jak w takim podejściu ustawić pierwszy element jako domyślnie wybrany? Jeśli ustawię SelectedIndex w widoku, to to nie zadziała, bo mój SelectedFakeObject da tam nulla i domyślnie nadal nie będzie nic ustawione. Dodatkowo jeśli chciałbym mieć przycisk Reset we VM, to też chyba nie uda mi się przywrócić elementu "XYZ". Dodam, że wygodnie jest mieć listę obiektów FakeObject, a nie wrapper, który zawiera jeden string i pozostałe elementy są kopiami FakeObject - bo to wymusza na mnie sprawdzanie warunków w kilku innych miejsach.

W jaki sposób rozwiązać ten problem z dodatkowym elementem w liście, który jest zwykłym stringiem i pełni funkcje nie wybrania niczego? W jaki sposób wybrać domyślne zaznaczenie tego elementu?

0

miałem identyczny problem i rozwiązałem go po prostu tworząc klasę dziedziczącą po (w Twoim przypadku) FakeObject

tak więc robisz:

public class EmptyFakeObject : FakeObject
{
    public override string ToString()
    {
        return "XYZ";
    }
}

i zamiast:

<ComboBoxItem>XYZ</ComboBoxItem>

tworzysz:

<local:EmptyFakeObject />

potem ustawienie pustego elementu to po prostu:

SelectedItem = emptyFakeObject;

(gdzie emptyFakeObject to instancja EmptyFakeObject - można zaimplementować tę klasę jako singleton)
potem elementy od pustego elementu możesz odróżnić po instancji zamiast po typie - imo trochę bardziej eleganckie

0

Może bardziej skomplikuję. Jeśli będzie to Singleton, to nie stworzę takiego obiektu w XAMLu.

No więc idąc dalej, w swoim VM muszę:
a) Utworzyć instancję EmptyFakeObject - nie ma w tym nic złego.
b) Pobrać dane z API, które uzupełni listę - i tak to robię i jest to normalne.
c) Muszę wstawić swój empty object do tej listy - i to mi się nie podoba, bo trzymam obiekt, który w rzeczywistości reprezentuje brak stanu. Mam listę obiektów, która zawiera jeden wyjątkowy element, który w sumie nie istnieje. Jeśli taką listę chciałbym przekazać dalej, bądź zrobić z nią cokolwiek innego, to muszę mieć na uwadzę to, że ten nie-obiekt tam jest. To mnie cholernie drażni, bo to jest takie wyjątkowe i zdaje się niepotrzebne.

Po części Twoje rozwiązanie mi się podoba. Może ja szukam dziury w całym i nie powinienem za dużo nad tym myśleć. Myślałem, że uda się Bindować do listy, która go nie będzie posiadała.

Ograniczają mnie chyba umiejętności, bo Twoje sugestie byłby super, gdybym tego elementu nie musiał dodawać do listy (gdyby XAML łyknął Singleton). Jeszcze do głowy przychodzi mi trzymanie dwóch list, ale to już chyba w ogóle karkołomne.

0

Poradziłem sobie, jednak udało się utworzyć instancję w XAMLu poprzez metodę, a nie poprzez konstruktor. Dziękuję za pomysł.

0
Świetny Lew napisał(a):

Poradziłem sobie, jednak udało się utworzyć instancję w XAMLu poprzez metodę, a nie poprzez konstruktor. Dziękuję za pomysł.

mógłbyś pokazać swoją implementację?

Myślałem, że uda się Bindować do listy, która go nie będzie posiadała.

no dokładnie taki pomysł przedstawiłem

0

Tak, jutro jak usiądę do swojego komputera to pokażę przykładowy kod, żeby ktoś mógł z niego skorzystać.

Pozdrawiam

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