3

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;         
    }
}
4

3 回答 3

5

RelativeSource={RelativeSource Self}从绑定中删除,。此代码在 Button 中而不是在其 DataContext 中进行绑定搜索 IsDirty。

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

或使用

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

IsDirty 也应该是属性而不是变量

 private bool _isDirty;
 public bool IsDirty
        get
        {

            return _isDirty;
        }
        set
        {
            _isDirty = value

            _codeCollection = value;
            RaisePropertyChanged("IsDirty");
        }
于 2013-10-18T15:44:51.297 回答
3

我认为您没有正确绑定它。尝试这个:

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

您应该在调试项目时检查输出窗口,看看是否有任何绑定错误。

于 2013-10-18T15:42:33.277 回答
0

好像IsDirty没有更改通知。您是否INotifyPropertyChanged在 ViewModel 上实现?如果它是在ViewModelBase: 我看不到任何这样的代码。PropertyChanged(new PropertyChangedEventArgs("IsDirty"));当你改变时被调用IsDirty。因此,很可能没有调用转换器,因为它不知道IsDirty已更改。

于 2013-10-18T17:34:01.587 回答