2010-11-18 10 views
6

Wiele czytałem o MVVM (używając biblioteki Laurenta Bugniona w szczególności) i ciągle walczę o to, aby ustalić, jak robić rzeczy w MVVM, które w innym przypadku byłyby łatwe z kodem.Zawartość Aktualizacji Listbox MVVM Utrzymanie Wybranego Elementu Silverlight

Oto tylko jeden przykład, w którym podejrzewam, że robię rzeczy w trudny sposób. Jeśli ktokolwiek ma czas na przeczytanie tego wszystkiego, może może wypowiedzieć się na temat zdrowego rozsądku mojego podejścia. :)

Mam pole listy związany z ViewModel tak:

<ListBox x:Name="lstFruitBasketLeft" ItemsSource="{Binding FruitBasket}" 
    SelectedItem="{Binding SelectedFruit, Mode=TwoWay}" Width="150"> 
<ListBox.ItemTemplate> 
    <DataTemplate> 
     <StackPanel Orientation="Horizontal" VerticalAlignment="Center" 
        HorizontalAlignment="Left" Margin="2"> 
      <TextBlock Text="{Binding Name}" /> 
      <TextBlock Text=":" /> 
      <TextBlock Text="{Binding Quantity}" /> 
     </StackPanel> 
    </DataTemplate> 
</ListBox.ItemTemplate> 

ItemSource jest ObservableCollection obiektów owocowe:

public class Fruit 
{ 
    public string Name { get; set; } 
    public int Quantity { get; set; } 

    public Fruit() { } 
    public Fruit(string name, int quantity) 
    { 
     this.Name = name; 
     this.Quantity = quantity; 
    } 
    } 

To jest zdefiniowane w ViewModel as:

// Property FruitBasket 
public const string FruitBasketPropertyName = "FruitBasket"; 
private ObservableCollection<Fruit> _fruitBasket = null; 
public ObservableCollection<Fruit> FruitBasket 
{ 
    get { return _fruitBasket; } 
    set 
    { 
    if (_fruitBasket == value) 
     return; 

    _fruitBasket = value; 

    // Update bindings, no broadcast 
    RaisePropertyChanged(FruitBasketPropertyName); 
    } 
} 

Związana właściwość SelectedItem jest jako takie:

//Property SelectedFruit 
public const string SelectedFruitPropertyName = "SelectedFruit"; 

private Fruit _selectedFruit = null; 

public Fruit SelectedFruit 
{ 
    get { return _selectedFruit; } 
    set 
    { 
    if (_selectedFruit == value) 
     return; 

    var oldValue = _selectedFruit; 
    _selectedFruit = value; 

    // Update bindings, no broadcast 
    RaisePropertyChanged(SelectedFruitPropertyName); 
    } 
} 

Następnie lista jest wypełniana na budowę ViewModel.

Teraz dodaję funkcję RelayCommand do przycisku na stronie prezentacji, który wykonuje metodę zwiększania ilości wybranego elementu. Zauważ, że nie używam jeszcze tego parametru, ale "Bob" jest symbolem zastępczym niektórych zmian na później.

<Button x:Name="butMore" Content="More!" HorizontalAlignment="Right" Height="25" Width="75" Margin="4"> 
    <i:Interaction.Triggers> 
     <i:EventTrigger EventName="Click"> 
      <cmd:EventToCommand 
       Command="{Binding addMoreCommand}" 
       CommandParameter="Bob" /> 
     </i:EventTrigger> 
    </i:Interaction.Triggers> 
</Button> 

Oto kod za pomocą polecenia:

// Property addMoreCommand 
public RelayCommand addMoreCommand 
{ 
    get; 
    private set; 
} 

...

//Init relays (this is in the constructor) 
    addMoreCommand = new RelayCommand(AddFruit, CanExecute); 

...

public void AddFruit() 
{ 
    //Increment the fruit 
    SelectedFruit.Quantity++; 

    //Save the previous selected item 
    Fruit oldSelectedItem = SelectedFruit; 

    //We have to have a new list in order to get the list box to refresh 
    FruitBasket = new ObservableCollection<Fruit>(FruitBasket); 

    //Reselect 
    SelectedFruit = oldSelectedItem; 
} 


