Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[WPF/XAML] MVVM:Binding afhankelijk van een ander viewmodel

Pagina: 1
Acties:

  • NinjaTuna
  • Registratie: Mei 2011
  • Laatst online: 14:09
Devvers, ik zit met het volgende:

In een window heb ik twee ListViews zitten, met elk hun eigen Viewmodel (AListViewModel en BListViewModel) als datacontext en bijbehorende ObservableCollection als ItemsSource. Deze ObservableCollections bevatten dan weer ViewModels voor de omvatte items (AViewModel en BViewModel)

Nu zit er in elk ListViewItem van A (via een itemtemplate) een checkbox met een Binding voor IsChecked naar een bool property in AViewModel. Deze property is afhankelijk van een property in BViewModel (SelectedItem in lijst B om precies te zijn).

Het probleem is dat de IsChecked property niet geüpdatet wordt wanneer SelectedItem in lijst B verandert en de checkboxes in lijst A dus gewoon gelijk blijven.

Heeft iemand een idee hoe ik dit netjes oplos?

PS: ik zou me voor kunnen stellen dat bovenstaande structuur niet meteen helder is, mocht dit zo zijn dan zal ik een poging doen het te verduidelijken

  • CM5
  • Registratie: Maart 2003
  • Niet online

CM5

Ik heb je situatie niet helemaal helder, maar misschien kom je met de volgende manier verder. Je kunt een extende ObservableCollection maken, waarbij het CollectionChanged event geraised word bij het veranderen van een property:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class TrulyObservableCollection<T> : ObservableCollection<T>
where T : INotifyPropertyChanged
{
    public TrulyObservableCollection()
        : base()
    {
        CollectionChanged += new NotifyCollectionChangedEventHandler(TrulyObservableCollection_CollectionChanged);
    }

    void TrulyObservableCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.NewItems != null)
        {
            foreach (Object item in e.NewItems)
            {
                (item as INotifyPropertyChanged).PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
            }
        }
        if (e.OldItems != null)
        {
            foreach (Object item in e.OldItems)
            {
                (item as INotifyPropertyChanged).PropertyChanged -= new PropertyChangedEventHandler(item_PropertyChanged);
            }
        }
    }

    void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        NotifyCollectionChangedEventArgs a = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
        OnCollectionChanged(a);
    }
}


zie: StackOverflow

  • NinjaTuna
  • Registratie: Mei 2011
  • Laatst online: 14:09
Bedankt voor je antwoord, ik denk alleen niet dat het een oplossing is voor mijn probleem.

Ik heb een viewmodel class voor lijst A, met een property voor SelectedItem:
C#:
1
2
3
4
5
6
7
8
9
public object SelectedItem
{
    get { return _selectedItem; }
    set 
    {
        _selectedItem = value;
        RaisePropertyChanged("SelectedItem"); //Vuurt een PropertyChanged-event
    }
}


Deze property verandert dus wanneer de gebruiker op een ander item klikt.
Dan heb ik een viewmodel class voor object B (eigenlijk ook een lijst maar een enkel object is wellicht even wat eenvoudiger), met daarin een property IsChecked, welke afhankelijk is van SelectedItem in viewmodel A. Het idee is dat het property IsChecked in viewmodel B zichzelf update (en de binding in XAML dus ook), wanneer property SelectedItem in viewmodel A verandert.

Ik heb dit nu voor elkaar met een naar mijn idee lelijke hack: een aanroep, vanuit de setter van property SelectedItem, naar een functie in viewmodel B die een event vuurt dat IsChecked is veranderd, zodat de binding zichzelf updatet:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//In viewmodel A
public object SelectedItem
{
    get { return _selectedItem; }
    set 
    {
        _selectedItem = value;
        RaisePropertyChanged("SelectedItem"); //Vuurt een PropertyChanged-event
        ViewModelB.UpdateIsChecked();
    }
}

//In viewmodel B
public void UpdateIsChecked()
{
    RaisePropertyChanged("IsChecked");
}

Dit zou toch beter moeten kunnen heb ik het idee...
Ik maak overigens gebruikt van NuGet package MVVM Light

  • Fexxman
  • Registratie: November 2010
  • Niet online
Ik zou dit anders doen, namelijk niet twee keer dezelfde selecteditem maken maar juist een nieuwe ViewModel die dit doet. Bijvoorbeeld als een GlobalVM. Als je dit niet nodig vind dat kun je ook de selecteditem van listbox B verwijzer naar de property in viewmodel A. Dit kan met de path van de binding. "{Binding SelectedModel, path={StaticResource VMA}}". Wat ik ook zou overwegen is 1 VM waar de andere twee VM's als property inzitten:

code:
1
2
3
4
5
6
7
class VM
{
   prop ViewModelA VMA;
   prop ViewModelB VMB;

  prop Model SelectedModel;
}


En dan je itemssource binden als "{Binding VMA.ItemsX}" en "{Binding VMB.ItemsY}". De SelectedItem properties bind je dan simpelweg als "{Binding SelectedModel}"

ps laatste tip. Gebruik geen MVVMLight maar programmeer het zelf. Hiermee wordt het een stuk logischer en gemakkelijker. Ik snap MVVM en heb de frameworks nooit nodig gehad. Soms is een convertertje handig maar die snag je zo van StackOverflow.

[ Voor 34% gewijzigd door Fexxman op 03-11-2013 13:33 ]