Search code examples
c#.netwpfdatagridivalueconverter

WPF: passing datagridrow object to converter


I've got a problem with passing object to converter in WPF.

My DataGrid looks like:

<DataGrid x:Name="customTasksDataGrid" Margin="10,10,10,38" Grid.Column="1" IsReadOnly="True" AutoGenerateColumns="False">
    <DataGrid.RowStyle>
        <Style TargetType="DataGridRow">
            <Setter Property="ToolTip">
                <Setter.Value>
                    <TextBlock Text="{Binding Path=., Converter={StaticResource converter}, NotifyOnTargetUpdated=True}"/>
                </Setter.Value>
            </Setter>
        </Style>
    </DataGrid.RowStyle>
    <DataGrid.Columns>
        <DataGridTextColumn Header="ID" Binding="{Binding ID}"/>
        <DataGridTextColumn Header="Klient" Binding="{Binding Client.Names}"/>
        ...
    </DataGrid.Columns>
</DataGrid>

Converter:

public class DateToBrushConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        CustomTask t = (CustomTask)value;
        Console.WriteLine(t.ToString()); // HERE
        ...
    }

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

When running my prog marked line throws error, that my CustomTask t object is null. What am I doing wrong?

EDIT:

As Vadim Martynov suggested I change my converter to:

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
    if (value == null)
        return null;
    CustomTask t = (CustomTask)value;
    ...
}

And it works perfectly now! Thanks


Solution

  • Next code works fine for me:

    <DataGrid.RowStyle>
        <Style TargetType="DataGridRow">
            <Setter Property="ToolTipService.ToolTip" Value="{Binding Path=., Converter={StaticResource converter}}" />
        </Style>
    </DataGrid.RowStyle>
    

    Also I noticed that there is only one call with null value in your code. Next calls (if your binding does not fail) will have not null CustomTask value (when you actually call Tooltip) and will fork fine. Then just add if(t == null) return null; to your converter and everything will work fine.

    public class DateToBrushConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        CustomTask t = (CustomTask)value;
        if(t == null)
            return null;    // or other default value
        ...
    }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    

    I think this the reason of this behavior is that DataGrid renders whole its templates on page render and call tooltip without data and data source. If you set property via my first code example there is nothing to render and converter calls only after Data was binded.

    UPDATE To manipulate isolated column in similar case you can change style or template of this column instead of RowStyle like int the example below:

    <DataGrid x:Name="customTasksDataGrid" ItemsSource="..." IsReadOnly="True" AutoGenerateColumns="False">
        <DataGrid.Columns>
            <DataGridTextColumn Header="ID" Binding="{Binding ID}"/>
            <DataGridTextColumn Header="Klient" Binding="{Binding Name}">
                <DataGridTextColumn.ElementStyle>
                    <Style TargetType="{x:Type TextBlock}">
                        <Setter Property="ToolTipService.ToolTip">
                            <Setter.Value>
                                <TextBlock Text="{Binding Path=., Converter={StaticResource converter}}"/>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </DataGridTextColumn.ElementStyle>
            </DataGridTextColumn>
        </DataGrid.Columns>
    </DataGrid>