2

I have a class that is bound to a ListBox:

class FolderFM : INotifyPropertyChanged
{
    public FolderFM(string path)
    {
        this.Folder = new DirectoryInfo(path);
        this.Name = Folder.Name;
    }

    private string name;
    private DirectoryInfo folder;
    private ObservableCollection<FileInfo> matchingFiles;

    ...

    public ObservableCollection<FileInfo> MatchingFiles 
    {
        get { return matchingFiles; }
        set
        {
            matchingFiles = value;
            FireWhenPropertyChanged("MatchingFiles");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void FireWhenPropertyChanged(string property)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(property, new PropertyChangedEventArgs(property));
        }
    }
}

XAML Code:

<ListBox Name="lstFolders" ItemsSource="{Binding}" Style="{StaticResource FolderBoxStyle}">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition />
                                <ColumnDefinition Width="25" />
                            </Grid.ColumnDefinitions>
                            <Label Content="{Binding Path=Name}" FontWeight="Bold" FontSize="13" />
                            <Button Content="{Binding Path=MatchingFiles, Converter={StaticResource lcc}}" Grid.Column="1" FontWeight="Bold" Foreground="Red" />
                        </Grid>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>

Code-Behind where the update is taking place:

private void btnAnalyze_Click(object sender, RoutedEventArgs e)
    {
        List<FileInfo> remainingFiles = files;
        foreach (FolderFM currentFolder in folders)
        {
            currentFolder.MatchingFiles = new ObservableCollection<FileInfo>();
            string folderName = currentFolder.Folder.Name;
            string[] splitName = folderName.Split(' ');
            for (int i = 0; i < remainingFiles.Count; i++)
            {
                if (remainingFiles[i] == null)
                    continue;
                FileInfo fileName = remainingFiles[i];
                string searchedName = fileName.Name;
                matchScore = 0;
                int searchCount = 0;
                foreach (string part in splitName)
                {
                    if (part.Length < 3 || part == "the")
                        continue;
                    matchScore += searchedName.Contains(part) ? 1 : 0;
                    searchCount += 1;
                }
                if (matchScore == searchCount)
                {
                    string destination = System.IO.Path.Combine(currentFolder.Folder.FullName, fileName.Name);
                    if (File.Exists(destination))
                        continue;
                    Directory.Move(fileName.FullName, destination);
                    currentFolder.MatchingFiles.Add(remainingFiles[i]);
                    //lstFolders.Items.Refresh();
                    remainingFiles[i] = null;
                }
            }
        }
        populateFiles();
    }

The attached Converter accepts the ObservableCollection and returns it's Count as string.

The application is working properly and the values are being updated but the changes are not being reflected on the UI.

However when I call: lstFolders.Items.Refresh(); the UI gets updated.

What am I missing/doing wrong ??

I looked at a few questions like: WPF Binding with INotifyPropertyChanged does not update but haven't been able to solve this problem.

Edit:

The DataContext is being assigned by this method:

private void populateFolders()
    {
        folders = getFolders(selectedFolder.FullName);
        lstFolders.ItemsSource = folders;
    }

private List<FolderFM> getFolders(string path)
    {
        List<FolderFM> d = new List<FolderFM>();
        foreach (string folder in Directory.GetDirectories(path))
        {
            d.Add(new FolderFM(folder));
        }
        return d;
    }
Community
  • 1
  • 1
Shrey
  • 33
  • 5
  • i think or maybe, FileInfo has no INotifyPropertyChanged implementation, so no updates are triggered – punker76 Dec 31 '12 at 10:42
  • @punker76 why should it matter though ?? i'm not changing the FileInfo instance, i'm only changing the ObservableCollection. – Shrey Dec 31 '12 at 15:16

2 Answers2

0

Instead of creating a new ObservableCollection, just replace that with a .Clear(). It should do the trick.

Federico Berasategui
  • 43,562
  • 11
  • 100
  • 154
  • but then where should i initialize the Collection then ?? the collections are null before that line of code. – Shrey Dec 31 '12 at 17:06
  • As per common sense, collections should never be null. http://stackoverflow.com/questions/1969993/is-it-better-to-return-null-or-empty-collection. http://stackoverflow.com/questions/3875672/should-an-object-return-null-and-a-collection-of-objects-return-an-empty-collect – Federico Berasategui Dec 31 '12 at 17:08
  • I found your link to be very informative and changed my class to not have null Collections and changed that line of code to use .clear(). But the UI is still not updating without the refresh() command. – Shrey Dec 31 '12 at 17:38
  • where is the view's DataContext being assigned? – Federico Berasategui Dec 31 '12 at 17:44
  • Edited the OP to show the assignment method which is called when we select a folder from the FolderBrowserDialog. – Shrey Dec 31 '12 at 17:52
  • I don't understand. You're doing `lstFiles.ItemsSource = files; ` in your code, which breaks the binding initially established in XAML. Also, I don't see what the getFiles() method is doing. Please clarify. – Federico Berasategui Dec 31 '12 at 17:55
  • the ItemsSource={Binding} in the XAML was just me trying things out to make this work, the code works just the same without it. Also added the getFiles() method in the OP. – Shrey Dec 31 '12 at 18:00
  • Ok. Now I understand LESS. What does all the initial code in the button click have to do with the lstFolders??? – Federico Berasategui Dec 31 '12 at 19:43
  • ok let me try to explain. First I call the folder dialog and select a folder, from which i extract a list of sub-folders and display them in lstFolders which is the ListBox in question. This ListBox's DataTemplate also contains a Button which contains the count of Files that match a certain criteria. This is the count that keeps changing but is not being reflected in the UI without the refresh() command. – Shrey Dec 31 '12 at 20:50
  • Ok. Now I see it. You re binding against the collection itself, and using a converter. BUT, since the collection instance is always the same, the binding engine does not refresh the binding. Try binding directly to MatchingFiles.Count, or inherit the observablecollection and find a way to call NotifyPropertyChanged("Count") – Federico Berasategui Jan 03 '13 at 01:11
  • Thanks, I bound it directly to the count property and its working properly now. Can u make a new answer so i can mark it as correct ?? – Shrey Jan 03 '13 at 08:02
0

Converting my comment into an answer:

Try binding directly to MatchingFiles.Count.

Federico Berasategui
  • 43,562
  • 11
  • 100
  • 154