Domanda

ho creato un ControlTemplate per il mio MyControl controllo personalizzato.

deriva da MyControl System.Windows.Controls.Control e definisce la seguente public ObservableCollection<MyControl> Children{ get; protected set; } struttura.

Per visualizzare i controlli figlio nidificati Sto utilizzando un ItemsControl (StackPanel) che è circondato da un GroupBox. Se non ci sono controlli figlio, voglio nascondere il GroupBox.

Tutto funziona bene all'avvio dell'applicazione: La casella di gruppo e controlli figlio vengono visualizzate se la proprietà bambini inizialmente conteneva almeno un elemento. Nell'altro caso è nascosto.

Il problema inizia quando l'utente aggiunge un controllo figlio per un insieme vuoto. la visibilità del GroupBox è ancora crollato. Lo stesso problema si verifica quando l'ultimo controllo figlio viene rimosso dalla collezione. Il GroupBox è ancora visibile. Un altro sintomo è che il convertitore HideEmptyEnumerationConverter non viene chiamato. L'aggiunta / rimozione di controlli figlio di opere non collezioni vuoti come previsto.

sbagliato

Che cosa è con il seguente vincolante? Ovviamente funziona una volta, ma non viene aggiornato, anche se la collezione che sto legame a è di 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
}

Un altro, questione più generale: come si fa a ragazzi attacchi di debug? Ho trovato questo ( http://bea.stollnitz.com/blog/?p=52), ma ancora lo trovo molto difficile da fare.

Sono contento per qualsiasi aiuto o suggerimento.

È stato utile?

Soluzione

Il problema è che la vostra proprietà Children in sé non cambia mai, solo il suo contenuto. Dal momento che il valore della proprietà non cambia, il legame non è rivalutata. Quello che dovete fare è legano alla proprietà Count della collezione. Il modo più semplice è possibile raggiungere questo obiettivo è con un DataTrigger nel modello:

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

Altri suggerimenti

È necessario avvisare ogni volta che il numero di elementi nei vostri bambini modifiche alle proprietà. Si può fare implementando l'interfaccia INotifyPropertyChanged, registrati per evento CollectionChanged di raccolta dei bambini e rilancio PropertyChanged da lì.

Esempio:

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));
        }
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top