Search code examples
c#wpfxamlmvvmconverters

WPF Converter not triggered, when updating bound value from a seperate Thread


I have WPF Application that contains a DataGrid, which is bound onto a C# DataTable. It has a converter that changes the background-color of the cell based on the value inside the cell. Under normal use everything works as it's supposed to, but when I update the values of the DataTable from a seperate Thread, the displayed value changes, but the converter isn't triggered.

The DataGrid:

<UserControl.Resources>
    <utility:CellColorConverter x:Key="ColorConverter" />

    <Style x:Key="BlueDataGridStyle" TargetType="{x:Type DataGrid}">
        <Setter Property="CellStyle" Value="{DynamicResource BlueDataGridCellStyle}" />
    </Style>

    <Style x:Key="BlueDataGridCellStyle" TargetType="DataGridCell" >
        <Setter Property="Background">
            <Setter.Value>
                <MultiBinding Converter="{StaticResource ColorConverter}">
                    <MultiBinding.Bindings>
                        <Binding RelativeSource="{RelativeSource Self}" />
                        <Binding Path="Row" />
                    </MultiBinding.Bindings>
                </MultiBinding>
            </Setter.Value>
        </Setter>

        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type DataGridCell}">
                    <Grid Background="{TemplateBinding Background}">
                        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</UserControl.Resources>


<DataGrid
    Name="dgSimple"
    AutoGenerateColumns="True"
    ItemsSource="{Binding Grid}"
    IsReadOnly="True"
    CanUserResizeColumns="False"
    CanUserResizeRows="False"
    CanUserSortColumns="False"
    CanUserReorderColumns="False"
    Margin="6"
    SelectedIndex="{Binding SelectedRow}"
    CurrentColumn="{Binding SelectedColumn}"
    Style="{StaticResource BlueDataGridStyle}"
    HeadersVisibility="All"
    RowHeaderWidth="32"
    ColumnWidth="32">
</DataGrid>

The Converter:

public class CellColorConverter : IMultiValueConverter
{
    object IMultiValueConverter.Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if (values[0] is DataGridCell cell && values[1] is DataRow row)
        {
            try
            {
                string columnName = (string)cell.Column.Header;
                int columnIndex = cell.Column.DisplayIndex;

                if (columnIndex == 0)
                {
                    cell.FontStyle = FontStyles.Italic;
                    cell.FontWeight = FontWeights.Bold;
                    cell.FontSize = 20;
                    return new SolidColorBrush(Colors.Yellow);
                }

                string content = row.Field<string>(columnName); // Header must be same as column name

                if (content == "w")
                {
                    return new SolidColorBrush(Colors.Blue);
                }

                if (content == "h")
                {
                    return new SolidColorBrush(Colors.Red);
                }

                if (content == "m")
                {
                    return new SolidColorBrush(Colors.LightGray);
                }

                if (content == "c" || content == "b" || content == "s" || content == "d" || content == "p")
                {
                    return new SolidColorBrush(Colors.Gray);
                }

            }
            catch (Exception e)
            {
                Debug.WriteLine(e);
                return new SolidColorBrush(Colors.Black); // Error! An Exception was thrown
            }
        }
        return new SolidColorBrush(Colors.Green); // Something else.
    }

    object[] IMultiValueConverter.ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

I tried invoking the NotifyPropertyChanged event, in hopes that that would trigger the converter, but had no luck with that.


Solution

  • I would assume the issue is that you are not invoking the setter using the Dispatcher. I don't see the code that you fire under a different thread, but I would add code like this:

    //code fired on non UI thread.
    Application.Current.Dispatcher.BeginInvoke(new Action(() =>
            {
                //call code will trigger PropertyChanged event
            }));