0

I am having a hard time binding a ListView with an ObservableCollection in another class.

My xaml:

<ListView Height="117" HorizontalAlignment="Left" Margin="20,239,0,0" Name="lvResults" VerticalAlignment="Top" Width="759" ItemsSource="{Binding RuleSearch.FileMatches}">
        <ListView.View>
            <GridView>
                <GridViewColumn Header="Name" Width="120" DisplayMemberBinding="{Binding FileName}"/>
                <GridViewColumn Header="Size" Width="120" DisplayMemberBinding="{Binding DirectoryName}"/>
                <GridViewColumn Header="Date" Width="120" DisplayMemberBinding="{Binding Size}"/>
                <GridViewColumn Header="Full Path" Width="120" />
                <GridViewColumn Header="Some Meaningless Data" Width="120" />
            </GridView>
        </ListView.View>
    </ListView>

The Xaml behind code:

private Search _ruleSearch = new Search();
public Search RuleSearch { get { return _ruleSearch; }}

In Search class:

public ObservableCollection<Result> FileMatches { get; private set; }

Note the changes are made on a new thread, if that makes a difference:

private void FindResultOnNewThreads()
  {
     FileMatches.Clear();

     Parallel.ForEach(_fileList, file =>
     {
        foreach (Regex search in SearchTermList.Where(search => search.IsMatch(file)))
        {
           lock (FileMatches)
           {
              FileInfo fileInfo = new FileInfo(file);
              FileMatches.Add(new Result
                                 {
                                    Attributes = fileInfo.Attributes,
                                    DirectoryName = fileInfo.DirectoryName,
                                    Extension = fileInfo.Extension,
                                    FileName = fileInfo.Name,
                                    FullNamePath = fileInfo.FullName,
                                    Size = fileInfo.Length
                                 });
           }
        }
     });
  }

Result class:

    public class Result
   {
      public string FileName { get; set; }
      public string DirectoryName { get; set; }
      public string FullNamePath { get; set; }
      public long Size { get; set; }
      public string Extension { get; set; }
      public FileAttributes Attributes { get; set; }

   }

Issue really is, I am learning wpf by myself and couldn't really find a rule set for data binding in WPF. I know that it requires properties and public ones, other than that I am stuck.

Reza M.
  • 1,205
  • 14
  • 33
  • You say you're having a hard time, be specific about what's wrong. Where are you setting the DataContext, if at all? – Big Daddy Oct 12 '12 at 14:20
  • @BigDaddy, I thought I specified the problem was I couldn't bind. I bind the DataContext in xaml: `ItemsSource="{Binding RuleSearch.FileMatches}"` I even tried a couple different variations. one in the code behind... – Reza M. Oct 12 '12 at 14:29

2 Answers2

1

Probably your listViews DataContext is not set to the UserControls or Windows or whatever, where you have your RuleSearch prop.

You can set it in the xaml.cs codebehind.

lvResult.DataContext = this;

or in xaml

<ListView Height="117" HorizontalAlignment="Left" Margin="20,239,0,0" Name="lvResults" VerticalAlignment="Top" Width="759" ItemsSource="{Binding Path=RuleSearch.FileMatches, RelativeSource={RelativeSource AncestorType={x:Type typeOfAncestor}}}">
    <ListView.View>
        <GridView>
            <GridViewColumn Header="Name" Width="120" DisplayMemberBinding="{Binding FileName}"/>
            <GridViewColumn Header="Size" Width="120" DisplayMemberBinding="{Binding DirectoryName}"/>
            <GridViewColumn Header="Date" Width="120" DisplayMemberBinding="{Binding Size}"/>
            <GridViewColumn Header="Full Path" Width="120" />
            <GridViewColumn Header="Some Meaningless Data" Width="120" />
        </GridView>
    </ListView.View>
</ListView>

where typeOfAncestor is the type of your usercontrol/window...

Miklós Balogh
  • 2,164
  • 2
  • 19
  • 26
  • The codebehind I tried before and does not work. I just tried your xaml part and it seems I am getting something. Well I think it is good because I am getting an error on my ObservableCollection about how I am not allowed to change it's value on a different thread anymore. – Reza M. Oct 12 '12 at 14:34
  • Balogh, In genius ! it works if i take it off the different thread... I have 2 questions though: 1- Can you link me to where I can understand more about that piece of xaml code ? 2- Anyway I can put this on another thread ? as I require not to have lag. – Reza M. Oct 12 '12 at 14:39
  • 1
    see [this](http://msdn.microsoft.com/en-us/library/ms743599.aspx) and [this](http://www.c-sharpcorner.com/UploadFile/yougerthen/relativesources-in-wpf/) – Miklós Balogh Oct 12 '12 at 14:44
  • You can do it on the other thread by using Dispatcher.Invoke. See [this](http://stackoverflow.com/questions/9980053/dispatcher-dispatch-on-the-ui-thread) answer. – V Maharajh Oct 12 '12 at 15:29
0

Your Search class needs to implement INotifyPropertyChanged, which is used to let the UI know when the properties in your code-behind changes (in this case, FileMatches). This will involve registering a callback to the FileMatches.CollectionChanged event that then raises the INotifyPropertyChanged.PropertyChanged event with a property name of "FileMatches".

Note that if you ever want the values in the collection to stay in sync with the UI, you should also implement INotifyPropertyChanged on your Result class. (From looking at your code, the contents of your Result class looks constant, so you won't need to do this).

V Maharajh
  • 9,013
  • 5
  • 30
  • 31
  • Unfortunately, I was trying this before and wouldn't work either. but thanks. – Reza M. Oct 12 '12 at 15:17
  • The only way to do it without INotifyPropertyChanged is if the data is ready before the UI needs to show itself. If it happens to be working without INotifyPropertyCHanged, you could just be getting lucky and your off thread task happens to be completing before the UI is shown. – V Maharajh Oct 12 '12 at 15:31