2010-12-27 11 views
9

Tengo un UserControl con una propiedad ItemsSource. A medida que la clase de control de usuario de base no implementa ItemsSource, tuve que crear mi propia propiedad de dependencia de esta manera:Control de usuario con elementos personalizados Propiedad de dependencia de fuente

#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 

Ahora, en mi modelo de vista que tienen una propiedad de Eventos que es un ICollectionView de artículos EventItem así:

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; 
     } 
    } 

El problema al que me enfrento es que en mi vista, cuando me vinculo a la propiedad Eventos, y agrego un elemento a eventItems, el UserControl no desencadenará el evento ItemsSourceChanged y por lo tanto no actualizará la UI. Con el objetivo de probar agregué un cuadro de lista simple a la vista que también se une a la propiedad de Eventos. Eso funciona como un encanto. Las actualizaciones de eventItems observableCollection se reflejan en el ListBox.

Supongo que tiene algo que ver con mi propiedad de dependencia ItemsSource. Tal vez necesitaría usar un control personalizado que herede el formulario ItemsControl en lugar de un UserControl?

Para ayudarlo a comprender mi problema: Estoy tratando de crear un calendario como control que muestre entradas de eventos/agenda (similar a Google Calendar). Funciona a las mil maravillas. La interfaz de usuario se actualiza cuando se cambia el tamaño del control. Lo único que queda es la actualización automágica una vez que cambie ItemsSource.

Espero que alguien pueda ayudar.

EDITAR: El momento en que publiqué me di cuenta de que el evento no se puede disparar, ya que la propiedad ItemsSource no cambia. Es la colección subyacente que cambia. Sin embargo, no soy cómo manejar eso. ¿Qué debo implementar para que esto funcione? Solo una pista sería suficiente. No necesito todos los detalles de implementación.

Respuesta

6

La apertura de la PresentationFramework.dll dentro del reflector y mirando a System.Windows.Controls.ItemsControl mostraron lo siguiente:

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); 
} 

Sin saber qué RefreshLayout hace mi corazonada es que tiene algo que ver con la forma en que el ObservableCollection<T> está siendo envuelto ya que el código anterior es ajeno a lo que es el tipo de colección de concreto y, por lo tanto, sería manejado por el tipo que se envuelve; en este caso, un ObservableCollection<T> Intente modificar su propiedad como se ve a continuación para devolver la vista predeterminada y ajustar su propiedad ItemsSource para que sea más similar al código anterior del marco y trabaje hacia atrás desde allí.

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

Perdón por la respuesta tardía. Voy a marcar tu respuesta como "Respuesta", ya que parece que es el camino a seguir. Sin embargo, no puedo asegurarlo ya que no lo he probado. De hecho, decidí rediseñar el control de un UserControl a un CustomControl que hereda de ItemsControl y que parece (por ahora) para resolver el problema. –

Cuestiones relacionadas