2010-12-27 17 views
9

Ho un controllo utente con una proprietà ItemsSource. Come la classe di base UserControl non implementa ItemsSource, ho dovuto creare la mia propria proprietà di dipendenza in questo modo:Controllo utente con proprietà di dipendenza ItemsSource personalizzata

#region ItemsSource Dependency Property 
    public static readonly DependencyProperty ItemsSourceProperty = 
     DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(MonthViewControl), 
     new PropertyMetadata(OnItemsSourceChanged)); 

    static void OnItemsSourceChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) 
    { 
     (obj as MonthViewControl).OnItemsSourceChanged(e); 
    } 

    private void OnItemsSourceChanged(DependencyPropertyChangedEventArgs e) 
    { 
     RefreshLayout(); 
    } 

    public IEnumerable ItemsSource 
    { 
     get 
     { 
      return (base.GetValue(ItemsSourceProperty) as IEnumerable); 
     } 
     set 
     { 
      base.SetValue(ItemsSourceProperty, value); 
     } 
    } 

    #endregion 

Ora nel mio ViewModel Ho un immobile Eventi che è un ICollectionView di elementi EventItem in questo modo:

private ObservableCollection<Controls.EventCalendar.EventItem> eventItems; 
    private CollectionViewSource events; 
    public System.ComponentModel.ICollectionView Events 
    { 
     get 
     { 
      if (events == null) 
      { 
       events = new CollectionViewSource(); 
       events.Source = eventItems; 
      } 

      return events.View; 
     } 
    } 

Il problema che sto affrontando è che nella mia vista, quando lego alla proprietà Events e aggiungo un oggetto a eventItems, UserControl non attiverà l'evento ItemsSourceChanged e quindi non aggiornerà l'interfaccia utente. Per motivi di prova ho aggiunto una semplice listbox alla vista che si lega anche alla proprietà Events. Funziona come un fascino. Gli aggiornamenti a eventItems observableCollection si riflettono nel ListBox.

Sto pensando che abbia qualcosa a che fare con la mia proprietà di dipendenza ItemsSource. Forse avrei bisogno di usare un controllo personalizzato che eredita la forma di ItemsControl invece di un UserControl?

Per aiutarti a capire il mio problema: sto cercando di creare un calendario come controllo che mostra eventi/voci di agenda (simile a Google Calendar). Esso funziona magicamente. L'interfaccia utente viene aggiornata quando il controllo viene ridimensionato. L'unica cosa che rimane è l'aggiornamento automatico una volta che l'oggetto ItemsSource cambia.

Spero che qualcuno possa aiutare.

EDIT: Nel momento in cui ho pubblicato mi sono reso conto che l'evento non può essere attivato poiché la proprietà ItemsSource non cambia. È la collezione sottostante che cambia. Tuttavia, non sono come gestirlo. Cosa devo implementare per fare in modo che funzioni. Basterebbe un suggerimento. Non ho bisogno di tutti i dettagli di implementazione.

risposta

6

Apertura del PresentationFramework.dll all'interno del riflettore e guardando System.Windows.Controls.ItemsControl ha mostrato il seguente:

public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(IEnumerable), 
    typeof(ItemsControl), new FrameworkPropertyMetadata(null, 
    new PropertyChangedCallback(ItemsControl.OnItemsSourceChanged))); 

private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
{ 
    ItemsControl control = (ItemsControl) d; 
    IEnumerable oldValue = (IEnumerable) e.OldValue; 
    IEnumerable newValue = (IEnumerable) e.NewValue; 
    ItemValueStorageField.ClearValue(d); 
    if ((e.NewValue == null) && !BindingOperations.IsDataBound(d, ItemsSourceProperty)) 
    { 
     control.Items.ClearItemsSource(); 
    } 
    else 
    { 
     control.Items.SetItemsSource(newValue); 
    } 
    control.OnItemsSourceChanged(oldValue, newValue); 
} 

Non sapendo cosa RefreshLayout fa la mia impressione è che ha qualcosa a che fare con il modo in cui il ObservableCollection<T> viene eseguito il wrapping poiché il codice precedente non è a conoscenza di quale sia il tipo di raccolta concreta e pertanto verrebbe gestito dal tipo in corso di wrapping; in questo caso un Prova a modificare la tua proprietà come mostrato di seguito per restituire la vista predefinita e regola la tua proprietà ItemsSource in modo che sia più simile al codice sopra dal framework e lavori all'indietro da lì.

private ObservableCollection<Controls.EventCalendar.EventItem> eventItems; 
private ICollectionview eventsView; 
public System.ComponentModel.ICollectionView Events 
{ 
    get 
    { 
     if (eventsView == null) 
      eventsView = CollectionViewSource.GetDefaultView(eventItems); 
     return eventsView; 
    } 
} 
+0

Ci scusiamo per la risposta in ritardo. Segnerò la risposta come "Rispondi" in quanto sembra la strada da percorrere. Tuttavia, non posso dire per certo come non l'ho provato. In effetti, ho deciso di ridisegnare il controllo da un UserControl a un CustomControl che eredita da ItemsControl e che sembra (per ora) risolvere il problema. –

Problemi correlati