2011-03-17 119 views
2

我有一個DataGrid綁定到我的ViewModel中的ICollectionView。 DataGrid位於UserControl中,用於幾種不同的數據場景,其中一些需要某些DataGrid列,而另一些則不需要。MVVM DataGridTemplateColumn MVVM下的可見性綁定

我只想將DataGridTemplateColumn的Visibility屬性綁定到內部標籤的Content屬性,因此如果沒有任何行包含值,它將被隱藏。我有一個String to Visibility轉換器集,但無法弄清楚如何找到內部標籤的Content屬性。

<DataGridTemplateColumn Header="Groups" Width="*" CanUserSort="True" SortMemberPath="Groups" Visibility="{Binding ElementName=lbl, Path=Content, Converter={StaticResource StringToVisibilityConverter}}"> 
    <DataGridTemplateColumn.CellTemplate> 
     <DataTemplate> 
      <Label Name="lbl" Content="{Binding Path=Groups}" /> 
     </DataTemplate> 
    </DataGridTemplateColumn.CellTemplate> 
</DataGridTemplateColumn> 

有什麼建議嗎?

+0

任何正在尋找答案的人,請參閱http:// stackoverflow。com/questions/7955318/bind-datagridtemplatecolumn-visibility – 2015-02-11 15:09:36

回答

1

通過ViewModel上的Groups屬性可以更好地實現;因爲這最終是Label正在使用的。

<DataGridTemplateColumn Header="Groups" Width="*" CanUserSort="True" SortMemberPath="Groups" Visibility="{Binding Groups, Converter={StaticResource SomeConverter}}"> 
    <DataGridTemplateColumn.CellTemplate> 
     <DataTemplate> 
      <Label Name="lbl" Content="{Binding Path=Groups}" /> 
     </DataTemplate> 
    </DataGridTemplateColumn.CellTemplate> 
</DataGridTemplateColumn> 
+0

是的,同樣的。 – Will 2011-03-17 15:53:04

+0

嗨,夥計們,我已經嘗試過,並在運行時得到這個錯誤:System.Windows.Data錯誤:2:無法找到目標元素的治理FrameworkElement或FrameworkContentElement。 BindingExpression:路徑=組;的DataItem = NULL;目標元素是'DataGridTemplateColumn'(HashCode = 38907373);目標屬性是'可見性'(類型'可見性') – Aaron 2011-03-17 16:04:26

+0

令人沮喪的是,當我使用在XAML中定義的CollectionViewSource時,通過將可見性綁定源設置爲ColletionViewSource,這實際上起作用。我不得不將CollectionViewSource移動到ViewModel來處理排序/過濾,並且破壞了這個Visibility綁定。任何其他想法? – Aaron 2011-03-17 16:12:59

0

你不能這樣做。綁定/名稱解析不能以這種方式工作。爲什麼不,StringToVisibilityConverter創建一個CollectionToVisibilityConverter檢查數據源(可能傳入要檢查的列/屬性),查看該列/屬性是否完全爲空,然後將其轉換爲可見性?

4

我在Stack Overflow的某處(無法找到確切的帖子)DataGridColumn沒有分配數據上下文,因爲它們不是FrameworkElement。爲了解決這個問題,我不得不使用代碼類同此:

<DataGridTemplateColumn 
     Header="Groups" 
     Width="*" 
     CanUserSort="True" 
     SortMemberPath="Groups" 
     Visibility"{Binding RelativeSource={x:Static RelativeSource.Self}, 
         Path=(FrameworkElement.DataContext).IsGroupsVisible, 
         Converter={StaticResource booleanToVisiblityConverter}}"> 
     <DataGridTemplateColumn.CellTemplate>   
       <DataTemplate>    
        <Label Name="lbl" Content="{Binding Path=Groups}" />   
       </DataTemplate>  
     </DataGridTemplateColumn.CellTemplate> 
    </DataGridTemplateColumn> 

Where 

<UserControl.Resources> 
    <BooleanToVisibilityConverter x:Key="booleanToVisibilityConverter" /> 
</UserControl.Resources> 
+2

嗨安迪,有趣。現在沒有得到任何綁定錯誤,但它仍然無法正常工作。轉換器甚至沒有被調用... – Aaron 2011-03-17 17:24:48

+0

是在ViewGodel上DataGrid綁定的屬性?或者它是DataGrid中的行綁定到的單個項目的屬性?我認爲它是兩個,因爲你想要顯示單個單元格中的文本,並且網格中的列的可見性只能綁定到一個屬性。 – 2011-03-17 17:36:20

+0

它是一個ObservableCollection中的單個項目的屬性,它被設置爲CollectionViewSource的源,並作爲ICollectionView返回到DataGrid。我也嘗試將它綁定到ViewModel上的一個名爲IsGroupsVisible的屬性上,該屬性不那麼優雅,但它也沒有選擇它。 – Aaron 2011-03-17 17:39:10

2

