基于列值隐藏DataGrid列

3

我有一个带有DataGrid的窗口,我想根据ObservableCollection的内容隐藏某些列,而这个ObservableCollection是DataGrid的ItemSource。

基于这个问题: 根据绑定内容在xaml中使用条件元素

我写了一个VisibilityConverter:

 public class StringLengthVisiblityConverter : IValueConverter
{
    public StringLengthVisiblityConverter() { }
    public Object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null || value.ToString().Length == 0)
        {
            return Visibility.Collapsed;
        }
        else
        {
            return Visibility.Visible;
        }
    }

    public Object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

这里是XAML代码:

        <DataGrid.Resources>
            <local:StringLengthVisiblityConverter x:Key="VisConverter"/>
        </DataGrid.Resources>
        <DataGrid.Columns>

            <DataGridTextColumn  Header="Switch Port" Binding="{Binding FCPort}"/>
            <DataGridTextColumn Width="*" Header="WWPN" Binding="{Binding Path=WWPN}" 
                         Visibility="{Binding Path=WWPN, Converter={StaticResource VisConverter}}"/>
            <DataGridTextColumn Header="FCID" Binding="{Binding Path=FCID}"
            Visibility="{Binding Path=FCID, Converter={StaticResource VisConverter}}"/>

        </DataGrid.Columns>
    </DataGrid>

我使用一个类的实例加载了集合,其中WWPN和FCID都是null。我期望这些列在数据网格中被隐藏,但它们仍然可见。我在VisbilityConverter中添加了一个断点,并通过调试器运行它,但看起来它并没有被调用。


1
你是否喜欢在所有项目都是空字符串或null时隐藏整列?那么你可以绑定到Items(让路径为空),并创建一个MultiValueConverter来迭代你的项目。 - WPFGermany
1
这是因为DataGridColumn直接从DependencyObject派生而来,而不是从FrameworkElementFrameworkContentElement派生,因此数据上下文不会被继承。请查看输出窗口,您应该能够在那里找到一个System.Windows.Data: Error: 2的消息。 - Grx70
这是一篇很好的文章,其中解释了您确切问题的解决方法和解决方案。点击此处阅读 - Grx70
@Grx70 - 谢谢,这回答了问题。 - David Green
1个回答

1
你需要检查DataGridTextColumn中的每个值,并相应地设置Column.Visibility。 为了包含从DataGrid推导出来的所有逻辑。
public class MyDataGrid : DataGrid
{
    private void ValidateColumnVisibility()
    {
        if (Items.Count == 0 || Items[0] == CollectionView.NewItemPlaceholder) return;
        var itemClass = Items[0].GetType();
        foreach (var column in Columns)
        {
            if (column.GetType() == typeof(DataGridTextColumn))
            {
                // find the property that this column is bound to
                DataGridBoundColumn boundColumn = column as DataGridBoundColumn;
                Binding binding = boundColumn.Binding as Binding;
                string boundPropertyName = binding.Path.Path;
                var prop = itemClass.GetProperty(boundPropertyName);

                // Validating Column.Visibility when first value is null
                // when all values are null -> Visibility.Collapsed
                // bound value not a string -> Visibility.Visible
                // all bound strings empty  -> Visibility.Collapsed
                if (prop.GetValue(Items[0]) == null)
                {
                    column.Visibility = Visibility.Collapsed;
                    foreach (var item in Items)
                    {
                        if (item != CollectionView.NewItemPlaceholder)
                        {
                            if (prop.GetValue(item) != null)
                            {
                                if (prop.GetValue(item).GetType() != typeof(String))
                                    column.Visibility = Visibility.Visible;
                                else if (String.IsNullOrEmpty(prop.GetValue(item) as String) == false)
                                    column.Visibility = Visibility.Visible;
                            }
                        }
                    }
                }

                // First value not null and all bound strings empty -> Visibility.Collapsed
                else if (prop.GetValue(Items[0]).GetType() == typeof(String))
                {
                    column.Visibility = Visibility.Collapsed;
                    foreach (var item in Items)
                    {
                        if (item != CollectionView.NewItemPlaceholder)
                        {
                            if (String.IsNullOrEmpty(prop.GetValue(item) as String) == false)
                                column.Visibility = Visibility.Visible;
                        }
                    }
                }
            }
        }
    }

    protected override void OnItemsSourceChanged(
        IEnumerable oldValue, IEnumerable newValue)
    {
        base.OnItemsSourceChanged(oldValue, newValue);
        ValidateColumnVisibility();
    }

    protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
    {
        base.OnItemsChanged(e);
        ValidateColumnVisibility();
    }
}

使用MyDataGrid,您不再需要在XAML中设置Column.Visibility,因为它会自动发生。

那非常干净,我认为我会这样做。它也会清理XAML。 - David Green

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接