我有一个问题试图让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 controltemplate,stackpanel visibility,border visibility。
很抱歉,如果之前已经回答过这个问题。提前感谢您的任何答案/评论。
答案 0 :(得分: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>
答案 1 :(得分: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附加属性,您可以构建所需的绑定。