WPF: OnCollectionChanged not firing

Deadly 提交于 2019-12-31 04:50:13

问题


Using VS 2102, .NET 4.0 and MVVM Light.

I have the following code that reads items from an XML file into an ObservableCollection. I then want to update the Save button with a Converter if the collection changes (using an IsDirty flag) but the OnCodeCollectionChanged method is not being executed.

The collection is properly displayed in the data grid and I can add new entries to the data grid but the OnCodeCollectionChanged method is never called. I am NOT trying to catch the change of an existing item (I know ObservableCollection doesn't notify that change), I just want to raise the on change event if a new item is added or removed to/from the collection.

What am I doing wrong and is there a better way of doing what I want?

Codes.cs (Model)

[Serializable()]
public class Codes
{
    public Codes() { }

    [XmlElement("Code")]
    public ObservableCollection<Code> CodeCollection { get; set; }

}

[Serializable()]
public class Code
{
    [XmlElement("AccpacCode")]
    public string AccpacCode { get; set; }

    [XmlElement("LAC")]
    public string LAC { get; set; }

    [XmlElement("SCSCode")]
    public string SCSCode { get; set; }

    [XmlElement("ParentEmployerAccpacCode")]
    public string ParentEmployerAccpacCode { get; set; }
}

MainViewMdoel.cs (ViewModel)

public class MainViewModel : ViewModelBase
{
    public bool IsDirty = false;

    /// <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)
    {
        // Change notification setup
        CodeCollection.CollectionChanged += OnCodeCollectionChanged;

        // 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;

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

    }

    private void SaveToXML()
    {
        try
        {

        }
        catch (Exception ex)
        {

        }
    }

    private RelayCommand<ViewModelBase> _saveButtonClickedCommand;
    public RelayCommand<ViewModelBase> SaveButtonClickedCommand;
    private void SaveButtonClicked(ViewModelBase viewModel)
    {
        SaveToXML();
    }

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

MainWindow.xaml (View)

<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}"/>
    <Button Name="SaveButton" Content="Save" HorizontalAlignment="Right" Margin="0,0,90,10" Width="75"
            Command="{Binding SaveButton_Click}"
            Background="{Binding IsDirty, Converter={StaticResource IsDirtyConverter}}" 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>


回答1:


Move your CodeCollection.CollectionChanged += OnCodeCollectionChanged; code from constructor to the LoadXml code after you fill the collection

    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.CollectionChanged -= OnCodeCollectionChanged;
                CodeCollection = (_serializer.Deserialize(_reader) as Codes).CodeCollection;
                CodeCollection.CollectionChanged += OnCodeCollectionChanged;

            }                
        }

you are changing the instance of the CodeCollection and need to register to the event again



来源:https://stackoverflow.com/questions/19451411/wpf-oncollectionchanged-not-firing

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!