2016-11-16 78 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。 –