2013-04-09 11 views
5

Ich habe ein Problem beim Versuch, eine GroupBox zu kollabieren. Ich möchte eine GroupBox, die zusammenfällt, wenn alle untergeordneten Elemente ausgeblendet sind.Können Sie die Sichtbarkeit einer GroupBox an die Sichtbarkeit ihrer untergeordneten Elemente binden?

Ich habe es geschafft, dies mit einem Multibinding zu den Eigenschaften zu erreichen, wie unten gezeigt.

Das Problem damit ist, dass wir in der Lage sein wollen, dies mehrmals zu tun und sich nicht darum sorgen, eine Bindung zu verlassen. Also meine Frage: Gibt es irgendeinen Weg dies generisch zu tun, am liebsten in einem Stil? Eine weitere Voraussetzung ist, dass es in XAML nicht Code hinter sein muss.

Also meine ideale Antwort wäre ein Stil, so könnte ich das folgende in meinem XAML.

Ich habe diese Fragen angeschaut und sie führen mich zu der Annahme, dass dies nicht möglich ist; binding in controltemplate, stackpanel visibility, border visibility.

Es tut uns leid, wenn dies zuvor beantwortet wurde. Vielen Dank im Voraus für alle Antworten/Kommentare.

Antwort

4

Sie einen MultiDataTrigger verwenden könnte die GroupBox zusammenzubrechen, wenn die Kinder

Hier ist ein funktionierendes Beispiel kollabiert sind:

<StackPanel> 
    <GroupBox> 
     <GroupBox.Header> 
      <Label Content="GroupBox"/> 
     </GroupBox.Header> 
     <StackPanel> 
      <Label x:Name="lbl_a" Content="A" Visibility="{Binding IsChecked, ElementName=chk_a, Converter={StaticResource boolToVis}}" /> 
      <Label x:Name="lbl_b" Content="B" Visibility="{Binding IsChecked, ElementName=chk_b, Converter={StaticResource boolToVis}}" /> 
     </StackPanel> 
     <GroupBox.Style> 
      <Style TargetType="GroupBox"> 
       <Style.Triggers> 
        <MultiDataTrigger> 
         <MultiDataTrigger.Conditions> 
          <Condition Binding="{Binding Visibility, ElementName=lbl_a}" Value="Collapsed" /> 
          <Condition Binding="{Binding Visibility, ElementName=lbl_b}" Value="Collapsed" /> 
         </MultiDataTrigger.Conditions> 
         <MultiDataTrigger.Setters> 
          <Setter Property="GroupBox.Visibility" Value="Collapsed" /> 
         </MultiDataTrigger.Setters> 
        </MultiDataTrigger> 
       </Style.Triggers> 
      </Style> 
     </GroupBox.Style> 
    </GroupBox> 

    <CheckBox x:Name="chk_a" Content="A Visible" Grid.Column="0" Grid.Row="1" /> 
    <CheckBox x:Name="chk_b" Content="B Visible" Grid.Column="1" Grid.Row="1" /> 

</StackPanel> 
+0

Aber wenn ich dann eine andere GroupBox erstellen oder ein anderes hinzufügen will, muss ich nicht jedes Mal die Bedingungen hinzufügen? Dies wäre das gleiche Problem wie bei der MultiBinding – davidcorne

0

Es gibt zwei Ansätze, die beide mit angebautem Verhalten: Die erste ist zu Legen Sie eine angehängte Eigenschaft für die übergeordnete GroupBox und die OnPropertyChanged-Callback-Schleife für alle untergeordneten Elemente fest, und fügen Sie einer Multibinding-Komponente eine Bindung hinzu, die dann an die GroupBox Visibility-Eigenschaft angehängt wird. Das Problem bei diesem Ansatz besteht darin, dass Sie die Art (n) der untergeordneten Elemente angeben müssen, die Sie in das Multibinding einschließen möchten (weil Sie sie finden müssen, um sie der Gruppe hinzuzufügen, die den Status des übergeordneten Elements vorschreibt). FindVisualChildren müssen mit mehreren generischen Typen genannt werden, wenn Sie alles erfassen möchten Sie möchten es ... leicht obwohl getan:

