[C#][XAML] PropertyChanged binnen ViewModel detecteren

Pagina: 1
Acties:

Vraag


Acties:
  • 0 Henk 'm!

  • Sneezydevil
  • Registratie: Januari 2002
  • Laatst online: 29-09 10:22
Ik ben bezig met mijn eerste Universal Windows App en ik moet zeggen dat het even wennen is. De meeste dingen kom ik na een nachtje slapen wel uit, maar nu heb ik iets wat ik niet helemaal begrijp en misschien doe ik het wel helemaal verkeerd, vandaar dat ik jullie raad vraag.

Situatie:

Ik heb een view:


XML:
1
2
<TextBlock Text="{Binding Name}" />
<ToggleSwitch IsOn="{Binding Status, Mode=TwoWay, Converter={StaticResource StatusBoolConverter}}" />


Verder heb ik een ViewModelBase, met onderandere:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected void NotifyPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null)
            {
                PropertyChangedEventArgs args = new PropertyChangedEventArgs(propertyName);

                handler(this, args);
            }
        }
    }


En tot slot heb ik mijn ViewModel met een ObservableCollection (Elk item heeft een id, naam en status), als ik daar iets verander is dit te zien in de UI en als ik iets verander in de UI wordt dat aangepast in de ObservableCollection.

Nu wil ik graag een functie binnen mijn ViewModel triggeren als de status van de ToggleSwitch veranderd. Ik dacht dit met behulp van de volgende code te doen:
C#:
1
2
3
4
            this.PropertyChanged += (sender, args) =>
             {
                 Debug.WriteLine(args.PropertyName);
             };


Maar dat doet helemaal niks zo lijkt het. Zoek ik in de verkeerde richting? Ik wil dus graag weten van welk item in mijn ObservableCollection de status veranderd, zodat ik daarop kan reageren.

Met onderstaande code lukt het me wel te zien of er een item toegevoegd of verwijderd wordt, maar als alleen de status veranderd dan zie je geen replace.
C#:
1
items.CollectionChanged += items_CollectionChanged;

Alle reacties


Acties:
  • 0 Henk 'm!

  • jip_86
  • Registratie: Juli 2004
  • Laatst online: 19:54
Je luistert nu naar gewijzigde properties van je viewmodel terwijl je wilt luisteren naar de gewijzigde properties van je objecten. INotifyPropertyChanged zit dus op het verkeerde object.

Acties:
  • 0 Henk 'm!

  • Killah_Priest
  • Registratie: Augustus 2001
  • Laatst online: 11-10 16:49
Wat ik in een vergelijkbaar geval heb gedaan is de de betreffende actie opgenomen in de Set actie van de betreffende waar het UI element aan gebind is in de viewmodel (dus bij bv een textbox in de set property van het object waar deze aan gebind is : zodra er iets ingevoerd wordt zal de Set aangeroepen worden)
Verdient misschien niet de schoonheidsprijs, werkt echter wel perfect.

[ Voor 34% gewijzigd door Killah_Priest op 08-01-2016 22:13 ]


Acties:
  • 0 Henk 'm!

  • Sneezydevil
  • Registratie: Januari 2002
  • Laatst online: 29-09 10:22
jip_86 schreef op vrijdag 08 januari 2016 @ 21:20:
Je luistert nu naar gewijzigde properties van je viewmodel terwijl je wilt luisteren naar de gewijzigde properties van je objecten. INotifyPropertyChanged zit dus op het verkeerde object.
Wat je daar zegt is eigenlijk wel logisch. Het eerste wat ik geprobeerd heb was dit:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public MyItem Item
{
    get { return item; }
    set
    {
        if (item != null)
            item.PropertyChanged -= OnItemPropertyChanged;

        item = value;

        if (item != null
            item.PropertyChanged += OnItemPropertyChanged;

        NotifyPropertyChanged("Item");
     } 
}


Dat zat dan dichter bij de oplossing dan wat ik hier poste :D . Maar dat werkte niet, dus ben ik gaan klooien.
Killah_Priest schreef op vrijdag 08 januari 2016 @ 22:11:
Wat ik in een vergelijkbaar geval heb gedaan is de de betreffende actie opgenomen in de Set actie van de betreffende waar het UI element aan gebind is in de viewmodel (dus bij bv een textbox in de set property van het object waar deze aan gebind is : zodra er iets ingevoerd wordt zal de Set aangeroepen worden)
Verdient misschien niet de schoonheidsprijs, werkt echter wel perfect.
Ik snap denk ik wat je bedoeld, zoals de code hierboven, maar dan op de status. Op het moment gebruik ik toggled="functie" maar dat vond ik ook niet zo'n mooie oplossing, hoewel het ook werkt.

Acties:
  • 0 Henk 'm!

  • Zeg
  • Registratie: Juli 2012
  • Laatst online: 21-09 16:44

Zeg

In jouw geval is het denk ik handiger om gebruik te maken van DependencyProperties.

Een voorbeeld:

C#:
1
2
3
4
5
6
7
8
9
public static readonly DependencyProperty NameProperty = DependencyProperty.Register(nameof(Name), typeof(string), typeof(ViewModelBase), new PropertyMetadata(this.Name_PropertyChanged));

...

public string Name
{
    get { return <string>this.GetValue(NameProperty); }
    set { this.SetValue<string>(NameProperty, value); }
}


Dan hoef je alleen nog maar de Name_PropertyChanged callback te schrijven die de logica afhandelt bij een wijziging aan de desbetreffende property, bijvoorbeeld het uitvoeren van method X. De XAML blijft overigens hetzelfde, je bindt gewoon de naam van de property.

Overigens, nameof() is sinds C# 6 een handige manier om ook na een rename de desbetreffende definitie mee te nemen.

Het binden van een ObservableCollection<T> werkt vergelijkbaar, je moet dan alleen ook de achterliggende namen van de properties van die collection expliciet benoemen in je view.

[ Voor 9% gewijzigd door Zeg op 08-01-2016 22:48 ]