要使用RelativeSource.Self作爲RelativeSourceDataGridTemplateColumn結合 - 你需要的DataGridContextHelper添加到您的應用程序。對於WPF 4 DataGrid,這仍然是必需的。

<DataGridTemplateColumn 
     Header="Groups" 
     Width="*" 
     CanUserSort="True" 
     SortMemberPath="Groups" 
     Visibility"{Binding RelativeSource={x:Static RelativeSource.Self}, 
         Path=(FrameworkElement.DataContext).IsGroupsVisible, 
         Converter={StaticResource booleanToVisiblityConverter}}"> 
     <DataGridTemplateColumn.CellTemplate>   
       <DataTemplate>    
        <Label Name="lbl" Content="{Binding Path=Groups}" />   
       </DataTemplate>  
     </DataGridTemplateColumn.CellTemplate> 
    </DataGridTemplateColumn> 
0

一百感謝SliverNinja和本文DataGridContextHelper。我的應用程序使用DataGrid和AutoGenerateColumns = False並使用DataGridTemplateColumn,因此在將列添加到網格之前設置了DataContext。

下面是附加屬性類:

public sealed class DataGridColumnDataContextForwardBehavior 
{ 
    private DataGrid dataGrid = null; 

    public DataGridColumnDataContextForwardBehavior(DataGrid dataGrid) 
    { 
     this.dataGrid = dataGrid; 

     dataGrid.Columns.CollectionChanged += DataGridColumns_CollectionChanged; 
    } 

    private void DataGridColumns_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) 
    { 
     var IsDataContextForwardingEnabled = GetIsDataContextForwardingEnabled(dataGrid); 

     if (IsDataContextForwardingEnabled && dataGrid.DataContext != null) 
     { 
      if (e.Action == NotifyCollectionChangedAction.Add) 
      { 
       foreach (DataGridColumn column in e.NewItems) 
       { 
        column.SetValue(FrameworkElement.DataContextProperty, dataGrid.DataContext); 
       } 
      } 
     } 
    } 

    static DataGridColumnDataContextForwardBehavior() 
    { 
     FrameworkElement.DataContextProperty.AddOwner(typeof(DataGridColumn)); 
     FrameworkElement.DataContextProperty.OverrideMetadata(typeof(DataGrid), 
      new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits, new PropertyChangedCallback(OnDataContextChanged))); 
    } 

    public static readonly DependencyProperty IsDataContextForwardingEnabledProperty = 
     DependencyProperty.RegisterAttached("IsDataContextForwardingEnabled", typeof(bool), typeof(DataGridColumnDataContextForwardBehavior), 
      new FrameworkPropertyMetadata(false, OnIsDataContextForwardingEnabledChanged)); 

    public static void OnDataContextChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) 
    { 
     DataGrid dataGrid = obj as DataGrid; 
     if (dataGrid == null) return; 

     var IsDataContextForwardingEnabled = GetIsDataContextForwardingEnabled(dataGrid); 
     if (IsDataContextForwardingEnabled) 
     { 
      foreach (DataGridColumn col in dataGrid.Columns) 
      { 
       col.SetValue(FrameworkElement.DataContextProperty, e.NewValue); 
      } 
     } 
    } 

    static void OnIsDataContextForwardingEnabledChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) 
    { 
     var dataGrid = obj as DataGrid; 
     if (dataGrid == null) return; 

     new DataGridColumnDataContextForwardBehavior(dataGrid); 

     if (!(e.NewValue is bool)) return; 

     if ((bool)e.NewValue && dataGrid.DataContext != null) 
      OnDataContextChanged(obj, new DependencyPropertyChangedEventArgs(FrameworkElement.DataContextProperty, dataGrid.DataContext, dataGrid.DataContext)); 
    } 

    public static bool GetIsDataContextForwardingEnabled(DependencyObject dataGrid) 
    { 
     return (bool)dataGrid.GetValue(IsDataContextForwardingEnabledProperty); 
    } 

    public static void SetIsDataContextForwardingEnabled(DependencyObject dataGrid, bool value) 
    { 
     dataGrid.SetValue(IsDataContextForwardingEnabledProperty, value); 
    } 
} 

另一個非明顯的事情是正確的使用如何爲DataGridTemplateColumn結合:

<DataGrid bhv:DataGridColumnDataContextForwardBehavior.IsDataContextForwardingEnabled="True"> 
<DataGrid.Columns> 
<DataGridTemplateColumn Visibility="{Binding Path=DataContext.Mode, RelativeSource={RelativeSource Self}, Converter={StaticResource SharedFilesModeToVisibilityConverter}, ConverterParameter={x:Static vmsf:SharedFilesMode.SharedOut}}"/> 

它使用路徑是重要= DataContext.MyPropRelativeSource Self

Only thing i不喜歡在當前實現 - 處理DataGrid.Columns.CollectionChanged事件我創建我的類的實例,不保留它的參考。因此理論上GC可能會在這段時間內殺死它,不確定如何在目前正確處理它,將會考慮並稍後更新我的帖子。任何想法和批評都是受歡迎的。