Question

Je créé un ControlTemplate pour mon MyControl de contrôle personnalisé.

dérive de MyControl de System.Windows.Controls.Control et définit la public ObservableCollection<MyControl> Children{ get; protected set; } de propriété suivante.

Pour afficher les contrôles enfants imbriqués J'utilise un ItemsControl (StackPanel) qui est entouré d'un GroupBox. S'il n'y a pas de contrôle de l'enfant, je veux cacher la GroupBox.

Tout fonctionne bien au démarrage de l'application: La zone de groupe et contrôles enfants sont indiqués si la propriété des enfants contenait initialement au moins un élément. Dans l'autre cas, il est caché.

Le problème commence lorsque l'utilisateur ajoute un contrôle enfant à une collection vide. La visibilité du GroupBox est encore effondré. Le même problème se produit lorsque le dernier contrôle enfant est supprimé de la collection. Le GroupBox est encore visible. Un autre symptôme est que le convertisseur HideEmptyEnumerationConverter ne soit pas appelé. Ajout / suppression du contrôle des enfants aux travaux non collections vides comme prévu.

Quel est le problème avec les éléments suivants de liaison? Il est évident que cela fonctionne une fois, mais ne soit pas mis à jour, même si la collection que je suis se liant à est de type 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
}

Une autre question plus générale: Comment trouvez-vous les gars consolidations débogage? Nous avons trouvé cet ( http://bea.stollnitz.com/blog/?p=52) mais je trouve qu'il est très difficile de le faire.

Je suis heureux pour toute aide ou suggestion.

Était-ce utile?

La solution

Le problème est que votre propriété Children lui-même ne change jamais, juste son contenu. Étant donné que la valeur de la propriété ne change pas, la liaison ne sont pas réévaluées. Ce que vous devez faire est de se lier à la propriété Count de la collection. La meilleure façon que vous pouvez y parvenir est avec un DataTrigger dans votre modèle:

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

Autres conseils

Vous devez informer chaque fois que le nombre d'éléments dans vos changements de propriété enfants. Vous pouvez le faire en mettant en œuvre l'interface INotifyPropertyChanged, inscrivez-vous à l'événement CollectionChanged de collection Enfants et augmentation PropertyChanged à partir de là.

Exemple:

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));
        }
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top