views:

249

answers:

4

Here's my extension method for invoke on a control:

 public static void Invoke<T>(this T c, Action<System.Windows.Forms.Control> DoWhat)
  where T:System.Windows.Forms.Control
 {
  if (c.InvokeRequired)
   c.Invoke(o=> DoWhat(c) );
  else
   DoWhat(c);
 }

ds is a strongly typed dataset. This works:

Action<DataGridView> a = row => row.DataSource = ds.bLog;

  this.dataGridView1.Invoke(a);

this doesn't compile:

this.dataGridView1.Invoke<DataGridView>(o => o.DataSource = ds.bLog);

and says System.Windows.Forms.Control does not contain a definition for 'DataSource'...

do I really have to break this into 2 lines? For clarity/safety should I call the generic extension method InvokeSafe?

Edit:Extension method revised (works, but I'd like to remove the named delegate requirement):

private delegate void myDel();

public static void InvokeSafe<T>(this T c, Action<T> DoWhat)
where T : System.Windows.Forms.Control
 {

  myDel d = delegate() { DoWhat(c); };
  if (c.InvokeRequired)
   c.Invoke(d);
  else
   DoWhat(c);



 }

I can't seem to figure out how to make factor out myDel into an anonymous delegate in the block?

+3  A: 

The problem is that your action is only declared (in the method) to act on Control. Change it to this:

public static void Invoke<T>(this T c, Action<T> DoWhat)
    where T:System.Windows.Forms.Control
{
    if (c.InvokeRequired)
        c.Invoke((EventHandler) delegate { DoWhat(c) } );
    else
        DoWhat(c);
}

That way the compiler will infer that you want an Action<DataGridView> so the lambda expression in the caller will be able to use DataSource.

Jon Skeet
c.Invoke(o=> DoWhat(c) ); appears to me to be a stackoverflow, when I change the function name to InvokeSafe, that line no longer functions.I'm trying to call the control's Invoke, not recurse.
Maslow
Why would that be a stack overflow? Bear in mind that the *only* part of your code I've changed is the type of the DoWhat variable.
Jon Skeet
because my code was bad to begin with. It was calling itself as written, instead of the control's invoke method.
Maslow
Where was it doing that? Or do you mean in code you hadn't posted?
Jon Skeet
That line in the original and your answer. c.Invoke(o=> DoWhat(c) );Is there a way to subscribe to comments to your question, or to comment responses to your own comments?
Maslow
Ah, I see what you mean, yes. Sneaky. And no, I don't think there's any way of subscribing to comments. (It's a fairly frequently requested feature though.)
Jon Skeet
(Fixed the recursion using an anonymous method. This is the danger of extending a type with another method of the same name, btw.)
Jon Skeet
Interesting solution, I had tried using just delegate alone in that spot and it complained... a cast to event handler makes it work? how bizarre.
Maslow
@Maslow: Not very bizarre when you know what the compiler's thinking :) The compiler has to know exactly which delegate type (or expression tree type) to convert anonymous methods or anonymous functions to. Just casting to "delegate" doesn't work - it needs to know the real type.
Jon Skeet
+2  A: 

Try changing your method signature to:

public static void Invoke<T>(this T c, Action<T> DoWhat)

This will let your Action use the desired type that you specify.

Jason
Thanks, this was the key that I was missing, combined with changing the Invoke to InvokeSafe to find the accidental stack overflow, thanks. If I am reading it right you got your answer in before Jon, and could use the rep more so i'll accept this one.
Maslow
Just as a point of order, my answer was in 2 minutes before Jason's, but I really don't mind :)
Jon Skeet
@Jon - I hoped you wouldn't mind, I guess I read them backwards, thanks Jon
Maslow
A: 

To further what Jon Said, The datasource does not live on System.Windows.Forms.Control. The datasource is on the datagrid. So if you look at the error message, you will see that it is trying to set the datasource on a type that does not have a data source. Doing what Jon suggested should fix the problem.

Tony
A: 

Works!

public static void InvokeSafe<T>(this T c, Action<T> DoWhat)
where T : System.Windows.Forms.Control
 {

  Action d = delegate() { DoWhat(c); };
  if (c.InvokeRequired)
   c.Invoke(d);
  else
   DoWhat(c);

 }

This code does result in an InvalidOperationException- Cross-thread operation not valid:

List<customer> c=new List<customer>{new customer{ Name="test"},new customer{Name= "John doe"}};
  Thread t = new Thread(o => this.dataGridView1.DataSource = c);
  t.Start();

the new extension method does not!

List<customer> c=new List<customer>{new customer{ Name="test"},new customer{Name=   "John doe"}};
  Thread t = new Thread(o => this.dataGridView1.InvokeSafe(p => p.DataSource = c));
  t.Start();
Maslow
I imagine there's a way to factor out the explicit delegate initialization too, but I'm happy with it.
Maslow