L'implementazione di INotifyPropertyChanged su un controllo personalizzato è una cattiva pratica?

3

Immagina che venga creato Control .

Ha un po 'di DependencyProperties e ci sono alcune proprietà che dipendono dal DependencyProperties , ma non ha bisogno di essere visto o aggiornato dall'esterno.

Ad esempio : Foo è un DependencyProperty (che può essere sia letto che scritto dall'esterno) e Bar è una proprietà comune che verrà aggiornata quando ( e solo quando ) Foo cambia.

public class MyControl : Control
{
    private static DependencyProperty FooProperty = 
        DependencyProperty.Register("Foo", 
                                    typeof(int), 
                                    typeof(MyControl), 
                                    new PropertyMetadata(FooChanged));

    private static void FooChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        MyControl changedObject = d as MyControl;

        changedObject.Bar++;
    }

    // The dependency property
    public int Foo { get; set; }

    // The property that is changed (only) when the dependency property changes
    public int Bar { get; private set; }
}

Tuttavia, il valore di Bar viene visualizzato sullo schermo (viene stabilita una Binding nel modello del controllo). Ma poiché Bar è not a DependencyProperty non viene inviata alcuna notifica per dire che il suo valore è cambiato.

Vedo due opzioni per risolvere questo problema (ma sono aperto ai suggerimenti).

  1. Rendi il mio Control implementa INotifyPropertyChanged

o

  1. Crea Bar a sola lettura DependencyProperty

Quali sono i pro e i contro di ciascun approccio? Come dovrei proceid?

È una cattiva pratica implementare INotifyPropertyChanged su Control ?

@EDIT

Questa domanda è stata sollevata durante la creazione di un controllo che filtra e visualizza una raccolta di giochi.

I dati di questa collezione sono "costanti" (i giochi sono caricati con l'app e non cambiano alla fine dell'esecuzione). Tuttavia, l'utente può applicare i filtri a questa raccolta (ad esempio, solo visualizzando i giochi che sono in inglese)

Come puoi immaginare, i filtri sono Dependency Properties , mentre la collezione di giochi è una proprietà semplice, che non ero sicuro di dover trasformare in'DependencyProperty' (dato che sarebbe sempre lo stesso, filtrato solo in base al ComboBoxes )

    
posta appa yip yip 31.12.2017 - 22:00
fonte

3 risposte

1

La tua modifica sembra cambiare la prospettiva delle cose. La linea di fondo è che se vuoi che l'IU reagisca ai cambiamenti nel tuo controllo, devi dire che le cose sono cambiate. Sulla base di alcuni anni di lavoro su WPF, ho sviluppato alcune linee guida:

Collezioni

Usa ObservableCollection come tipo. Comunicano l'interfaccia utente quando i valori vengono aggiunti e rimossi.

Le proprietà di sola lettura possono essere proprietà semplici:

public ObservableCollection Games { get; }

Altrimenti usa DependencyProperty e ObservableCollection insieme

public static DependencyProperty GamesProperty = DependencyProperty.Register(...);

public ObservableCollection Games
{
    get { return GetValue(GamesProperty) as ObservableCollection; }
    set { SetValue(GamesProperty, value); }
}

Proprietà su DependencyObjects (include i controlli)

Non associare mai a una proprietà semplice. Ci sono vecchi bug in WPF che non sono stati risolti che causano perdite di memoria in questo caso. Crea tutto a DependencyProperty .

DependencyObjects ha il proprio set di regole, quindi qualsiasi proprietà utilizzata nell'interazione deve essere effettivamente un DependencyProperty . È un dolore nel sedere, ma ti farà risparmiare mal di testa più tardi.

Proprietà su Models / ViewModels

Tutto ciò che intendi aggiornare sullo schermo deve implementare INotifyPropertyChanged . Queste proprietà non hanno la stessa perdita di memoria di una semplice proprietà.

( Ulteriori informazioni )

    
risposta data 09.01.2018 - 20:31
fonte
4

Un controllo è la parte Visualizza della M V VM. Quello che stai aggiornando in una vista è un'informazione stupida (anche se hai un controllo complesso).

Generalmente, quando si crea un controllo è perché:

  • Devi rendere molti elementi con poche informazioni sul modello, rende la tua vista principale gonfia e non puoi trovare le informazioni del modello che stai utilizzando per quella vista principale.
  • Vuoi riutilizzare alcuni elementi che si trovano insieme più di una volta. Forse è un titolo in cui si trova il nome dell'utente in un luogo e in un nome di categoria in un altro luogo.

In tal modo, il controllo deve essere agnostico su quando la proprietà del modello cambia. Quello che stai cercando è ProprietàDipendenza .

Al contrario, il INotifyPropertyChanged deve essere utilizzato nella parte ViewModel di MV VM perché è colui che sa quando:

  • Le informazioni sull'attività commerciale (ad esempio il nome dell'utente) sono cambiate nel Modello.
  • Le informazioni stupide (ovvero il testo) vengono modificate nella vista.
risposta data 03.01.2018 - 01:45
fonte
1

What are the pros and cons of each approach? How should I proceid?

1 - Fai in modo che il mio controllo implementa INotifyPropertyChanged

INotifyPropertyChanged non è una parte specifica di WPF. Pertanto, se si desidera una funzionalità di pubblicazione / sottoscrizione semplice, questa interfaccia è un metodo valido e standard fornito da .NET Framework.

2: imposta una proprietà di dipendenza in sola lettura

A mio avviso, vuoi solo che la proprietà Bar sia "pubblicata" per il client (nel tuo caso il modello di controllo) per aggiornarsi. Pertanto, in questo caso non è necessaria una proprietà DependencyProperty, perché non si desidera associarlo a qualcos'altro come uno stile, un modello o un'altra variabile di runtime.

In questo caso, funzionerebbe, ma sembra una soluzione alternativa (perché stai implementando nel controllo) per realizzare la tua funzione.

3 - Un'altra opzione

Non sono sicuro che sia applicabile perché il tuo esempio è troppo generico, ma ti suggerisco una terza opzione:

  • Rendi il tuo controllo il più stupido possibile
  • Crea Foo e Bar DependencyProperties;
  • Crea un ViewModel come DataContext sul tuo controllo
  • Fornisci i valori per Foo e Bar facendo in modo che ViewModel implementi l'interfaccia INotifyPropertyChanged
risposta data 03.01.2018 - 18:46
fonte

Leggi altre domande sui tag