在XAML中隐藏没有可见项的WPF组合框

本文关键字:WPF 组合 XAML 隐藏 | 更新日期: 2023-09-27 18:19:22

是否有一个纯XAML的方式来隐藏组合框,当它的所有项目被折叠?

例如,我有一个组合框:
<ComboBox ItemsSource="{Binding Persons}">
    <ComboBox.ItemContainerStyle>
        <Style TargetType="{x:Type ComboBoxItem}">
            <Setter Property="Visibility" Value="{Binding IsAlive, Converter={StaticResource BoolToVis}}" />
        </Style>
    </ComboBox.ItemContainerStyle>
</ComboBox>

预期行为:如果所有人都死了,组合框不可见,但如果至少有一个人活着,组合框可见(并且只显示活着的人)

我已经在代码中使用CollectionViewSource, FilterCollectionViewSource.View中应用过滤器后的元素计数实现了这种行为,但我更喜欢在没有代码的情况下仅在XAML中实现。

编辑:

我需要一个通用的解决方案,可用在所有的组合框作为样式的一部分,而不是分配与Person类型或IsAlive属性…因此,解决方案应该只依赖于包含项的可见性属性

在XAML中隐藏没有可见项的WPF组合框

如果items属性为null、空或者里面的所有项都不可见(visibility . collapse)

创建一个新的类ComboBoxExt(或任何你想叫它),然后添加一个附加的属性。(提示:你可以在visual studio中输入"propa",然后tab两次,它会给你一个附加属性的模板)

public class ComboBoxExt
  {
    public static bool GetHideOnEmpty(DependencyObject obj)
    {
      return (bool)obj.GetValue(HideOnEmptyProperty);
    }
    public static void SetHideOnEmpty(DependencyObject obj, bool value)
    {
      obj.SetValue(HideOnEmptyProperty, value);
    }
    public static readonly DependencyProperty HideOnEmptyProperty =
        DependencyProperty.RegisterAttached("HideOnEmpty", typeof(bool), typeof(ComboBoxExt), new UIPropertyMetadata(false, HideOnEmptyChanged));
    private static void HideOnEmptyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
      var cbox = d as ComboBox;
      if (cbox == null)
        return;
      HideComboBox(cbox, (bool)e.NewValue);
    }
    //This is where we check if all the items are not visible
    static void HideComboBox(ComboBox cbox, bool val)
    {
      //First, we have to know if the HideOnEmpty property is set to true. 
      if (val)
      {
        //Check if the combobox is either null or empty
        if (cbox.Items == null || cbox.Items.Count < 1)
          cbox.Visibility = Visibility.Collapsed; //Hide the combobox
        else
        {
          bool hide = true;
          //Check if all the items are not visible.  
          foreach (ComboBoxItem i in cbox.Items)
          {
            if (i.Visibility == Visibility.Visible)
            {
              hide = false;
              break;
            }
          }
          //If one or more items above is visible we won't hide the combobox.
          if (!hide)
            cbox.Visibility = Visibility.Visible;
          else
            cbox.Visibility = Visibility.Collapsed;
        }
      }
    }
  }

现在您可以在任何您想要的组合框中重用附加的属性。你只需要设置HideOnEmpty为true。

<ComboBox local:ComboBoxExt.HideOnEmpty="True"/>

有了这个解决方案,你就不会有一个代码后面,你可以重用附加的属性,HideOnEmpty,在每一个你想要的组合框。

您的'过滤'组合框项目的方法是不正确的,并且非常不高效[1]。您应该使用CollectionView/CollectionViewSource来过滤Persons集合,而不是在ItemContainerStyle中分配可见性。一旦实现了这一点,您就可以在使用绑定的CollectionView.IsEmpty属性的ComboBox.Visibility属性中使用一个简单的绑定和转换器。

[1]关于性能:目前每个Person对象将创建一个容器之前,可见性绑定将被评估。