2013-04-09 64 views
5

我有一個問題試圖讓GroupBox崩潰。我想要一個GroupBox,如果它的所有子節點都被摺疊,它將會崩潰。您可以將GroupBox的可見性綁定到它的子級的可見性嗎?

我已經成功地使用多重綁定來實現這個屬性,如下所示。

<StackPanel> 
    <GroupBox> 
     <GroupBox.Visibility> 
     <MultiBinding 
      Converter="{StaticResource multiBoolOrToVis}" 
      ConverterParameter="{x:Static Visibility.Collapsed}" 
     > 
      <Binding Path="a_visible"/> 
      <Binding Path="b_visible"/> 
     </MultiBinding> 
     </GroupBox.Visibility> 
     <GroupBox.Header> 
     <Label Content="GroupBox"/> 
     </GroupBox.Header> 
     <StackPanel> 
     <Label 
      Content="A" 
      Visibility="{Binding Path=a_visible, Converter={StaticResource boolToVis}}" 
     /> 
     <Label 
      Content="B" 
      Visibility="{Binding Path=b_visible, Converter={StaticResource boolToVis}}" 
     /> 
     </StackPanel> 
    </GroupBox> 
    <Grid> 
     <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="*"/> 
     <ColumnDefinition Width="*"/> 
     </Grid.ColumnDefinitions> 
     <CheckBox 
     Content="A Visible" 
     Grid.Column="0" 
     Grid.Row="1" 
     IsChecked="{Binding Path=a_visible, Mode=TwoWay}" 
     /> 
     <CheckBox 
     Content="B Visible" 
     Grid.Column="1" 
     Grid.Row="1" 
     IsChecked="{Binding Path=b_visible, Mode=TwoWay}" 
     /> 
    </Grid> 
    </StackPanel> 

這個問題是我們希望能夠多次執行此操作,而不必擔心會脫離綁定。所以我的問題是有什麼辦法一般這樣做,最好是風格。另一個要求是它必須在xaml後面沒有代碼。

所以我理想的答案是一種風格,所以我可以在我的xaml中以下。

<StackPanel> 
    <GroupBox Style="ChildrenVisibilityStyle"> 
     <GroupBox.Header> 
     <Label Content="GroupBox"/> 
     </GroupBox.Header> 
     <StackPanel> 
     <Label 
      Content="A" 
      Visibility="{Binding Path=a_visible, Converter={StaticResource boolToVis}}" 
     /> 
     <Label 
      Content="B" 
      Visibility="{Binding Path=b_visible, Converter={StaticResource boolToVis}}" 
     /> 
     </StackPanel> 
    </GroupBox> 
    <Grid> 
     <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="*"/> 
     <ColumnDefinition Width="*"/> 
     </Grid.ColumnDefinitions> 
     <CheckBox 
     Content="A Visible" 
     Grid.Column="0" 
     Grid.Row="1" 
     IsChecked="{Binding Path=a_visible, Mode=TwoWay}" 
     /> 
     <CheckBox 
     Content="B Visible" 
     Grid.Column="1" 
     Grid.Row="1" 
     IsChecked="{Binding Path=b_visible, Mode=TwoWay}" 
     /> 
    </Grid> 
    </StackPanel> 

我看過這些問題,他們讓我認爲這是不可能的; binding in controltemplatestackpanel visibilityborder visibility

對不起,如果這之前已經回答。提前感謝任何答覆/評論。

回答

4

你可以使用一個MultiDataTrigger崩潰的GroupBox當孩子被倒塌

這裏是一個工作示例:

<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

但是,如果我想製作另一個GroupBox或添加另一個項目,我不必每次都添加條件嗎?這與MultiBinding的問題是一樣的 – davidcorne 2013-04-09 12:19:50

0

有兩種方法,都與附加的行爲: 首先是在父組GroupBox和OnPropertyChanged回調循環中爲所有子組設置一個附加屬性,並將一個綁定添加到一個多重綁定,然後該組合綁定到GroupBox Visibility屬性。這種方法的問題在於,您必須指定要包含在多重綁定中的子(ren)的類型(因爲您需要將它們添加到指定父級狀態的組中) - FindVisualChildren需要與多個泛型類型被稱爲如果你想捕捉一切你想它...容易做雖然:

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> 

這樣做的其他方式,把一個附加屬性的子元素並且在樹上尋找父組GroupBox的OnPropertyChanged可能會更好,但您不知道有多少元素。這只是綁定的限制。至少通過GroupBox附加屬性,您可以構建您所需的綁定。