2012-09-17 14 views
9

Ho un controllo personalizzato che è ereditato dal controllo TextBox. Vorrei implementare l'interfaccia INotifyPropertyChanged nel mio controllo personalizzato.InotifyPropertyChanged in UserControl

public class CustomTextBox : TextBox, INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 
    protected void NotifyPropertyChanged(string info) 
    { 
     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs(info)); 
    } 
} 

Il mio problema è quando cerco di sollevato un evento PropertyChanged il gestore di eventi PropertyChanged è sempre nullo.

Chiunque può aiutarmi?

+0

Non funziona come hai fatto tu. Basta creare una classe extra e implementare l'interfaccia di notifica lì e applicare questa classe al DataContext di UserControl. E funzionerà come hai bisogno. –

risposta

12

il gestore di eventi PropertyChanged è sempre nullo.

Questo sarà sempre vero fino a quando qualcosa si abbona all'evento PropertyChanged.

In genere, se si sta eseguendo un controllo personalizzato, tuttavia, non si utilizzerà INotifyPropertyChanged. In questo scenario, avresti invece un Custom Dependency Property. Normalmente, gli oggetti dipendenza (es .: controlli) utilizzano tutti le proprietà di dipendenza e INPC viene utilizzato dalle classi che diventano lo DataContext di questi oggetti. Ciò consente al sistema di binding di funzionare correttamente.

6

Cosa ti aspettavi? L'evento PropertyChanged viene utilizzato dal codice dell'interfaccia utente, ma non in questo senso. I controlli non implementano mai INPC (abbreviazione di INotifyPropertyChanged), sono obbligati a obiettare che hanno implementato INPC. In questo modo alcune proprietà dell'interfaccia utente, ad es. la proprietà Text sul controllo TextBox è associata a una proprietà su tale classe. Questa è la base dell'architettura MVVM.

esempio, si potrebbe scrivere il seguente codice XAML:

<TextBlock x:Name="txtBox" Text="{Binding Title}" /> 

e si imposta il contesto dati per TextBlock (o qualsiasi suo antenato, DataContext si propaga) nel codice nel modo seguente:

txtBox.DataContext = new Movie {Title = "Titanic"}; 

E ora per la classe stessa:

public class Movie : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 
    protected void NotifyPropertyChanged(string info) 
    { 
     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs(info)); 
    } 

    private string _title; 
    public string Title 
    { 
     get { return _title; } 
     set 
     { 
      if (_title == value) return; 

      _title = value; 
      NotifyPropertyChanged("Title"); 
     } 
    } 
} 

ora, ogni volta che si ch Ange la proprietà Title, sia nel codice che tramite altri binding, l'interfaccia utente verrà automaticamente aggiornata. Google for Data Binding e MVVM.

+2

Questo sta aggiornando il controllo ogni volta che i dati cambiano, ma presumo che l'OP stia cercando di implementare il binding bidirezionale in cui l'origine dati viene automaticamente aggiornata da UserControl. Presumibilmente c'è un modo per notificare che il controllo utente ha aggiornato la proprietà, ma non l'ho ancora trovato. – misnomer

1

Fai come ho detto nei commenti. Non funziona come hai fatto tu. Basta creare una classe extra e implementare Notification Interface lì e applicare questa classe allo DataContext dello UserControl. E funzionerà come hai bisogno.

public partial class W3 : UserControl 
    { 
     WeatherViewModel model = new WeatherViewModel(); 

     public W3() 
     { 
      InitializeComponent(); 
      this.DataContext = model; 
     } 

     public void UpdateUI(List<WeatherDetails> data, bool isNextDays) 
     { 
      model.UpdateUI(data, isNextDays); 
     } 
    } 

    class WeatherViewModel : INotifyPropertyChanged 
    {  

     public void UpdateUI(List<WeatherDetails> data, bool isNextDays) 
     { 
      List<WeatherDetails> weatherInfo = data; 
      if (weatherInfo.Count != 0) 
      { 
       CurrentWeather = weatherInfo.First(); 
       if (isNextDays) 
        Forecast = weatherInfo.Skip(1).ToList(); 
      } 
     } 

     private List<WeatherDetails> _forecast = new List<WeatherDetails>(); 

     public List<WeatherDetails> Forecast 
     { 
      get { return _forecast; } 
      set 
      { 
       _forecast = value; 
       OnPropertyChanged("Forecast"); 
      } 
     } 

     private WeatherDetails _currentWeather = new WeatherDetails(); 

     public WeatherDetails CurrentWeather 
     { 
      get { return _currentWeather; } 
      set 
      { 
       _currentWeather = value; 
       OnPropertyChanged("CurrentWeather"); 
      } 
     } 

     public event PropertyChangedEventHandler PropertyChanged; 

     private void OnPropertyChanged(string propertyName) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    }