2013-04-09 63 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附加属性,您可以构建您所需的绑定。