WPF DataGridTemplateColumn Binding Visibility под MVVM - PullRequest
2 голосов
/ 17 марта 2011

У меня есть DataGrid, связанный с ICollectionView в моей ViewModel.DataGrid находится внутри UserControl, который используется в нескольких различных сценариях данных, некоторые из которых требуют определенных столбцов DataGrid, а другие нет.

Я просто хочу связать свойство Visibility объекта DataGridTemplateColumn со свойством 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>

Есть предложения?

Ответы [ 5 ]

4 голосов
/ 17 марта 2011

Я где-то читал о переполнении стека (не могу найти точную запись), что 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 голосов
/ 17 января 2012

Чтобы использовать RelativeSource.Self в качестве привязки RelativeSource для DataGridTemplateColumn - необходимо добавить DataGridContextHelper в ваше приложение.Это все еще требуется для таблицы данных WPF 4.

<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> 
1 голос
/ 17 марта 2011

Этого лучше достичь, если использовать свойство Groups в ViewModel;поскольку в конечном итоге это то, что 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 голосов
/ 09 ноября 2016

Сто благодаря SliverNinja и этой статье DataGridContextHelper . Ссылки на исходный код уже не работают и не могут быть загружены, поэтому я написал свой собственный Attached Proeprty, чтобы он работал во всех возможных случаях (DataContext изменен, значение Присоединенного свойства изменено, добавлен столбец)

Мое приложение использует 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}}"/>

Важно использовать Path = DataContext.MyProp и RelativeSource Self

Единственное, что мне не нравится в текущей реализации - для обработки события DataGrid.Columns.CollectionChanged я создаю экземпляр моего класса и не сохраняю ссылку на него. Таким образом, теоретически GC может убить его за определенное время, не зная, как правильно обращаться с ним в данный момент, подумает об этом и обновит мой пост позже. Любые идеи и критика приветствуются.

0 голосов
/ 17 марта 2011

Вы не можете сделать это.Привязка / разрешение имен не работает таким образом.Почему бы вместо StringToVisibilityConverter создать CollectionToVisibilityConverter, который проверяет источник данных (возможно, передает столбец / свойство для проверки), проверяет, является ли этот столбец / свойство полностью пустым, а затем преобразует его в видимость

...