public bool CanExecute() 
{ 
    return true; //for now 
} 

Teraz to działa, ale mam pewne problemy z tym:

Po pierwsze, czuję, że istnieje wiele warunków, które muszą się ze sobą połączyć, aby zadziałało i zastanawiam się, czy będę miał tyle szczęścia, próbując przenieść kod telelizujący i przeciągnij Telerik do MVVM.

Po drugie, wygląda na to, że do odtworzenia takiej listy wystarcza bardzo słabe podejście do wydajności.

Wreszcie, wydaje się, że będzie łatwiej w kodzie za sobą (chociaż nie jestem w 100% pewny, że nadal nie będę musiał odbudowywać tej listy).

Czy ktoś ma jakieś przemyślenia na temat mojego podejścia, a może nawet ... sugestie, aby ułatwić sobie pracę? Czy właśnie tu brakuje czegoś oczywistego?

Dzięki

-Driodilate:]

Odpowiedz

2

maulkye,

Jest coś idzie źle, jeśli trzeba odświeżyć ObservableCollection.Zwykle nie powinno to być konieczne, ponieważ ObservableCollection będzie powiadamiać o zmianach w przedmiotach.

Nigdy to zrobić:

FruitBasket = new ObservableCollection<Fruit>(FruitBasket); 

Twój public ObservableCollection<Fruit> FruitBasket nie powinien mieć seter publicznego, to należy tylko do odczytu. Tylko Add lub Remove Przedmioty do/z listy.

Jeśli chcesz obsłużyć wiele wyborów, prawdopodobnie będziesz potrzebować rozszerzonego CollectionView, który może obsłużyć to, uzyskać więcej wskazówek here.

Mam nadzieję, że to pomoże trochę, nawet jeśli ja prawdopodobnie nie odpowie na wszystkie pytania:)

EDIT: Ok, myślę, że mam kilka rzeczy źle. Teraz myślę, że w pełni rozumiem, co próbujesz osiągnąć. Jesteś , a nie otrzymujesz powiadomienie o zmianie właściwości, prawda? Z tego powodu zmieniliśmy "BindableLinq" w jednym z naszych projektów, który można bezproblemowo skompilować w Silverlight. (dostępne są podobne rozwiązania o nazwie Continuous Linq lub Obtics, dokonaj wyboru).

Korzystanie BindableLinq, można przekształcić swoje ObservableCollection do BindableCollection stosując pojedynczą metodę rozszerzenia. BindableCollection będzie wtedy poprawnie odzwierciedlał wszystkie zmiany. Spróbuj.

EDIT2: Aby wdrożyć prawidłowe ViewModel, proszę wziąć pod uwagę następujące zmiany.

1) Fruit to Twój model Model. Ponieważ nie implementuje ona INotifyPropertyChanged, nie będzie propagować żadnych zmian. Utwórz , osadzając swój model Fruit i wywołaj RaisePropertyChanged dla każdego ustawiacza właściwości.

2) Zmień swój FruitBasket na ObservableCollection z . Powoli zaczyna to mieć sens :)

3) SelectedFruit również musi być . Teraz ma to jeszcze większy sens.

4) Teraz już działa dla mnie, nawet bez BindableLinq. Czy odniosłeś jakiś sukces?

HTH

pozdrawiam,
Thomas

+0

Dobrze, że nie pomaga, ale pozostawia mnie w sytuacji, nie wiedząc, jak uzyskać kontrolę związaną poprawnie zaktualizować. Pamiętaj, że nie dodaję ani nie usuwam elementów (działa to doskonale bez dodatkowego kodu). Mój problem występuje, gdy aktualizuję właściwość jednego z obiektów, który znajduje się w ObservableCollection. – maulkye

+0

Hmmmm, chociaż mnie zmusiłeś. Mogłem po prostu usunąć wybrany element, zaktualizować go, a następnie dodać go ponownie, aby automatyczne aktualizacje działały. Chociaż nie jestem pewien, jak to wpłynie na sortowanie. – maulkye

+0

Sprawdź moją EDYCJĘ, istnieje kolejna ścieżka, którą możesz śledzić :) – thmshd