2016-11-16 61 views
3

我有一个DataGrid的窗口,我想基于ObservableCollection的内容隐藏某些列,这些列是DataGrid的ItemSource。基于列值隐藏DataGrid列

基于这样一个问题: Conditional element in xaml depending on the binding content

我写了一个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都是空的。我期望这些列隐藏在数据网格中,但它们仍然可见。我向VisablingConverter添加了一个断点,并通过调试器运行它,但看起来并没有被调用。

+1

如果所有项目都是空字符串或null,你喜欢隐藏整列吗?然后你可以绑定到Items(让路径为空)并创建一个MultiValueConverter迭代你的项目。 – WPFGermany

+1

这是因为'DataGridColumn'直接来自'DependencyObject'而不是'FrameworkElement'或'FrameworkContentElement',因此数据上下文不会被继承。检查输出窗口,你应该能够在那里找到一个'System.Windows.Data:Error:2'消息。 – Grx70

+0

[这是一篇很好的文章](https://blogs.msdn.microsoft.com/jaimer/2008/11/22/forwarding-the-datagrids-datacontext-to-its-columns/),附上解释和解决方法确切的问题。 – Grx70

回答

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您不再需要设置Column.Visibility在XAML,因为它发生自动的。

+0

这是非常干净的,我想我会这样做。它也会清理XAML。 –