0

I have below DataGridTextColumn in my datagrid:

<my:DataGridTextColumn Visibility="{Binding Path=DataContext.Filter, Converter={StaticResource ColumnVisibilityConverter}"> 

Filter is a property in view model:

        private EnumStatus filter;
        public EnumStatus Filter
        {
            get { return filter; }
            set
            {
                if (!filter.Equals(value))
                {
                    filter= value;
                    OnPropertyChanged("Filter");
                }
            }
        }

EnumStatus is an enumeration:

public enum EnumEstatRemesa 
{        
    Pending,
    Approved,
    Reviewing
};

Converter:

public class ColumnVisibilityConverter: IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        EnumStatus status = (EnumStatus)value;

        return (status == EnumStatus.Pending) ? Visibility.Visible : Visibility.Collapsed;
    }

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

Creating resource in window:

<Window.Resources>
    <ColumnVisibilityConverter x:Key="ColumnVisibilityConverter"/>
</Window.Resources>

My problem here is that converter is never called. Why?

When debugging, output window says:

System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=DataContext.Filter; DataItem=null; target element is 'DataGridTextColumn' (HashCode=20546761); target property is 'Visibility' (type 'Visibility')

Willy
  • 9,848
  • 22
  • 141
  • 284
  • 2
    What is `DataContext.Filter` ? Check "Output" window for binding errors. Converter is only called if binding to source is successful. – Sinatr Jan 15 '18 at 14:46
  • A number of non-related thoughts: Are you sure that Filter is definitely changing, and reporting its change? It might be worth specifying explicitly the binding Mode=OneWay. Are there any errors relating to the binding in the output window? Have you tried running up SnoopWPF to inspect the binding for errors at runtime? – LordWilmore Jan 15 '18 at 14:47
  • @Sinatr It shows an error in output window when debugging. See update. – Willy Jan 15 '18 at 14:59
  • @LordWilmore Yes, Filter property is changing and reporting change with INotifyPropertyChanged. Output window is showing an error. See update. – Willy Jan 15 '18 at 15:01
  • The property is "Filter" Yet the Enumeration and Raised property name is "FiltreEstatRemesa". That can not work. There is Syntax to have the Compiler fill in the property name since C#5 or so. I sugest you use it. It is specifically there so refactoring of the Property value does not cause any such issues. – Christopher Jan 15 '18 at 15:04
  • `"FiltreEstatRemesa"`? Shouldn't it rather be `nameof(Filter)`? And it seems you only miss `RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}` part to bind to `DataGrid`'s viewmodel. – Sinatr Jan 15 '18 at 15:05
  • It's looking for the Filter property on the DataGridTextColumn, so the datacontext is wrong. Search this site for how to bind to the datacontext of another element - there is loads of advice on this – LordWilmore Jan 15 '18 at 15:05
  • 2
    DataGridColumns aren't actually in the visual tree so binding doesn't work as normal: https://stackoverflow.com/questions/22073740/binding-visibility-for-datagridcolumn-in-wpf – Dave M Jan 15 '18 at 15:07
  • @Christopher it was a typo. Corrected. Sorry. – Willy Jan 15 '18 at 15:10
  • @LordWilmore which site? link missed? – Willy Jan 15 '18 at 15:41
  • 1
    @DaveM Yes, applying the solution you suggested is working! Also I had seen this site: https://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/ – Willy Jan 15 '18 at 15:41
  • @user1624552 I meant this site, stackoverflow – LordWilmore Jan 15 '18 at 19:59

1 Answers1

2

I see several problems here:

  1. Binding expression

Remove "DataContext." string in the Binding expression.

The default behaviour of the binding extension is to always go to the data context. (Which contains the view model)

  1. DataContext null

The second thing which is stated by the error message you postet is that dataitem is null. It seems you dont have assigned a datacontext. somewhere in the code behind you should - for example - have something like

this.DataContext = new MyViewModel();
  1. Columns dont have datacontext

The DataGridColumns are not in the VisualTree so they don't get the datacontext from the parent DataGrid. Keep in mind that columns do not have a Element-View Model assigned. They exist independendly of the existance of Items bound to ItemsSource property.

So your binding should look something like:

{Binding DataContext.FilterViewModel[MyCol].Filter,Mode=FindAncestor, AncestorType=DataGrid}

The part 'FilterViewModel[MyCol]' depends on how your view model looks like.

Note you need to give 'DataContext' here as the Binding source will be the DataGrid and the viewmodel is accessable via the DataContext property of the DataGrid. This is a case where you need to give 'DataContext' in the binding explictely.

  1. Intention

It is not so clear in your question what your intention is. However, if your intention is to hide certain rows of the datagrid: This does not work via the ColumnVisibility at all. (It seems you want to filter rows with a certain ApporvalStatus)

charly_b
  • 69
  • 10
  • 1
    I like the "4. Intention" part :) – grek40 Jan 15 '18 at 15:58
  • Well my intention is to make collapsed or visible the column depending on the value of the view model Filter property. I solved by applying DaveM solution, also explained here: https://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/ – Willy Jan 15 '18 at 16:03
  • Ah ok . Then ignore 4. ;-) – charly_b Jan 15 '18 at 17:25