tags:

views:

41

answers:

3

Hello All,

I have a treeview that represents different filter items to a set of records. At runtime, I am setting each node's tag to a Func type. For example:

myTreeView.Nodes.Add(New TreeNode("Node1"));
myTreeView.Nodes["Node1"].Tag = New Func<MyRecordType, bool>(p=> p.Title == "test 1");

myTreeView.Nodes.Add(New TreeNode("Node2"));
myTreeView.Nodes["Node2"].Tag = New Func<MyRecordType, bool>(p=> p.Title == "test 2");

etc..

Then when the user clicks on the node, I simply pass the Tag and use it as a predicate for getting my data:

gridView.DataSource = populateData(nodeClicked.Tag as Func<MyRecordType, bool>);

private MyRecordType[] populateData(Func<MyRecordType, bool> predicate)
{
  MyRecordType[] records;

  if(predicate == null)
     records = MyRecords.ToArray();
  else
    records = MyRecords.Where(predicate).ToArray();

  return records;
}

This was all working great, but I added some code that creates nodes based on a set of records. It looks like this:

var users = DB.MyRecords.OrderBy(o=> o.CreatedBy).Select(s=> s.CreatedBy).Distinct();

foreach(var user in users) {
  var node = new TreeNode("Node" + user, user);
  node.Tag = new Func<MyRecordType, bool>(p=> p.CreatedBy == user);
  MyTreeView.Nodes.Add(node);
}

The problem is that the nodes that are created dynamically all contain the same predicate object (which seems to be the same predicate created during the last forearch iteration).

I'm not really sure what's going on here. Any idea? Thanks a million!

A: 
(Func<MyRecordType, bool>)(p=> p.CreatedBy == user);

should work.

Gnostus
+2  A: 

You are capturing a non-local variable, namely user.

Create a temporary inside the loop and refer to that instead.

Example:

foreach(var user in users) {
  var u = user;
  var node = new TreeNode("Node" + user, user);
  node.Tag = new Func<MyRecordType, bool>(p=> p.CreatedBy == u);
  MyTreeView.Nodes.Add(node);
}
leppie
Thanks a million!
kevlingo
@kevlingo: This is a common mistake, one that I am sure you wont make again :)
leppie
A: 

When you create the Func<> object, it does not store the current value of the user variable, and rather operates on the variable shared by the loop iteration. It will work, howerver, if you create a new copy of the variable inside the loop.

E.g., instead of:

        foreach (string s in new string[] { "1", "2", "3" })
            funcs.Add(() => s);

use

        foreach (string s in new string[] { "1", "2", "3" })
        {
            string s1 = s;
            funcs.Add(() => s1);
        }
matiash