public sealed class GroupBoxCloseBehavior : DependencyObject 
{ 
    public static readonly DependencyProperty IsEnabledProperty = DependencyProperty.RegisterAttached("IsEnabled", typeof(bool), typeof(GroupBoxCloseBehavior), new PropertyMetadata(false, OnIsEnabledChanged)); 

    public static bool GetIsEnabled(DependencyObject obj) 
    { 
     return (bool)obj.GetValue(IsEnabledProperty); 
    } 

    public static void SetIsEnabled(DependencyObject obj, bool value) 
    { 
     obj.SetValue(IsEnabledProperty, value); 
    } 

    private static void OnIsEnabledChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) 
    { 
     GroupBox parent = obj as GroupBox; 
     if (parent == null) 
     { 
      return;//Do nothing, or throw an exception depending on your preference 
     } 

     if (parent.IsLoaded) 
     { 

      MultiBinding mb = new MultiBinding(); 
      mb.Converter = new MultiVisibilityToVisibilityConverter(); 
      if ((bool)e.NewValue) 
      { 
       foreach (CheckBox child in FindVisualChildren<CheckBox>(parent)) 
       { 
        mb.Bindings.Add(new Binding("Visibility") { Mode = BindingMode.OneWay, Source = child }); 
       } 
       BindingOperations.SetBinding(parent, UIElement.VisibilityProperty, mb); 
      } 
      else 
      { 
       BindingOperations.ClearBinding(parent, UIElement.VisibilityProperty); 
      } 
     } 
     else 
     { 
      parent.Loaded += (sender, eventArgs) => 
      { 
       MultiBinding mb = new MultiBinding(); 
       mb.Converter = new MultiVisibilityToVisibilityConverter(); 
       if ((bool)e.NewValue) 
       { 
        foreach (CheckBox child in FindVisualChildren<CheckBox>(parent)) 
        { 
         mb.Bindings.Add(new Binding("Visibility") { Mode = BindingMode.OneWay, Source = child }); 
        } 
        BindingOperations.SetBinding(parent, UIElement.VisibilityProperty, mb); 
       } 
       else 
       { 
        BindingOperations.ClearBinding(parent, UIElement.VisibilityProperty); 
       } 
      }; 
     } 
    } 

    private sealed class MultiVisibilityToVisibilityConverter : IMultiValueConverter 
    { 
     public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
     { 
      return values.OfType<Visibility>().Any(vis => vis != Visibility.Collapsed) ? Visibility.Visible : Visibility.Collapsed; 
     } 

     public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) 
     { 
      throw new NotSupportedException(); 
     } 
    } 

    public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject 
    { 
     if (depObj != null) 
     { 
      for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++) 
      { 
       DependencyObject child = VisualTreeHelper.GetChild(depObj, i); 
       if (child != null && child is T) 
       { 
        yield return (T)child; 
       } 

       foreach (T childOfChild in FindVisualChildren<T>(child)) 
       { 
        yield return childOfChild; 
       } 
      } 
     } 
    } 
} 

<StackPanel> 
    <GroupBox Header="GroupBox" cl2:GroupBoxCloseBehavior.IsEnabled="True"> 
     <StackPanel> 
      <CheckBox x:Name="CheckOne" Content="CheckBox One"/> 
      <CheckBox x:Name="CheckTwo" Content="CheckBox Two"/> 
     </StackPanel> 
    </GroupBox> 
    <StackPanel> 
     <Button Content="Hide One" Click="Button_Click_1"/> 
     <Button Content="Hide Two" Click="Button_Click_2"/> 
    </StackPanel> 
</StackPanel> 

tun dies in die andere Richtung, eine angeschlossene Eigenschaft auf die untergeordneten Elemente setzen und der OnPropertyChanged, der den Baum hinaufgeht, um nach einer übergeordneten GroupBox zu suchen, ist vielleicht besser, aber Sie haben den Ärger, nicht zu wissen, wie viele Elemente es gibt. Dies ist nur eine Einschränkung der Bindung. Zumindest mit der Eigenschaft GroupBox attached können Sie die benötigte Bindung erstellen.

Verwandte Themen