WPF: IValueConverter is not called

advertisements

I am trying to change the 'Background' of a button based on the 'changed' condition of an ObservableCollection. I have an 'IsDirty' boolean property on my ViewModel and I am sure it is getting updated when the ObservableCollection is changed.

However, the background of the button is not being changed and it doesn't appear that the 'Convert' method is ever being called.

What am I missing with my converter? The button's background should change to red when the ObservableCollection is changed (IsDirty is true)

EDIT

I updated the converter to return a value of red or green (instead of red and transparent) and the button has no background color so that would tell me the converter is never getting called.

EDIT 2

Added the ViewModel code showing the IsDirty property.

Converter

public class IsDirtyConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return System.Convert.ToBoolean(value) ?
            new SolidColorBrush(Colors.Red)
            : new SolidColorBrush(Colors.Green);
    }

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

}

View

<Window x:Class="SerializeObservableCollection.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:conv="clr-namespace:SerializeObservableCollection.Converter"
        xmlns:ignore="http://www.ignore.com"
        mc:Ignorable="d ignore"
        Height="300"
        Width="491"
        Title="MVVM Light Application"
        DataContext="{Binding Main, Source={StaticResource Locator}}">

    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Skins/MainSkin.xaml" />
            </ResourceDictionary.MergedDictionaries>

            <conv:IsDirtyConverter x:Key="IsDirtyConverter" />

        </ResourceDictionary>
    </Window.Resources>

    <Grid x:Name="LayoutRoot">

        <TextBlock FontSize="36"
                   FontWeight="Bold"
                   Foreground="Purple"
                   Text="{Binding WelcomeTitle}"
                   VerticalAlignment="Top"
                   TextWrapping="Wrap" Margin="10,10,10,0" Height="54" HorizontalAlignment="Center" />

        <DataGrid Margin="10,69,10,38"
                  ItemsSource="{Binding CodeCollection, Mode=TwoWay}"/>
        <Button Name="SaveButton" Content="Save"
                Command="{Binding SaveButtonClickedCommand}"
                Background="{Binding
                                RelativeSource={RelativeSource Self},
                                Path=IsDirty,
                                UpdateSourceTrigger=PropertyChanged,
                                Converter={StaticResource IsDirtyConverter}}"
                HorizontalAlignment="Right" Margin="0,0,90,10"
                Width="75" Height="20"
                VerticalAlignment="Bottom"/>
        <Button Content="Refresh" HorizontalAlignment="Right" Margin="0,0,10,10" Width="75"
                Command="{Binding RefreshButton_Click}" Height="20" VerticalAlignment="Bottom"/>

    </Grid>
</Window>

View Model

public class MainViewModel : ViewModelBase
{
    public bool IsDirty;

    /// <summary>
    /// ObservableCollection of Codes
    /// </summary>
    private const string CodeCollectionPropertyName = "CodeCollection";
    private ObservableCollection<Code> _codeCollection;
    public ObservableCollection<Code> CodeCollection
    {
        get
        {
            if (_codeCollection == null)
            {
                _codeCollection = new ObservableCollection<Code>();
            }
            return _codeCollection;
        }
        set
        {
            if (_codeCollection == value)
            {
                return;
            }

            _codeCollection = value;
            RaisePropertyChanged(CodeCollectionPropertyName);
        }
    }

    /// <summary>
    /// Initializes a new instance of the MainViewModel class.
    /// </summary>
    public MainViewModel(IDataService dataService)
    {
         // Load XML file into ObservableCollection
        LoadXML();
    }

    private void LoadXML()
    {
        try
        {
            XmlSerializer _serializer = new XmlSerializer(typeof(Codes));

            // A file stream is used to read the XML file into the ObservableCollection
            using (StreamReader _reader = new StreamReader(@"LocalCodes.xml"))
            {
                CodeCollection = (_serializer.Deserialize(_reader) as Codes).CodeCollection;

            }

            // Change notification setup
            CodeCollection.CollectionChanged += OnCodeCollectionChanged;

        }
        catch (Exception ex)
        {
            // Catch exceptions here
        }

    }

    private void SaveToXML()
    {
        try
        {
            XmlSerializer _serializer = new XmlSerializer(typeof(ObservableCollection<Code>));
            using (StreamWriter _writer = new StreamWriter(@"LocalCodes.xml"))
            {
                _serializer.Serialize(_writer, CodeCollection);
            }
        }
        catch (Exception ex)
        {

        }
    }

    private RelayCommand _saveButtonClickedCommand;
    public RelayCommand SaveButtonClickedCommand
    {
        get
        {
            return _saveButtonClickedCommand ??
                (_saveButtonClickedCommand = new RelayCommand(
                    () =>
                    {
                        SaveButtonClicked();
                    }));

        }
    }
    private void SaveButtonClicked()
    {
        SaveToXML();
    }

    private void OnCodeCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        IsDirty = true;
    }
}


Remove RelativeSource={RelativeSource Self}, from your binding. This code is making the binding search IsDirty within the Button not in its DataContext.

            Background="{Binding
                        Path=IsDirty,
                        UpdateSourceTrigger=PropertyChanged,
                        Converter={StaticResource IsDirtyConverter}}"

OR use

               Background="{Binding
                        RelativeSource={RelativeSource Self},
                        Path=DataContext.IsDirty,
                        UpdateSourceTrigger=PropertyChanged,
                        Converter={StaticResource IsDirtyConverter}}"

Also IsDirty should be property not variable

 private bool _isDirty;
 public bool IsDirty
        get
        {

            return _isDirty;
        }
        set
        {
            _isDirty = value

            _codeCollection = value;
            RaisePropertyChanged("IsDirty");
        }