views:

32

answers:

1

I have a WPF (.Net 4) ListView used to navigate a local Windows directory. It displays the contents of the current directory, with name and size and all that. However, in some directories, the first element it displays shows up twice. For example, let's say in directory "D1" I have subdirectories "W", "X", "Y", and "Z". The ListView will say "W W X Y Z", even though the actual data it's bound to (a ThreadObservableCollection) doesn't have the duplicate. The ThreadObservableCollection is also initially empty when the object that contains it is created, subdirectories and files are found on a background thread and then put in the collection as they are located.

I'm at a loss for how to even debug this, since it's occurring purely in the presentation area, and am worried it may be a bug in the framework itself. It does not occur in every directory, but it seems (somewhat) repeatable in the ones it does occur in which suggests there's some pattern at work here, though I've yet to find any distinguishing characteristics. It's also always the first entry if it does happen.

I have also tried listening to the CollectionChanged event of the ThreadObservableCollection, but it only fires once per item changed as one would expect, and I've watched the values provided to ensure that there are no duplicates (which there aren't).

I also attached a DebugConverter (see below) to the TextBlock containing the name of the (sub)directories shown, and it does show duplicate values. So there are definitely two actual rows in the ListView with the same item behind them, but I still have no idea why.

I'd appreciate any suggestions on what may be going wrong or even how to try to find out why it thinks it has to duplicate the first entry.

+1  A: 

I would probably start by running it through a DebugConverter (you'll have to write it, I don't think there's an implementation published with .Net). It looks like this:

(Obviously, stick your breakpoint in VS at the single line of code in the method).

 public class DebugConverter : IValueConverter { 
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
      return value;    
    }
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value;
    }
}

Now you can stick a breakpoint in, and verify that the duplicate is actually turning up at interface generation level. Examine the absolute path of the file (is it, for instance, the default "." which represents the current directory, or something like that? Is it a misconversion somewhere else? I don't know why that would only happen on some directories, but start by casting your debugging net wide).

It probably isn't a threading issue because to my mind the Dispatcher controls all interaction with the UI, including the observablecollection which backs your view, which means it can only interact serially. However, if you're not using an ObservableCollection you might have threading? I suspect WPF is fairly strict about any backing enumeration, but I'm not sure. Oh, wait, you said you're using an ObservableCollection. Okay, can't be threading. Are you doing anything fancy with DataTemplateSelector? Is there a style which applies the view template? Could you have both the default Setter applying a style and a Trigger including another view item?

Let's try as hard as we can not to assume that it's a bug in the framework. In my experience, the problem is ALWAYS my code, even if I don't feel like it could be up front.

(post comment)

Even if your collection was empty at binding time you should be able to access the individual elements as they go in like this:

<ListView>
 <ListView.ItemTemplate>
  <DataTemplate>
   <TextBlock Text='{Binding Path=filename, Converter={StaticResource DebugConverter}' />
  ...etc
  </DataTemplate>
 </ListView.ItemTemplate>
</ListView>

Any chance you can post your code?

Chris Hagan
First off, thanks! In rough order you mentioned it: The ValueConverter there is a great idea that I wish I thought of, but the actual collection at binding time is empty - things are loaded in the background and then the collection tells the ListView to update. No DataTemplateSelector, no Triggers that affect.. anything in the ListView, unless I've completely forgotten my own code. There are background threads, yes, but those can't touch the UI anyway in WPF; there's just the one finding directories/files to put in the list.
JustABill
Replying to the post-comment edit: The code here is rather complex; to post the entire related section would take pages and pages. Is there any particular part you're interested in? The definition of the ListView or something? I will try the TextBlock debug converter though.
JustABill
Apparently I can't edit that comment, so I just tried that. It did show duplicates, which at least confirms there's two unique TextBlocks that for some reason are attached to the same item. So somewhere between the collection and the ListView it's getting duplicated.
JustABill
Well I "fixed" it. By changing directory via the path and creating a new Directory instead of passing in the already-existent Directory object it works. I still have absolutely no idea why the hell this works this way, but for now it works and that's all I really care about for the immediate future. Marking this as the answer since it was the inspiration I needed to find that difference.
JustABill
Glad it's working for you now.
Chris Hagan