2013-04-09 17 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で次のことができます。

私はこれらの質問を見て、これが可能ではないと思うように導いています。 binding in controltemplate,stackpanel visibility,border visibility

ご迷惑をおかけして申し訳ございません。すべての回答/コメントに感謝します。

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

答えて

4

あなたはGroupBoxを折りたたむにMultiDataTriggerを使用することができ 最初はにあります親GroupBoxおよびOnPropertyChangedコールバックループのすべての子にアタッチされたプロパティを設定し、GroupBindingのVisibilityプロパティにフックされるマルチバインディングにバインディングを追加します。このアプローチの問題点は、マルチバインドに含める子のタイプを指定する必要があることです。親の状態を示すグループに追加する必要があるためです。あなたはすべてのものをキャプチャしたい場合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を探しているTreeを歩いているOnPropertyChangedのほうがいいかもしれませんが、いくつの要素があるか分からないという面倒があります。これはバインディングの単なる制限です。少なくともGroupBox添付プロパティを使用すると、必要なバインドを構築できます。

+0

しかし、別のGroupBoxを作成したり、別のアイテムを追加したい場合、毎回条件を追加する必要はありませんか?これは、MultiBindingと同じ問題です – davidcorne

0

は、添付の行動の両方、二つのアプローチがあります:子供たちはここで

実施例があるが折りたたまれたときに