Pregunta

I creó una ControlTemplate para mi MyControl control personalizado.

deriva MyControl de System.Windows.Controls.Control y define la siguiente public ObservableCollection<MyControl> Children{ get; protected set; } propiedad.

Para visualizar los controles secundarios anidados que estoy usando un ItemsControl (StackPanel) que está rodeado por un GroupBox. Si no hay controles secundarios, quiero ocultar la GroupBox.

Todo funciona bien en el inicio de la aplicación: El cuadro de grupo y los controles secundarios se muestran si la propiedad Niños inicialmente contenía al menos un elemento. En el otro caso se oculta.

El problema comienza cuando el usuario añade un control secundario a una colección vacía. La visibilidad de la GroupBox todavía está contraído. El mismo problema se produce cuando el último control secundario se retira de la colección. El GroupBox es aún visible. Otro síntoma es que el convertidor HideEmptyEnumerationConverter no consigue llamado. Añadir / eliminar los controles secundarios a las obras no colecciones vacías como se esperaba.

mal

¿Cuál es la siguiente vinculante? Obviamente funciona una vez, pero no se actualiza, aunque la colección estoy unión a es de tipo ObservableCollection.

<!-- Converter for hiding empty enumerations -->
<Common:HideEmptyEnumerationConverter x:Key="hideEmptyEnumerationConverter"/>
<!--- ... --->

<ControlTemplate TargetType="{x:Type MyControl}">
  <!-- ... other stuff that works ... -->
  <!-- Child components -->
  <GroupBox Header="Children"
            Visibility="{Binding RelativeSource={RelativeSource TemplatedParent},
              Path=Children, Converter={StaticResource hideEmptyEnumerationConverter}}">
    <ItemsControl ItemsSource="{TemplateBinding Children}"/>
  </GroupBox>
</ControlTemplate>

.

[ValueConversion(typeof (IEnumerable), typeof (Visibility))]
public class HideEmptyEnumerationConverter : IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        int itemCount = ((IEnumerable) value).Cast<object>().Count();
        return itemCount == 0 ? Visibility.Collapsed : Visibility.Visible;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    #endregion
}

Otra cuestión más general: ¿Cómo ustedes fijaciones de depuración? Encontrado este ( http://bea.stollnitz.com/blog/?p=52), pero todavía me resulta muy difícil de hacer.

Me alegro por cualquier ayuda o sugerencia.

¿Fue útil?

Solución

El problema es que su propia propiedad Children nunca cambia, sólo su contenido. Dado que el valor de la propiedad no cambia, no se vuelve a evaluar la unión. Lo que hay que hacer es obligar a la propiedad Count de la colección. La forma más sencilla se puede lograr esto es con un DataTrigger en su plantilla:

<ControlTemplate TargetType="{x:Type MyControl}">
  <!-- ... other stuff that works ... -->
  <!-- Child components -->
  <GroupBox x:Name="gb" Header="Children">
    <ItemsControl ItemsSource="{TemplateBinding Children}"/>
  </GroupBox>
  <ControlTemplate.Triggers>
      <DataTrigger Binding="{Binding Path=Children.Count, RelativeSource={RelativeSource TemplatedParent}}"
                   Value="0">
        <Setter TargetName="gb" Property="Visibility" Value="Collapsed" />
      </DataTrigger>
  </ControlTemplate.Triggers>
</ControlTemplate>

Otros consejos

Es necesario notificar cada vez que el número de elementos en sus cambios de propiedades niños. Puede hacerlo mediante la implementación de la interfaz INotifyPropertyChanged, registro para eventos de recolección CollectionChanged hijos y formar PropertyChanged desde allí.

Ejemplo:

public class MyControl : Control, INotifyPropertyChanged
{
    static MyControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(MyControl), new FrameworkPropertyMetadata(typeof(MyControl)));
    }

    public ObservableCollection<UIElement> Children
    {
        get { return (ObservableCollection<UIElement>)GetValue(ChildrenProperty); }
        set { SetValue(ChildrenProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Children.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ChildrenProperty =
        DependencyProperty.Register("Children", typeof(ObservableCollection<UIElement>), typeof(MyControl), new UIPropertyMetadata(0));

    public MyControl()
    {
        Children = new ObservableCollection<UIElement>();
        Children.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Children_CollectionChanged);
    }

    void Children_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        RaisePropertyChanged("Children");
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public void RaisePropertyChanged(String propertyName)
    {
        PropertyChangedEventHandler temp = PropertyChanged;
        if (temp != null)
        {
            temp(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top